Multi-step VLookup, Substitute, and then Evaluate Process - excel

I have a three-step process that should end up giving me Boolean values of True/False and also an occasional #N/A or #VALUE (which I actually want to keep as errors). I am using a workbook with multiple named worksheets and am pulling cell values from one tab through a VLookup, replacing a string in those values, and then making those values into a formula to be evaluated. Here's what I have so far; I've included comments in the code explaining where I'm stuck.
Public Sub DetermineRowsToExamine()
'Define what our Rows are for the calculations
Dim NumRecords As Long
NumRecords = Workbooks("POVA Daily Reporter.xlsm").Worksheets("Paste Daily Data").Range("B" & Rows.Count).End(xlUp).Row
Dim CellsForFormula As Range
Set CellsForFormula = Workbooks("POVA Daily Reporter.xlsm").Worksheets("Paste Daily Data").Range("g2", "G" & NumRecords)
'Now I Insert the VLookup
Dim WSLogic As Worksheet
Dim WSData As Worksheet
Set WSData = Workbooks("POVA Daily Reporter.xlsm").Worksheets("Paste Daily Data")
Set WSLogic = Workbooks("POVA Daily Reporter.xlsm").Worksheets("Logic Statements")
CellsForFormula.Value = Application.WorksheetFunction.VLookup(WSData.Range("B2"), WSLogic.Range("A:D"), 4, False)
'This works in principle, but the problem is the "B2" in the VLookup - I need the "B2" to change to "B3" related
'to each row, just as it would if I pasted the rows down the columns as an cell formula
'Now I want to take that value and perform a replacement:
CellsForFormula.Value = Application.WorksheetFunction.Substitute(Range("g2"), "ZZZ", "C2")
'Again, this works great, but I need it to replace "G2" or "G3" or whatever cell it's in.
'Finally, I then want to evaluate that cell as if it were a formula. When the above calculations are working,
'I end up with: AND(LEN(C2)=10,OR(LEFT(C2,2)="57",LEFT(C2,2)="13"))
'I want to evaluate this as a formula, basically making it =AND(LEN(C2)=10,OR(LEFT(C2,2)="57",LEFT(C2,2)="13"))
End Sub
I think what I'm just not understanding is how to get the Cell references in the VLookup and Substitute functions to relate to whatever row I'm in.

Agreeing with what #AlanWaage is saying, you should put the actual VLOOKUP formula in the cell. Then, to get the formula to update relative to its location, you can utilize copy and paste. Finally, once you have the formulas there, you can copy and paste values, and do your replacement based on the values now in CellsForFormula range. See the updated code below:
' Put the formula in the first cell of your range
CellsForFormula(1, 1).Formula = _
"=VLOOKUP(Paste Daily Data!B2,Logic Statements!$A$1:$D$10000,4,0)"
' Copy the formula to the rest of your range
CellsForFormula(1, 1).Copy _
Destination:=Range(CellsForFormula(2, 1), CellsForFormula(NumRecords - 1, 1))
' Copy and paste values to just get the values in your range
CellsForFormula.Copy
CellsForFormula.PasteSpecial Paste:=xlPasteValues
' Execute your replacement
for each cell in CellsForFormula
cell.Replace("ZZZ", cell.offset(0,-4).Address)
'Use the line below instead of the line above if you only
'want to replace if the entire value is "ZZZ"
'cell.Replace("ZZZ", cell.offset(0,-4).Address,xlWhole)
cell.Formula = "=" & cell.value
Next cell
---EDIT---
Note that I did Logic Statements!$A$1:$D$10000 instead of Logic Statements!A:D; this will be much faster than having Excel examine all rows in the columns A:D. Make this number larger or smaller as you see fit, but you should try to avoid using complete column/row references in formulas unless necessary

Related

How to use a user defined range in a formula in vba

