Sorting a range, Excel says range is empty - vba

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.

Related

Copying columns including blanks without skipping rows..leave "blanks" blank VBA

Aplication Defined error Copying a specified column and range including blanks with an embedded button running multiple Macros. I know that all rows will be filled in column A so if I could reference the rest of the Macros to A.end
I've looked Google youtube and here although there is a lot of info on copying and pasting, I cannot find one that works for this running multiple Macros.
Macros 5 & 6 is where I start having problems because these columns have multiple blanks throughout.
Raw data to Copy:
Destination:
Private Sub CommandButton1_Click()
Worksheets("Sheet1").Range("a2", Range("a2").End(xlDown)).Copy _
Worksheets("Sheet2").Range("a2") 'macro1
Worksheets("Sheet1").Range("d2", Range("d2").End(xlDown)).Copy _
Worksheets("Sheet2").Range("b2") 'Macro2
Worksheets("Sheet1").Range("c2", Range("c2").End(xlDown)).Copy _
Worksheets("Sheet2").Range("c2") 'macro3
Worksheets("Sheet1").Range("g2", Range("g2").End(xlDown)).Copy _
Worksheets("Sheet2").Range("d2") 'macro4
If Worksheets("Sheet1").Range("e2", Range("e2").End(xlDown)).Value = "<0" Then
Worksheets("Sheet2").Range("i2").Copy 'macro5
If Worksheets("Sheet1").Range("e2", Range("e2").End(xlDown)).Value = ">0" Then
Worksheets("Sheet2").Range("j2").Copy 'macro6
Worksheets("Sheet2").Activate 'macro7
Range.end(xldown) only gets you a contiguous range (effectively it will stop at the first blank cell).
Since you want to include blanks, you might want to instead work from the last row of your worksheet back up to the first non-blank cell encountered in that column (which is a way of getting the last row).
This would mean something like:
' If you are new to With statements (below), any objects within the With block that begin with a . relate to "Sheet1". Saves us typing Sheet1 repeatedly, and makes sense to use it since we access a lot of Sheet1's members like range/cells/rows
With Worksheets("Sheet1")
.Range("a2", .cells(.rows.count, "A").End(xlup)).Copy Worksheets("Sheet2").Range("a2") 'macro1
End with
Untested, written on mobile -- but hope it works or gets you closer to a solution. You would need to copy-paste the above and change the A to B, C, D, E, etc. I wasn't too sure what you're trying to achieve with the "<0" condition in macro 5 and 6.
(It would better if you turned the code into a parameterised Sub and just provide the column letter/number as an argument to the sub, but just depends how new you are to VBA and programming in general -- and for the time being whatever is easier for you to understand/maintain.)
Edit regarding macro 5 and 6
With Worksheets("Sheet1")
Dim cell as range
For each cell in .Range("E2", .Cells(.Rows.Count, "E").End(xlUp))
If cell.Value <= 0 Then 'Get rid of the equal sign if you don't want it in your logic/condition'
Cell.Copy Worksheets("Sheet2").cells(cell.row, "I") 'Macro5
ElseIf cell.value > 0 Then
Cell.Copy Worksheets("Sheet2").cells(cell.row, "J") 'Macro6
End If
Next cell
End With
Worksheets("Sheet2").Activate 'macro7

Index Match 2 criteria in VBA

I have a macro I'm trying to create to map a bunch of old values to new values. At one point I need to do a match on 2 columns and get the value from a third column. In normal excel I would run the formula below, but as it is a Formula Array (have to CTRL+SHIFT+ENTER to run) I'm not quite sure how to get this to work in VBA
=INDEX($D:$D,MATCH(1,(E2=$A:$A)*(F2=$B:$B),0))
Any help appreciated
Have you tried?
Cell.FormulaArray()
It should work with normal notation, although it is intended for R1C1
There are essentially three ways to evaluate an array formula to a result within VBA.
The first is 'square bracket' evaluation. This processes a formula just as if it is on the worksheet.
Dim result As Variant
result = [INDEX('Sheet1'!D:D,MATCH(1,(E2='Sheet1'!A:A)*(F2='Sheet1'!B:B),0))]
Debug.Print result
Care must be given to explicitly show worksheet parentage. In the above, the full columns have been given a parent worksheet but the individual cells have not. The individual cells will default to the ActiveSheet property which may or may not even be in the same workbook. Define all cell references explicitly!
The second method is with Application.Evaluate method. This allows more freedom with the formulas using string construction.
Dim result As Variant, wsn As String
wsn = Worksheets("Sheet1").Name
result = Application.Evaluate("INDEX('" & wsn & "'!D:D, " & _
"MATCH(1, (E2='" & wsn & "'!A:A)*(F2='" & wsn & "'!B:B),0))")
Debug.Print result
Again, only the full column references have been given parent worksheet references. This should be fixed before run-time use. This method is better for array formulas because you can use string construction to cut the full column references down to the rows in the Worksheet.UsedRange property.
As mentioned, the third method involves writing the formula to a worksheet cell using the Range.FormulaArray property and retrieving the answer from the cell.

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

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)"

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.

