Forum Discussion
To run a macro on another excel sheet with a different number of rows
The following macro assumes that you have public holidays in column B of the worksheet named Holidays in your PERSONAL.XLSB workbook, and that the list of dates on the active sheet is in column F.
You can change the name of the sheet and the columns by editing the constants at the beginning of the macro.
Sub ListSpecialDates()
Const sn = "Holidays" ' name of the sheet with public holidays
Const cs = "B" ' column with public holidays
Const ct = "F" ' column with dates on target sheet
Dim ws As Worksheet
Dim rs As Range
Dim a1 As String
Dim a2 As String
Dim wt As Worksheet
Dim mt As Long
Application.ScreenUpdating = False
' Refer to sheet in PERSONAL.XLSB
Set ws = Workbooks("PERSONAL.XLSB").Worksheets(sn)
' Range with public holidays
Set rs = ws.Columns(cs)
' Address of holidays column
a1 = rs.Offset(0, -1).Address(ReferenceStyle:=xlR1C1, External:=True)
' Address of description column
a2 = rs.Address(ReferenceStyle:=xlR1C1, External:=True)
' Target sheet
Set wt = ActiveSheet
' Last used row in date column
mt = wt.Range(ct & wt.Rows.Count).End(xlUp).Row
' Range in column to the right
With wt.Range(ct & "2:" & ct & mt).Offset(0, 1)
' Set formulas
.FormulaR1C1 = "=IFERROR(INDEX(" & a1 & ",MATCH(RC[-1]," & a2 & _
",0)),IF(WEEKDAY(RC[-1],2)>5,TEXT(RC[-1],""ddd""),""""))"
' Replace formulas with their result
.Value = .Value
End With
Application.ScreenUpdating = True
End SubThanks for your excellent response. I now wish to highlight a row that contains the last date 14 days from today’s date. The sheet already includes a column of dates in ascending order. The background colour of the row can be say yellow. Of course the sheet can have a variable number of rows. The date column is say column G. Of course if there is no exact date in the date column 14 days ahead then the next closest last date will suffice. Grateful for your thoughts.
- waygarJan 11, 2023Brass ContributorOk I now know what the cause is - assigning a shortcut key to the macro.
Even with your code, assigning a shortcut key such as CTRL SHFT U makes the code only work if run twice. I don't know why! - HansVogelaarJan 11, 2023MVP
I cannot explain that.
P.S. This discussion has become very long and awkward to navigate.
If you have a new question unrelated to the current discussion, would you be so kind to start a new discussion? Thanks in advance.
- waygarJan 11, 2023Brass ContributorSorry Hans
I did have a typo and your code now works in PERSONAL.XLSB
Why my code needs the dual run is a mystery? - HansVogelaarJan 11, 2023MVP
In that case, I have no idea why it doesn't work, but you could try
Set wbkClass = ActiveWorkbookas in your original code.
- waygarJan 11, 2023Brass ContributorYes
- HansVogelaarJan 11, 2023MVP
Are you sure that your workbook is named Classf.xlsx and that it is open in Excel?
- waygarJan 11, 2023Brass ContributorNope same error.
Runs perfectly if I remove Personal.XLSB from my XLSTART - HansVogelaarJan 11, 2023MVP
Yes, that requires a change to the code. Change the line
Set wbkClass = ThisWorkbookto
Set wbkClass = Workbooks("Classf.xlsx") - waygarJan 11, 2023Brass ContributorThanks Hans,
However when I put your code into a module within my PERSONAL.XLSB there are errors.
This was where my own macro sat and had the unusual two pass requirement. Could placing the macro within PERSONAL.XLSB cause issues? Your code now produces a runtime error 9 - HansVogelaarJan 11, 2023MVP
I streamlined the code a bit. It works on the first run for me...
See the attached version (now a macro-enabled workbook).
- waygarJan 11, 2023Brass Contributor
Hi Hans,
I have produced two small examples.
Load Classf.xlsx and run the macro below.
This will load WAL.xlsx and it is then supposed to copy all data from the sheet "ClassB_List" in Classf.xlsx and paste it at the end of the existing data in the sheet "Allocation List" in WAL.xslx.
However the first execution of the macro seems to load WAL.xlsx but does nothing more until you run the macro again and everything is then okay.
Do you have any ideas what the problem may be?Sub UpdateLists()
Dim l2Row As Long
Dim BNRows1 As Long
Application.ScreenUpdating = FalseWorkbooks("Classf.xlsx").Activate
Workbooks("Classf.xlsx").Sheets("ClassB_List").Activate
BNRows1 = ActiveSheet.Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
Workbooks.Open "C:\Home\Coding\WAL.xlsx"Workbooks("WAL.xlsx").Activate
Workbooks("WAL.xlsx").Sheets("Allocation List").Activate
l2Row = Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
l2Row = l2Row + 1
Workbooks("Classf.xlsx").Worksheets("ClassB_List").Range("A2", "K" & BNRows1).Copy _
Workbooks("WAL.xlsx").Worksheets("Allocation List").Range("A" & l2Row)
Range("A2").Select
Workbooks("Classf.xlsx").Close SaveChanges:=False
Application.ScreenUpdating = True
End Sub - waygarJan 11, 2023Brass ContributorHi Hans,
I have produced two small examples.
Load Classf.xlsx and run the macro below.
This will load WAL.xlsx and it is then supposed to copy all data from the sheet "ClassB_List" in Classf.xlsx and paste it at the end of the existing data in the sheet "Allocation List" in WAL.xslx.
However the first execution of the macro seems to load WAL.xlsx but does nothing more until you run the macro again and everything is then okay.
Do you have any ideas what the problem may be? - waygarJan 10, 2023Brass ContributorSorry Hans,
The files are too large. It just occurred to me that I had processed the original file, ClassfctnRptNew1482174.xlsx with another macro but did not save it before running the macro in question. I guess the 2nd execution of the macro in question forced some sort of update of ClassfctnRptNew1482174.xlsx ? - HansVogelaarJan 10, 2023MVP
I'd have to se a copy of both workbooks.
- waygarJan 10, 2023Brass Contributor
Hi Hans,
Any idea why I have to run the macro below twice for it to actually work?
ClassfctnRptNew1482174.xlsx is already open and the macro is run from there to open
Work Allocation List-test.xlsx and copy a block of data from ClassfctnRptNew1482174.xlsx to
Work Allocation List-test.xlsx
Sub UpdateLists()
Dim l2Row As Long
Dim BNRows1 As Long
Application.ScreenUpdating = FalseWorkbooks.Open "G:\Classification Workflow\Classification Admin\Work Allocation List-test.xlsx"
Workbooks("Work Allocation List-test.xlsx").Activate
Workbooks("Work Allocation List-test.xlsx").Sheets("Allocation List").Activate
l2Row = Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
l2Row = l2Row + 1
BNRows1 = 1809
Workbooks("ClassfctnRptNew1482174.xlsx").Worksheets("ClassB_List").Range("A2", "K" & BNRows1).Copy _
Workbooks("Work Allocation List-test.xlsx").Worksheets("Allocation List").Range("A" & l2Row)
Range("A2").Select
Workbooks("ClassfctnRptNew1482174.xlsx").Close SaveChanges:=False
Application.ScreenUpdating = True
End Sub - HansVogelaarJan 05, 2023MVP
Copying, inserting and deleting rows is slow in worksheets with lots of rows, but I agree that this is ridiculous. I put a timer on it, and each copy/insert/delete action took about 2.55 seconds on my PC.
Unfortunately, I don't see how we can speed it up (turning off automatic calculation temporarily had only a marginal effect).
- waygarJan 05, 2023Brass Contributor
Hi Hans,
I hope you had a good break.
I have attached two links below. Each has a worksheet.
The macro I am using is an adaption of your latest macro sent to me and is attached below. It works but the question is:
Why does it take so long to copy five rows using for example Felixh as the input in one example whereas in the other example it is almost instantaneous. The reason I ask is that in reality the destination sheet can contain thousands of rows and the time taken to copy and insert only a small number of rows from the source sheet to the destination sheet is unrealistic.
The only difference between the two examples is that I have reduced the number of rows in the destination sheet. I have tried to be specific in the ranges in the code but this has made no difference.
Do you have a solution to speeding the code up or what am I doing wrong?
Thank you.
https://urldefense.com/v3/__https:/www.dropbox.com/s/7msm1kkj9o6228u/Work*20Allocation*20List-test.xlsm?dl=0__;JSU!!MiK4Rck!SP58571kS6E1ddOdhS22BVWu5Cl3lssoEt8nW3B0bH4IX2WvefzmvO0S8I9qC38oZISly6dtiVBBLVwJhg0CQDOl$
https://urldefense.com/v3/__https:/www.dropbox.com/s/cykuhksqmktm1f8/Work*20Allocation*20List-test-short.xlsm?dl=0__;JSU!!MiK4Rck!SP58571kS6E1ddOdhS22BVWu5Cl3lssoEt8nW3B0bH4IX2WvefzmvO0S8I9qC38oZISly6dtiVBBLVwJhsiaWvmZ$
The macro is as follows
Sub MoveData_test()
Dim sht1 As Worksheet
Dim sht3 As Worksheet
Set sht1 = Sheets("Seven Day List")
Set sht3 = Sheets("Completed List")
'
Dim strName As String
Dim r As Long
Dim rng As Range
strName = InputBox("Username for Completion Data Transfer?")
If strName = "" Then Exit Sub
Application.ScreenUpdating = False
'
' Transfer completed classified media from Seven Day List (Sheet7) to Completed List (Sheet9).
'
Dim l1Row As Long
Dim l3Row As Long
Dim Count As Long
Dim first As Long
Dim last As Long
Dim rc As Long
'
'
l1Row = sht1.Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
l3Row = sht3.Cells.Find(What:="*", After:=Range("A1"), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
'
r = 10
first = 2
If l3Row > 101 Then
first = l3Row - 100
End If
last = l3Row + l1Row - r + 1
rc = r
For Count = rc To l1Row
If InStr(1, sht1.Range("J" & r).Value, strName, vbTextCompare) > 0 And (LCase(sht1.Range("K" & r).Value) = "y" Or LCase(sht1.Range("L" & r).Value) = "y") Then
sht1.Range("O" & r).Value = Date
Set rng = sht3.Range("J" & first, "J" & last).Find(What:=strName, LookAt:=xlPart, SearchDirection:=xlPrevious, MatchCase:=False)
If rng Is Nothing Then
Set rng = sht3.Range("J" & first, "J" & last).Find(What:="*", SearchDirection:=xlPrevious)
ElseIf rng.Offset(0, 5).Value <> Date Then
Set rng = sht3.Range("J" & first, "J" & last).Find(What:="*", SearchDirection:=xlPrevious)
End If
sht1.Range("A" & r).EntireRow.Copy
rng.Offset(1).EntireRow.Insert
sht1.Range("A" & r).EntireRow.Delete
r = r - 1
End If
r = r + 1
Next Count
Set rng = sht3.Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious)
Application.Goto sht3.Range("A" & rng.Row), True
Application.ScreenUpdating = True
End Sub - HansVogelaarDec 20, 2022MVP
Happy Holidays and best wishes for 2023 to you too.
- waygarDec 20, 2022Brass ContributorOk Hans,
I am done for this year.
Thanks for all you have helped with. I appreciate it.
Merry Christmas and I hope 2023 brings you more joy and knowledge.
Cheers,
Wayne - HansVogelaarDec 20, 2022MVP
It's very easy to do this without VBA:
- Select column B.
- On the Data tab of the ribbon, click 'Text to Columns'.
- Click 'Next >' twice.
- In Step 3, select Date, and select YMD from the drop down next to it.
- Click Finish.
As a macro:
Sub Convert2Date() Range("B:B").TextToColumns DataType:=xlDelimited, FieldInfo:=Array(1, xlYMDFormat) End Sub - waygarDec 20, 2022Brass Contributor
Perfect now, Thank you so much Hans.
The following request will help me understand a little more about VBA.
Attached is a sample spreadsheet.
Using VBA with Range B:B, how to convert the values in Column B (which are NOT in date format, but a general format) to a date format as follows:
20230205 ----> 5/02/2023
Probably using the formula: B(I)=Date(Left(B(I),4,2),Mid(B(I),5,2),Right(B(I),2))
Thanks.
Cheers,
Wayne - HansVogelaarDec 20, 2022MVP
Aha - from the way your data were laid out on Sheet3, I thought you wanted to keep rows for the same name together. Try this version:
Sub MoveData() Dim strName As String Dim r As Long Dim rng As Range strName = InputBox("Username for Completion Data Transfer?") If strName = "" Then Exit Sub Application.ScreenUpdating = False r = 11 Do If InStr(1, Sheet7.Range("J" & r).Value, strName, vbTextCompare) > 0 And LCase(Sheet7.Range("K" & r).Value) = "y" Then Sheet7.Range("O" & r).Value = Date Set rng = Sheet9.Range("J:J").Find(What:=strName, LookAt:=xlPart, SearchDirection:=xlPrevious, MatchCase:=False) If rng Is Nothing Then Set rng = Sheet9.Range("J:J").Find(What:="*", SearchDirection:=xlPrevious) ElseIf rng.Offset(0, 5).Value <> Date Then Set rng = Sheet9.Range("J:J").Find(What:="*", SearchDirection:=xlPrevious) End If Sheet7.Range("A" & r).EntireRow.Copy rng.Offset(1).EntireRow.Insert Sheet7.Range("A" & r).EntireRow.Delete r = r - 1 End If r = r + 1 Loop Until Sheet7.Range("C" & r).Value = "" Set rng = Sheet9.Cells.Find(What:="*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious) Application.Goto Sheet9.Range("A" & rng.Row), True Application.ScreenUpdating = True End Sub - waygarDec 20, 2022Brass ContributorNope eg If you run the macro using FELIXH, this row in Sheet1 is placed after the last occurrence of FELIXH dated 8/12/2022 and rather should be placed after the last row that has Paulyne dated 21/12/2022.
You can change the forward dates in Sheet3 of 21/12/2022 to say 20/12/22 (typos on my part) and the same thing happens.
Row placement from Sheet1should only be inserted after the last occurrence of FELIXH in Sheet3 if that date in Sheet3 matches the current date set in Sheet1 before transfer to Sheet3, otherwise it goes after the last row which in this case is PAULYNE dated 20/12/2022 (corrected) - HansVogelaarDec 20, 2022MVP
As far as I can tell the macro already does that, unless you manually change dates in column O to future dates...
- waygarDec 20, 2022Brass Contributor
Hi Hans,
I have sorted out the error I was getting.
I have attached a sample workbook with your macro (MoveData) included (Hotkey is Ctrl Shft e) again as there is still one issue in the initial request that needs to be actioned:
When a row containing the Name and Date is copied from Sheet1 to Sheet3, that row should be inserted under the last occurrence of that (Same Name and Same Date) in Sheet3. However, if there is not an equivalent Name and associated Date in Sheet3, then the row should be placed beneath the last occupied row in Sheet3.