I am trying to define a range starting at B2 (constant) to the last cell with data which will change month to month. I want to take the same range length and define another range for column A which will also start at A2 (constant) but will extend only down as far as column B goes. I'm trying to identify them as range and use the dimmed range in a formula in vba but it doesn't like it...any ideas?
Dim Data As range
Dim Time As range
range("b2").Select
'Select Range
Set Data = range("B2", range("B2").End(xlDown))
Set Time("A2", range("A2").End(xlDown))
ActiveCell.Offset(1, 1).Select
ActiveCell.FormulaR1C1 = _
"=FORECAST.ETS([#Timeline],.address(data),.address(time):R[-1]C[-2],1,0)"
You need to close the formula string, add the address, and then continue:
"=FORECAST.ETS([#Timeline],.address(" & data.address & "),.address(" &
time.address & "):R[-1]C[-2],1,0)"
Note since you're using R1C1 style, you might have to do this on both .address parts,
time.address(ReferenceStyle:=xlR1C1)
so:
"=FORECAST.ETS([#Timeline],.address(" & data.address(ReferenceStyle:=xlR1C1) & "),.address(" &
time.address(ReferenceStyle:=xlR1C1) & "):R[-1]C[-2],1,0)"
Edit: Also, I would change the keyword Time, as I think that's a reserved word. Perhaps Dim timeRng as Range?
In addition to #BruceWayne's answer, to address the first part of your question:
If I have a range B2:B50, and I want the corresponding A column, then I can use the Offset function:
Set time = data.Offset(columnOffset:=-1)
Alternatively you can construct the column like this:
Set time = Sheet1.Range("A2").Resize(Rows(data), 1) 'nrows, 1 column
Then you could put A2 anywhere
FWIW:
range("b2").Select is unnecessary and will really slow down your code if you get into this habit (it's just because the macro recorder doesn't know what you want exactly). You could use Range("B2").Offset(1,1).FormulaR1C1 with no selecting
You can name cells in excel and refer to the names: Range("myNamedCell")
Always best practice to prepend the sheet name and fully qualify references (e.g. Sheet1.Range("A1")) since that will always refer to the same cell, whereas Range("A1") refers to A1 on whichever sheet happens to be selected when you run the macro

Excel VBA Sort when Inputting Data, Updated in All Other Sheet?

I am new to VBA Excel.
I wanna create a database for each month, with 1 'Main Sheet' for the list of names, and the list on 'Main Sheet' will sort automatically as a row when I entered data along with the update of the other sheet.
I found this code, and it's only updated/sorting in the sheet entered (let's say the 'Main Sheet'). Is that possible if the entered data and sorting updated automatically in all other sheets?
Private Sub Worksheet_Change(ByVal Target As Excel.Range)
If Target.Column = 1 Then
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Range("A2:BN2" & lastRow).Sort key1:=Range("A2:A" & lastRow), order1:=xlAscending, Header:=xlNo
End If
End Sub
I tried referencing/paste the link to the name for each month (start from A2), but I have no idea to keep the column beside A2 (B2, C2, etc) sticking with the A2 as a full row.
Thanks!
Look at this part of your code for ideas how to solve your problem.
Range("A2:BN2" & lastRow).Sort Key1:=Range("A2:A" & lastRow)
The instruction is to sort Range("A2:BN2" & lastRow) on Key1. The range to sort starts at A2 and ends with the last used row in column BN. All columns of all rows are included, as they should. But lastRow was determined in column 1, which is column A. We hope that all columns have the same length. Observe that we don't know on which tab the range is located. By default, if no sheet is specified, Excel will presume the ActiveSheet. This is borne out by the fact that the code is located in a worksheet event procedure. Of course, this code is linked to the sheet on whose code module it is placed. It won't run when another sheet is active.
However, the syntax for specifying a range for a particular sheet would look like this.
With Worksheets("MySheet")
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set MyRange = .Range("A2:BN2" & lastRow)
End With
Please observe all the leading periods, each of which links the statement it precedes to the worksheet specified in the With statement. Imagine a loop in which the sheet name is changed on each turn, thereby defining the same range on a different sheet on each instance.
The Key argument of the Sort method specified the column on which to sort. It's called "Key" instead of "Column" because there are sheet columns and range columns. In your case the sheet rows are different from your range rows because your range starts in row 2 but the range columns are identical with the sheet columns. Anyway, Key1:=Range("A2:A" & lastRow) isn't a very good pointer to the column you want to sort on. 1 single cell would suffice, like Key1:=Range("A2") - or Key1:=Cells(2, 1) as I would prefer.
As you see, this part is a lot simpler. The only important point to observe is that the cell specifying the Key must be within the range to be sorted. This also means that you can't specify a Key on the ActiveSheet for a sort range on another tab. When you construct your loop, therefore, you will need to take a cell from the properly defined sort range as Key.

Return cells content from range

