Copy a reference formula down to stay in line with updating data - vba

I have a macro and one of the columns it produces is a column of dates. I wish to use this excel formula
=IF(COUNTIF(Sheet2!A9:A102,K2)>0, K2,J1)
But have it copy down so it always goes as far as the column of dates do its left. Basically when a new date gets added, this formula will copy down another cell. I tried using this:
Range("J2:J" & LastRow).FormulaR1C1 = "=IF(COUNTIF(Sheet2!R[7]C[-9]:R[100]C[-9],RC[1])>0, RC[1],R[-1]C)"
But get "method 'range' of object '_global' failed.

This Works. The destination of lastrow was incorrect but this now tracks the data in the row to the left.
Range("J2:J" & (Range("I" & Rows.Count).End(xlUp).Row)).FormulaR1C1 = "=IF(COUNTIF(Sheet2!R[7]C[-9]:R[100]C[-9],RC[1])>0, RC[1],R[-1]C)"

Related

Sorting a range, Excel says range is empty

I try to sort a range (containing 3 columns) I want to sort the data on the second column and if there are two things the same in that column I want it to sort it via the first column.
The second and the first column are always filled in.
Here is the line I use, but I keep getting the error:
Runtime error 1004: The sort reference is not valid, make sure that it's within the data you want to sort, and the first Sort By box isn't the same or blank
Target.Sheets("SheetToSort").Range("A1:C" & m).Sort Key1:=Range("B1:B" & m), Order1:=xlAscending, key2:=Range("A1:A" & m), order2:=xlAscending
Target is a defined workbook, the sheet exists, cells "A1:C" & m contain data only column C might have empty spaces but I don't sort anything on that column.
Thanks for your help!
I'd just make sure all your ranges refer to the same sheet, so amend it like this:
Target.Sheets("SheetToSort").Range("A1:C" & m).Sort _
Key1:=Target.Sheets("SheetToSort").Range("B1:B" & m), Order1:=xlAscending, _
Key2:=Target.Sheets("SheetToSort").Range("A1:A" & m), Order2:=xlAscending
I know I've had issues before where this has happened because the Range object, when you don't specify the sheet, might be pointing to a different sheet than you think.

Compare Cell Data and Copy