Trying to merge columns together in Excel

I appreciate there are a lot of similar questions out there but I've been searching various forums for three days now and not yet found anything which does what I need - so either I'm doing something very strange or my searching skills aren't up to scratch!
I'd really appreciate it if someone could let me know where I'm going wrong, or even link me to a solution which might help as I haven't managed to find one.
I currently have a spreadsheet with six worksheets. Worksheets 2-6 contain data on items which have been sold from different sources. Worksheet 1 currently contains four columns which populate the item data using a macro I've cobbled together into four separate columns. Worksheet 2 contains an 'itemlist' column into which I want to copy the data from each of the four columns in worksheet 2.
I hope this makes sense. At the moment, the code I have is below:
Sub UpdateList()
'Clear the current ranges
Range("PharmacyItems").Clear
Range("PrelabelItems").Clear
Range("RestockItems").Clear
Range("TakehomeItems").Clear
Range("FullItemList").Clear
'Populate control with unique list
Range("PharmacyFullList").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("PharmacyItems"), Unique:=True
Range("PrelabelFullList").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("PrelabelItems"), Unique:=True
Range("RestockFullList").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("RestockItems"), Unique:=True
Range("TakehomeFullList").AdvancedFilter Action:=xlFilterCopy, CopyToRange:=Range("TakehomeItems"), Unique:=True
'Combine the four ranges into one
Range("UniqueLists!$A:$A, UniqueLists!$B:$B, UniqueLists!$C:$C, UniqueLists!$D:$D").Copy Sheets("Drug totals").Range("A2")
'Sort the data
Range("FullItemList").Sort Key1:=Range("FullItemList").Columns(1), Order1:=xlAscending, Orientation:=xlSortColumns, Header:=xlYes, SortMethod:=xlPinYin, DataOption1:=xlSortNormal, DataOption2:=xlSortNormal, DataOption2:=xlSortNormal
End Sub
In order to clarify the above, here is a definition of which range is which:
PharmacyItems, PrelabelItems, RestockItems and TakehomeItems: these are the individual lists which contain the unique items copied from each data worksheet.
FullList: the fulllist of the above four are the source data lists which are not unique lists
FullItemList: the column into which I want all the data from the unique lists to end up
The reason I have a range which specifies each column rather than using a named range is that I was trying to see if this would make it any better as originally it was just giving me a vague and fluffy range issue error. With the columns defined in the range it tells me the size/shape of the destination doesn't match the source.
The exact error is:
Run-time error '1004':
The information cannot be pasted because the Copy area and the paste area are not the same size and shape. Try one of the following:
- click a single cell, and then paste
- select a rectangle that's the same size and shape, and then paste
Can anyone help me? Sadly I'm a SQL Server girl, I'd far rather be pulling data from a database but I'm not allowed on this one!
Thank you in advance
Summer
You can't paste an entire column to a range starting on row 2 (or any other row than 1) because then the last row(s) of the column won't fit on the sheet. That's why Excel says "the Copy area and the paste area are not the same size".
Instead of
Range("UniqueLists!$A:$A, UniqueLists!$B:$B, UniqueLists!$C:$C, UniqueLists!$D:$D").Copy Sheets("Drug totals").Range("A2")
try pasting it starting on the first row.
Range("UniqueLists!A:D").Copy Sheets("Drug totals").Range("A1")
But I'm guessing you don't have data all the way down to the very bottom of your "UniqueLists" sheet? If so, then why are you copying the entire column? Just copy the part you need. Then you'll be able to paste starting on cell "A2". Example:
Range("UniqueLists!A1:D1234").Copy Sheets("Drug totals").Range("A2")
If you don't need the individual unique lists but just want to create a single column of all the unique values then this should work for you (untested though...)
Sub UpdateList()
Range("FullItemList").Clear 'Clear the full item list range
'Populate control with unique list
UniquesToFullItemList Range("PharmacyFullList")
UniquesToFullItemList Range("PrelabelFullList")
UniquesToFullItemList Range("RestockFullList")
UniquesToFullItemList Range("TakehomeFullList")
'Sort the data
Range("FullItemList").Sort Key1:=Range("FullItemList").Columns(1), _
Order1:=xlAscending, Orientation:=xlSortColumns, Header:=xlYes, _
SortMethod:=xlPinYin, DataOption1:=xlSortNormal, DataOption2:=xlSortNormal, _
DataOption2:=xlSortNormal
End Sub
Sub UniquesToFullItemList(rngFrom As Range)
rngFrom.AdvancedFilter Action:=xlFilterCopy, _
CopyToRange:=Sheets("Drug totals").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0), _
Unique:=True
End Sub