Yesterday I learned here how to copy a row to a second sheet.
Sub maJolieProcedure(Texte As String)
With Worksheets("employes").Range("A:A")
Set c = .Find(what:=Texte)
If Not c Is Nothing Then
firstAddress = c.Row
Worksheets("employes").Rows(firstAddress).Copy _
Destination:=Worksheets("rapport").Range("A1")
MsgBox "Ok"
Else
MsgBox "Nok"
End If
End With
End Sub
To respect the formatting of the second sheet, I want to copy and paste the contents of each cell one by one.
I can identify the line number. However, I can't figure out how the Range object can return each cell one by one. For example, C3 content if Rows = 3.
Thanks a lot.
If you don't want to paste the formatting from one range to another paste values only.
Worksheets("employes").Rows(firstAddress).Copy
Worksheets("rapport").Range("A1").PasteSpecial xlValues
That's the same for all ranges, whether 1 cell or a million. The Copy process copies the subject to memory as one block. Any parsing must be done before the Copy instruction. An alternative is to read a range into an array.
Dim Arr As Variant
Arr = Worksheets("employes").Rows(firstAddress).Value
This will create a 3D array of 1 row and about 16000 columns. You might decide to limit your enthusiasm to only what you need.
With Worksheets("employees")
Arr = .Range(.Cells(firstAddress, 1), .Cells(firstAddress, .Columns.Count).End)xlToLeft)).Value
End With
Pay attention to the leading periods within the With statement. Each such period stands for the object mentioned in the With statement.
If your goal is to respect the formating of the second sheet, you don't need to loose time copying cell by cell.
It is more effective to do a paste special, like you do with the mouse:
Range("A1").Copy
Range("B1").PasteSpecial Paste:=xlPasteValues
works very well also with bigger ranges if you need:
Range("A1:A12").Copy
Range("B1:B12").PasteSpecial Paste:=xlPasteValues
or even
Range("A1:A12").Copy
Range("D3").PasteSpecial Paste:=xlPasteValues
If your goal is to really access all cell of a range individually , you just iterate on the range. For example:
For Each cell In Range("A1:A12")
cell.Value = cell.Value + 2
Next cell

Applying formula to range of cells, then pasting values

I need to apply a formula/function (the DOLLAR function) to a range of cells, then cut and paste just the values.
I have a heading row and use Find to get to the column that I need. Then with all of the cells below, I want to apply the DOLLAR formula. However, the result at the end of my macro needs to be that those cells now contain just the value after applying the formula, and not the formula itself (this is because I'm going to use the sheet to run a mail merge so it can't have formulas).
I've tried running Do While and other cut/paste methods. I just don't have the skill to get it done :(
Sub ProjectSummaryAdjustment()
Workbooks("Project Summary").Activate
Range("A1",Range("A1").End(xlToRight)).Find("TD Budget Effort").Select
This is as far as I've gotten with the code. Now for all the cells below, I want to apply the DOLLAR formula, then have just the values pasted there. I don't mind if it has to cut and paste to the first empty column and then cut and paste back to the original column.
First make sure that you should avoid Select and Activate. Then you can simple use evaluate to do the conversion. You do need to set the field as text first:
With Workbooks("Project Summary").Worksheets("Sheet1") 'Change to your sheet name
Dim rng As Range
Set rng = .Range("A1", .Range("A1").End(xlToRight)).Find("TD Budget Effort")
'Test to make sure the header was found
If Not rng Is Nothing Then
With .Range(.Cells(2, rng.Column), .Cells(.Rows.Count, rng.Column).End(xlUp))
.NumberFormat = "#"
.Value = .Parent.Evaluate("index(DOLLAR(" & .Address & "),)")
End With
End If
End With

VBA to paste from one column to another?

I need code for the below requirement, wherein the below code is not working:
Sub sample48()
Worksheets("Sheet").Select
Range("AG1").Select
Range("A1:AQ1").Autofilter Field:=33, Criteria1:="COD*"
Range("AG:AG").Value = Range("AM:AM").Value
End Sub
I need to filter a word called **COD** in column AG, and then I need to copy and paste values from Column AG to Column AM only for the those filtered line items.
Note that in excel you can copy from filtered area, but when you are pasting, data will not paste on filtered(visible) cells, instead pasted continuously. There is 2 way to do your task:
1: Use loop
Sub MyCopyPaste()
Dim RngCnt As Range
Dim LastRow As Long
LastRow = Range("AM" & Rows.Count).End(xlUp).Row
For Each RngCnt In Range("AM1:AM" & LastRow).SpecialCells(xlCellTypeVisible)
Range("AG" & RngCnt.Row).Value = Range("AM" & RngCnt.Row).Value
Next
End Sub
2: Without Loop
If in some case you don't want use loop or vba, you should create another column and put an ID number into it. This column will used to sort the worksheet to retain rows order to original. Then create another column with name custom_Order and after filtering, put numbers into it, then show all data and sort worksheet based on custom_order and then filter it. In this case all your expected rows will be filter and come continuously and you can easily copy and paste.
Sub sample48()
Range("A1:AQ1").AutoFilter Field:=33, Criteria1:="COD*"
Range("AG:AG").Copy
Range("AM:AM").PasteSpecial
End Sub
This does quite literaly what you asked:
filter your range
copy colmun AG (because it is filtered, only filtered values are copied)
paste filtered values in AM
you can not use an equation on a range for an entire range. Also, judging by your description, I assume your equation had to be the other way around.

Resources