I found this great snip of code and I am trying to manipulate it to work for me, but I just can't seem to get it. Unfortunately I haven't been able to get my head around it to fully understand it, which doesn't help. So I turn to you. I need to evaluate a column of cells and look for either similarities or differences. If a cell in sheet 1 column 1 is not the same as any of the cells in sheet 2 column 1, I want to copy the entire row into sheet 1 at the bottom of the used area. I've gotten this to the point where what you see will copy the correct first cell, but I can't manipulate it to copy the entire row. I think because of how the 'With' is structured but I need to try to stay away from doing loops since there is over 30k cells to evaluate.
Going down the road I will also be wanting to look for duplicates using the same method above, and if there is a duplicate, compare the adjacent cells for differences and if there is a difference, move the existing data into a comment and move the new data into the existing cell.
Any and all advice is, as always, very appreciated.
Sub Compare_Function()
Call Get_Master_Cell_Info
Application.ScreenUpdating = False
With Sheets("Update").Range(Cells(4, 1), Cells(Rows.Count, 1).End(xlUp)).Offset(, 1)
.Formula = "=VLOOKUP(A4,'New Master Data 6.1'!A:A,1,FALSE)"
.Value = .Value
.SpecialCells(xlCellTypeConstants, 16).Offset(, -1).Copy Sheets("New Master Data 6.1").Range("A" & Rows.Count).End(xlUp).Offset(1)
.ClearContents
End With
Application.ScreenUpdating = True
End Sub
Quick line by line breakdown
This just takes the entire used range from cells A4 to the last used cell in columnA then offsets it by one column so B4:Bx (x is the last used row in column A)
With Sheets("Update").Range(Cells(4, 1), Cells(Rows.Count, 1).End(xlUp)).Offset(, 1)
This puts the formula in all cells so it looks up A4,A5,A6, etc in master sheet, returns the value in the master sheet or an error if its not found. It then copies the values over so they are hardcoded in
.Formula = "=VLOOKUP(A4,'New Master Data 6.1'!A:A,1,FALSE)"
.Value = .Value
Specialcells looks for constants (all cells) and value 16 which means error cells (ie cells don't exist) offsets by -1 (so column A) and copies to new sheet column A at rows.count+1
.SpecialCells(xlCellTypeConstants, 16).Offset(, -1).Copy Sheets("New Master Data 6.1").Range("A" & Rows.Count).End(xlUp).Offset(1)
You might also want to do this after you .clearcontents so you don't get all the error cells in column B
to fix it just change the copied range to .entirerow so
.SpecialCells(xlCellTypeConstants, 16).entirerow.Copy Sheets("New Master Data 6.1").Range("A" & Rows.Count).End(xlUp).Offset(1)
You will also copy the errors in column B but with this structure there is no getting around that. Can always erase them from the master sheet after.
Also note this code will overwrite any data you have stored in column B.
One more note this code depends on the sheet update being active, it won't run otherwise since your cells function inside your range needs the worksheet explicitly stated, as does your rows.count. You would be better wrapping the whole thing in 2 withs, one for the sheet and one with the range (using .cells and .rows.counmt)

Syntax error for INDEX formula using Macro

I'm getting a syntax error when I try to insert a formula in a cell using Macro. I can't seem to figure out what am I doing wrong? The formula works fine when I manually enter it. Here's my code:
ws3.Range("F2:F" & lastRow3).Formula = "=INDEX($L$1:INDEX(L:L,MATCH("ZZZ",D:D)),AGGREGATE(15,6,ROW($K$1:INDEX(K:K,MATCH("ZZZ",D:D)))/($K$1:INDEX(K:K,MATCH("ZZZ",D:D))=D2),COUNTIF($D$1:$D2,D2)))"
ws3 is the worksheet, and lastRow3 is just to autofill the contents by comparing to a column to the left. Any ideas why this is giving an error?
FYI: This formula is finding values in one column from another column and giving the adjacent entries.
When filling a full range it is best to use R1C1 format.
Also with using vba to set the last row there is no reason for all the INDEX(L:L,MATCH("ZZZ",D:D)) to find the last row, since the code itself can set it directly.
Use this:
ws3.Range("F2:F" & lastRow3).FormulaR1C1 = _
"=INDEX(R1C12:R" & lastrow & "C12,AGGREGATE(15,6,ROW(R1C11:R" & lastrow & "C11)/(R1C11:R" & lastrow & "C11=RC[-2]),COUNTIF(R1C4:RC4,RC[-2])))"

VBA to assign a cell content as a formula not its results

I'm trying to assign a cell a formula using VBA, but every time I run the code it assign to the cell the result not the formula itself, like when I enter the formula using the excel spreadsheet.
Does anyone know how to display the formula using a macro within a cell and not the formula result.
I'm asking this because I need to insert this line within an existing sheet among other data and then run another macro to keep it updated, and the macro depends on this formula.
The code I'm using
Cells(C, 9).Formula = Application.Index(Plan2.Range("B2:D10000"), _
Application.Match(Plan1.Range("B" & C) & Range("F" & C), Plan2.Range("A2:A10000"), 0), 3)
As you can see this formula depends on the row that its inserted.
Your Formula is ultimately being reduced to whatever is returned by Application.Index. Unless the value being returned there is an actual formula string then you will just get a number as the result and this is set to the .Formula.
If you want to actually set the formula, you need to create a string in VBA that represents the formula to use. In this case, that string would look something like:
Cells(C, 9).Formula = "=INDEX(Plan2!B2:D10000, MATCH(Plan1!B" & C & "..."
where you concatenate in the dynamic parts. The end result needs to look like a normal formula. The Application.XXX and Application.WorksheetFunction.XXX functions return actual results, not pieces that can be combined to create a formula.

VBA runtime error - 1004 when trying to format or delete cells after pasting values

I am trying to use VBA to make my life easier but I keep getting a problem which I can't work around. Basically what I want is to copy some values from several output csv files I've got, to a nice formatted excel file. Then according to some bases numbers delete values or format the cells.
However I keep getting the same error message Run-time error '1004' application-defined or object defined error. I am doing that using many output files and pasting values at the same table file but on different sheets (10.2a, 10.2b, 10.2c, ...) by having macros for each sheet. I run all the macros in one using another macro that contains all the other macros
I looked a lot in other posts but don't understand where the error comes from. Any help would be much appreciated. The code I use for one sheet is below as an example.
Sub Table_10_2a()
'
' Copy Data from one file to another
'
Dim Output As Workbook
Dim Table As Workbook
Dim i As Integer
'Open workbooks
Set Output = Workbooks.Open("O:\...\Output.csv")
Set Table = Workbooks.Open("O:\...\Table.xlsx")
'Copy paste data from output file to Table
Output.Sheets("Output1").Range("B3:E7").Copy
Table.Sheets("10.2a").Range("B11").PasteSpecial xlValues
Output.Sheets("Output1").Range("B9:E13").Copy
Table.Sheets("10.2a").Range("B17").PasteSpecial xlValues
Output.Sheets("Output1").Range("B15:E15").Copy
Table.Sheets("10.2a").Range("B23").PasteSpecial xlValues
Output.Sheets("Output1").Range("B17:E21").Copy
Table.Sheets("10.2a").Range("B26").PasteSpecial xlValues
Output.Sheets("Output1").Range("B23:E27").Copy
Table.Sheets("10.2a").Range("B32").PasteSpecial xlValues
Output.Sheets("Output1").Range("B29:E29").Copy
Table.Sheets("10.2a").Range("B38").PasteSpecial xlValues
Output.Sheets("Output1").Range("B30:E30").Copy
Table.Sheets("10.2a").Range("B40").PasteSpecial xlValues
For i = 2 To 5
'Delete cells for values below 30
If Table.Sheets("10.2a").Cells(40, i).Value < 30 Then
Table.Sheets("10.2a").Range(Cells(26, i), Cells(36, i)).ClearContents
Table.Sheets("10.2a").Cells(38, i).NumberFormat = """[""0""]"""
Table.Sheets("10.2a").Cells(40, i).NumberFormat = """[""0""]"""
End If
'Format cells for values below 50
If Table.Sheets("10.2a").Cells(40, i).Value < 50 And Table.Sheets("10.2a").Cells(40, i).Value > 30 Then
Table.Sheets("10.2a").Range(Cells(26, i), Cells(38, i)).NumberFormat = """[""0.0""]"""
Table.Sheets("10.2a").Cells(40, i).NumberFormat = """[""0""]"""
End If
Next i
'Save file
Table.Save
'Close files
Output.Close
Table.Close
End Sub
This usage of Cells inside Range to build a block of cells commonly falls victim to an unqualified reference. In this case, you are using Table.Sheets("10.2a") to specify the sheet for Range but are not using the same qualifier on Cells. This means that Cells will use the default context available which varies with where the code is executing. Possibilities:
Inside a code module or ThisWorkbook, Cells refers to the ActiveSheet
Inside a Worksheet code behind, Cells refers to that Worksheet regardless of the ActiveSheet
Use Address to get around the different sheets
One approach is to follow the call to Cells with Address. This resolves the problem because Address returns the cell address without the sheet name. This is then interpreted by Range within its context which is Sheets("10.2a").
Range(Cells(26, i).Address, Cells(36, i).Address).ClearContents
Qualify the reference (generally preferred)
Another way to resolve this error is to qualify the reference by adding a sheet name before Cells: Table.Sheets("10.2a").Cells. Full line:
Range(Table.Sheets("10.2a").Cells(26, i), Table.Sheets("10.2a").Cells(36, i)).ClearContents
This type of code looks better within a With... End With block.