I have an issue. I am filtering from a big product table (with about 32'000 rows) the products that I need and sort it first by the product name and then by the delivery number.
My issue is, that if I wanna filter and sort numbers as product names (which is also possible), it does not sort correctly (see picture).
Picture of the filtered and sorted table
My code is this one:
'*************************************************************
'Filter Product Code
Set myrange = Range("A1:A" & lastrow)
For Each c In myrange
If Len(c.Value) <> 0 Then
ThisWorkbook.Worksheets(Worksheets.Count).Columns("A:D").AdvancedFilter xlFilterCopy, _
Sheet1.Range("A1:A" & lastrow), Sheet1.Range("G1"), False
End If
Next
'Sheet1.Range("51:100").RemoveDuplicates Columns:=3, Header:=xlYes
'*******************************************************************
'Sort the filtered list first by Product Code then by the Delivery number
Dim lngRow As Long
Dim lngRowMax As Long
Dim wsf As WorksheetFunction
With Sheet1
lastrow = Cells(Rows.Count, 8).End(xlUp).Row
Range("G2:J" & lastrow).Sort Key1:=Range("G2:G" & lastrow), _
Order1:=xlAscending, Key2:=Range("I2:I" & lastrow), _
Order1:=xlAscending, Header:=xlNo
Set wsf = Application.WorksheetFunction
lngRowMax = .UsedRange.Rows.Count
End With
How can I proceed to have it sorted correctly. First the same product codes, then by the delivery number (ascending) as I want to sell the oldest products first.
Thank you for your reply.
Now I found the solution for it. Only a small adjustment. The code for the sorting looks as follows now:
Dim lngRow As Long
Dim lngRowMax As Long
Dim wsf As WorksheetFunction
With Sheet1
lastrow = Cells(Rows.Count, 8).End(xlUp).Row
Range("G1:J" & lastrow).Sort Key1:=Range("G1:G" & lastrow), _
Order1:=xlAscending, Key2:=Range("I1:I" & lastrow), _
Order2:=xlAscending, Header:=xlYes, DataOption1:=xlSortTextAsNumbers
Set wsf = Application.WorksheetFunction
lngRowMax = .UsedRange.Rows.Count
End With
Related
I'm trying to autofill this formula from AD2 down to the end of the dataset. But, instead, my macro will use the formula on AD1 (the column title) and not fill down. I've done this several times, but I can't figure out why it's acting up now. The obnoxious formula is reading the from the cell a few columns over (AB) and then declares one of three strings.
Dim lastRow As Long
lastRow = Cells(Rows.Count).End(xlUp).Row
Range("AD2").Select
Selection.FormulaR1C1 = _
"=IF(NOT(ISERROR(FIND(""iMac"",RC[-2]))),""iMac"",IF(NOT(ISERROR(FIND(""MacBook"",R[-21]C[-2]))),""MacBook"",""N/A""))"
Range("AD2").Select
Selection.AutoFill Destination:=Range("AD2:AD" & lastRow)
try to modify your var lastRow with ActiveSheet.Cells(ActiveSheet.Rows.Count, "AB").End(xlUp).Row
Sub test()
Dim lastRow As Long
lastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "AB").End(xlUp).Row
Range("AD2").Select
Selection.FormulaR1C1 = _
"=IF(NOT(ISERROR(FIND(""iMac"",RC[-2]))),""iMac"",IF(NOT(ISERROR(FIND(""MacBook"",R[-21]C[-2]))),""MacBook"",""N/A""))"
Range("AD2").Select
Selection.AutoFill Destination:=Range("AD2:AD" & lastRow)
End Sub
Try this. You are missing a column in your Cells (I have used column A so change to suit) and you don't need to select anything. In fact you probably don't need Autofill at all, just apply to the whole range in one go.
Sub y()
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
With Range("AD2")
.FormulaR1C1 = _
"=IF(NOT(ISERROR(FIND(""iMac"",RC[-2]))),""iMac"",IF(NOT(ISERROR(FIND(""MacBook"",R[-21]C[-2]))),""MacBook"",""N/A""))"
.AutoFill Destination:=Range("AD2:AD" & lastRow)
End With
End Sub
Each row can have different last used column.I want to check column for each row which is last column. How I can do that?
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim LastCol As Long
Dim rng As Range
Set ws = Sheets("Sheet1")
Set rng = ws.Cells.Find(What:="*", _
After:=ws.Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
If rng Is Nothing Then
LastCol = 1
Else
LastCol = rng.Column
End If
Debug.Print LastCol
End Sub
This code is for finding last column(common for all rows). But I want to check different last used column for each row.
There are a number of different ways, here is one demo using the following data. It also gives you one method for finding the last row using column A. You may need to write something to convert column number to column letter.
Note also that you can specify the row/col being tested, by using either a variable e.g. rw as in Cells(rw, Columns.Count) or a constant e.g. "A" as in Cells(Rows.Count, "A").
Finally, especially if you are using multiple worksheets, you may also need to take care to specify the worksheet on which the data you are using resides, as in Sheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row. In my example, and unless otherwise 'qualified' in this way, the data on the ActiveSheet will be used. So be sure to select the sheet containing your data before running this code example.
Option Explicit
Sub lastCol()
Dim lCol As Long, rw As Long
For rw = 1 To Cells(Rows.Count, "A").End(xlUp).Row
lCol = Cells(rw, Columns.Count).End(xlToLeft).Column
MsgBox "For row " & rw & ", last column is " & lCol
Next rw
End Sub
EDIT
Sub lrow()
Dim lCol As Long, rw As Long
For rw = 1 To Cells(Rows.Count, "A").End(xlUp).Row
lCol = Cells(rw, Columns.Count).End(xlToLeft).Column
If Cells(rw, lCol).Value = "rajani" Then
MsgBox "Row " & rw & ", last column " & lCol & " contains rajani"
End If
Next rw
End Sub
I have two sheets containing the employee records.
Sheet1 contains the Event Date, CardNo, Employee Name, Dept Id, Employee No, Entry and Exit Time, Total Working Hours, Status, ConcatinatedColumn and Remarks (copied through vlookup from sheet2)
Sheet2 contains ConcatinatedColumn, Event Date, Employee No, Name, Remarks.
If the data in the remarks column of sheet2 is "Sick Off" then that row should be inserted to sheet1 without effecting the previous records.
I've already written the code for it but it does not work.
Would be really grateful if anyone can help me out !
THANKS IN ADVANCE !
MY CODE :
Sub SickOff()
Dim objWorksheet As Sheet2
Dim rngBurnDown As Range
Dim rngCell As Range
Dim strPasteToSheet As String
'Used for the new worksheet we are pasting into
Dim objNewSheet As Sheet1
Dim rngNextAvailbleRow As Range
'Define the worksheet with our data
Set objWorksheet = ThisWorkbook.Worksheets("Sheet2")
'Dynamically define the range to the last cell.
'This doesn't include and error handling e.g. null cells
'If we are not starting in A1, then change as appropriate
Set rngBurnDown = objWorksheet.Range("G2:G" & objWorksheet.Cells(Rows.Count, "G").End(xlUp).Row)
'Now loop through all the cells in the range
For Each rngCell In rngBurnDown.Cells
objWorksheet.Select
If rngCell.Value = "Sick Off" Then
'select the entire row
rngCell.EntireRow.Select
'copy the selection
Selection.Copy
'Now identify and select the new sheet to paste into
Set objNewSheet = ThisWorkbook.Worksheets("Sheet1" & rngCell.Value)
objNewSheet.Select
'Looking at your initial question, I believe you are trying to find the next available row
Set rngNextAvailbleRow = objNewSheet.Range("A1:A" & objNewSheet.Cells(Rows.Count, "A").End(xlUp).Row)
Range("A" & rngNextAvailbleRow.Rows.Count + 1).Select
ActiveSheet.Paste
End If
Next rngCell
objWorksheet.Select
objWorksheet.Cells(1, 1).Select
'Can do some basic error handing here
'kill all objects
If IsObject(objWorksheet) Then Set objWorksheet = Nothing
If IsObject(rngBurnDown) Then Set rngBurnDown = Nothing
If IsObject(rngCell) Then Set rngCell = Nothing
If IsObject(objNewSheet) Then Set objNewSheet = Nothing
If IsObject(rngNextAvailbleRow) Then Set rngNextAvailbleRow = Nothing
End Sub
Let's say you have data in Sheet2 as shown below
Let's say the end of data in Sheet1 looks like this
Logic:
We are using autofilter to get the relevant range in Sheet2 which match Sick Off in Col G. Once we get that, we copy the data to the last row in Sheet1. After the data is copied, we simply shuffle data across to match the column headers. As you mentioned that the headers won't change so we can take the liberty of hardcoding the column names for shuffling this data.
Code:
Paste this code in a module
Option Explicit
Sub Sample()
Dim wsI As Worksheet, wsO As Worksheet
Dim lRow As Long, wsOlRow As Long, OutputRow As Long
Dim copyfrom As Range
Set wsI = ThisWorkbook.Sheets("Sheet1")
Set wsO = ThisWorkbook.Sheets("Sheet2")
'~~> This is the row where the data will be written
OutputRow = wsI.Range("A" & wsI.Rows.Count).End(xlUp).Row + 1
With wsO
wsOlRow = .Range("G" & .Rows.Count).End(xlUp).Row
'~~> Remove any filters
.AutoFilterMode = False
'~~> Filter G on "Sick Off"
With .Range("G1:G" & wsOlRow)
.AutoFilter Field:=1, Criteria1:="=Sick Off"
Set copyfrom = .Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow
End With
'~~> Remove any filters
.AutoFilterMode = False
End With
If Not copyfrom Is Nothing Then
copyfrom.Copy wsI.Rows(OutputRow)
'~~> Shuffle data
With wsI
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
.Range("A" & OutputRow & ":A" & lRow).Delete Shift:=xlToLeft
.Range("F" & OutputRow & ":F" & lRow).Copy .Range("K" & OutputRow)
.Range("F" & OutputRow & ":F" & lRow).ClearContents
.Range("B" & OutputRow & ":B" & lRow).Copy .Range("E" & OutputRow)
.Range("B" & OutputRow & ":B" & lRow).ClearContents
End With
End If
End Sub
Output:
I have an excel sheet and I am trying to use a countifs formula to count the number or records meeting multiple conditions, however in one of the columns there are multiple criterias so I used SUMPRODUCT together with the COUNTIFS function.
I got it to work fine in the sheet but I have no idea on how to get it to work in VBA.
This is what I tried:
Dim lastrow As Long
lastrow = Sheet2.Cells(Sheet2.Rows.Count, "M").End(xlUp).Row
FirstDate = Sheets("Sheet1").Range("C7")
SecondDate = Sheets("Sheet1").Range("E7")
Application.Worksheetfunction.Sumproduct(CountIfs(Sheet2.Range("E2:E" & lastrow), ">=" & FirstDate, Sheet2.Range("E2:E" & lastrow), "<=" & SecondDate, Sheet2.Range("P2:P" & lastrow), {"John";"James";"Peter"}))
I keep getting an error when using the above formula. Can you please tell me what I'm doing wrong.
Thanks in advance.
EDIT: This is the formula I'm trying to mimic:
=Sumproduct(CountIfs(Sheet2!E2:E1000000,">="&Sheet1!C7,Sheet2!E2:E1000000,"<="&Sheet1!E7,Sheet2!E2:E1000000,{"John";"James";"Peter"}))
I don't want VBA to insert this formula into the cell, I'd rather have it calculate the value and then insert the result into the chosen cell.
Seems to work for me:
Sub Tester()
Dim v, wsf
Dim lastrow As Long
lastrow = Sheet2.Cells(Sheet2.Rows.Count, "M").End(xlUp).Row
Set wsf = Application.WorksheetFunction
v = Application.WorksheetFunction.SumProduct(wsf.CountIfs( _
Sheet2.Range("E1:E" & lastrow), ">=" & Sheet1.Range("C7").Value, _
Sheet2.Range("E1:E" & lastrow), "<=" & Sheet1.Range("E7").Value, _
Sheet2.Range("P1:P" & lastrow), Array("John", "James", "Peter")))
Debug.Print v
End Sub
VBA is throwing the above given error on the line Sheets("Sheet1").Range("A" & i).Copy Destination:=Sheets("Sheet2").Range("A" & i & "A" & LastCol - 1)
What I am trying to do is actually to copy the "A" & i cell (in first iteration it's A2) to a range in the second worksheet named Sheet2.
Sub FindFill()
Dim DatesRange As Range
Dim i As Integer
Dim TransposeThis As Range
Dim LastCol As Integer
If WorksheetFunction.CountA(Cells) > 0 Then
LastColumn = Cells.Find(What:="*", After:=[A1], _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
End If
With Sheets("Sheet1")
Set DatesRange = Range("B2" & LastCol)
End With
i = 1
Do While i <= ActiveSheet.Rows.Count
Sheets("Sheet1").Range("A" & i + 1).Copy Destination:=Sheets("Sheet2").Range("A" & i & "A" & LastCol - 1)
i = i + 1
Loop
End
End Sub
You are missing a ":" before "A"
Range("A" & i & ":A" & LastCol - 1)
FOLLOWUP
After I went through your comments, I saw lot of errors in your code
1) You have dimmed i as Integer. This can give you an error in Excel 2007 onwards if your last row is beyond 32,767. Change it to Long I would recommend having a look at this link.
Topic: The Integer, Long, and Byte Data Types
Link: http://msdn.microsoft.com/en-us/library/aa164754%28v=office.10%29.aspx
Quote from the above link
Integer variables can hold values between -32,768 and 32,767, while Long variables can range from -2,147,483,648 to 2,147,483,647
2) You are finding the Last Column But in Which Sheet? You have to fully qualify the path Like this.
If WorksheetFunction.CountA(Sheets("Sheet1").Cells) > 0 Then
LastCol = Cells.Find(What:="*", After:=[A1], _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
End If
Same is the case with
With Sheets("Sheet1")
Set DatesRange = Range("B2" & LastCol)
End With
You are missing a DOT before Range
This is the correct way...
.Range("B2....
Also Range("B2" & LastCol) will not give you the range that you want. See the code below on how to create your range.
3) You are using a variable LastColumn but using LastCol. I would strongly advise using Option Explicit I would also recommend having a look at this link (SEE POINT 2 in the link).
Topic: To ‘Err’ is Human
Link: http://www.siddharthrout.com/2011/08/01/to-err-is-human/
4) What happens if there .CountA(Sheets("Sheet1").Cells) = 0? :) I would suggest you this code instead
If WorksheetFunction.CountA(Sheets("Sheet1").Cells) > 0 Then
LastCol = Cells.Find(What:="*", After:=[A1], _
SearchOrder:=xlByColumns, _
SearchDirection:=xlPrevious).Column
Else
MsgBox "No Data Found"
Exit Sub
End If
5) ActiveSheet.Rows.Count will not give you the last active row. It will give you the total number of rows in that sheet. I would recommend getting the last row of Col A which has data.
You can use this for that
With Sheets("Sheet")
LastRow =.Range("A" & .Rows.Count).End(xlup).row
End With
Now use LastRow instead of ActiveSheet.Rows.Count You also might want to use a For Loop so that you don't have to increment i every time. For example
For i = 1 to LastRow
6) Finally You should never use End. Reason is quite simple. It's like Switching your Computer using the POWER OFF button. The End statement stops code execution abruptly, without invoking the Unload, QueryUnload, or Terminate event, or any other Visual Basic code. Also the Object references held (if any) by other programs are invalidated.
7) Based on your image in Chat, I believe you are trying to do this? This uses a code which doesn't use any loops.
Option Explicit
Sub FindFill()
Dim wsI As Worksheet, wsO As Worksheet
Dim DatesRange As Range
Dim LastCol As Long, LastRow As Long
If Application.WorksheetFunction.CountA(Sheets("Sheet1").Cells) = 0 Then
MsgBox "No Data Found"
Exit Sub
End If
Set wsI = Sheets("Sheet1")
Set wsO = Sheets("Sheet2")
With wsI
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
LastRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set DatesRange = .Range("B1:" & Split(Cells(, LastCol).Address, "$")(1) & 1)
.Columns(1).Copy wsO.Columns(1)
DatesRange.Copy
wsO.Range("B2").PasteSpecial xlPasteValues, _
xlPasteSpecialOperationNone, False, True
.Range("B2:" & Split(Cells(, LastCol).Address, "$")(1) & LastCol).Copy
wsO.Range("C2").PasteSpecial xlPasteValues
End With
End Sub