I'm having some issues with last row expression and autofill. I'm not sure what I'm missing here as it looks correct but it doesn't seem to be starting the vlookup in the proper cell (N2, it starts it in N1) and it won't autofill to the last row of M. Any push in the right direction would be greatly appreciated. I'm thinking it's something small I'm overlooking.
Sub Nightly()
'
' Nightly Macro
'
Dim PackSpec As Workbook
Dim FullBook As Workbook
Dim DebFile As Workbook
Dim lrow As Long
lrow = Cells(Rows.Count, 1).End(xlUp).Row
'Open the nightly pack spec file, cut and insert the year row into column D
Set PackSpec = Workbooks.Open("S:\Accounting\Apps\Packspec\CIDExport\Archive\" & Year(Date) & "\" & Month(Date) & "\" & Day(Date) - 1 & "\*.csv")
Columns("A:A").Select
Selection.Cut
Columns("D:D").Select
Selection.Insert Shift:=xlToRight
Range("A2").Select
'Open Fullbook master and insert columns after N then VLookup between Pack Spec and Fullbook
Set FullBook = Workbooks.Open("S:\Corporate\Groups\Comosoft\Downloads\FullBook\fullbook_Master.csv")
Columns("N:U").Select
Selection.Insert Shift:=xlToRight
Range("N2").Select
'Actvate Fullbook and enter Vlookup for dates
Windows("fullbook_Master.csv").Activate
With ActiveSheet.Range("N2")
.FormulaR1C1 = "=VLOOKUP(RC[-1],'[15.50.1.CID.csv]15.50.1.CID'!C[-13]:C[-11],3,0)"
.AutoFill Destination:=Range("N2:N" & lrow) 'issue not autofilling to end
Windows("fullBook_Master.csv").Activate
End With
End Sub
Just move the
lrow = Cells(Rows.Count, 1).End(xlUp).Row
after
Windows("fullbook_Master.csv").Activate
You should:
Link lrow to a sheet to avoid mistakes.
Avoid all the selects.
Sub Nightly()
'
' Nightly Macro
'
Dim PackSpec As Workbook
Dim FullBook As Workbook
Dim DebFile As Workbook
Dim lrow As Long
Dim ws As Worksheet, wsPackSpec As Worksheet
Set ws = Activesheet
'Or set ws = Sheets("Sheet1") - better
'Open the nightly pack spec file, cut and insert the year row into column D
Set PackSpec = Workbooks.Open("S:\Accounting\Apps\Packspec\CIDExport\Archive\" &
Year(Date) & "\" & Month(Date) & "\" & Day(Date) - 1 & "\*.csv")
Set wsPackSpec = PackSpec.Sheets(1)
wsPackSpec.Columns(1).Value = wsPackSpec.Columns(4).Value
wsPackSpec.Columns(1).EntireColumn.Delete
'Open Fullbook master and insert columns after N then VLookup between Pack Spec and Fullbook
'Apply same principle as above here
Set FullBook = Workbooks.Open("S:\Corporate\Groups\Comosoft\Downloads\FullBook\fullbook_Master.csv")
Columns("N:U").Select
Selection.Insert Shift:=xlToRight
Range("N2").Select
'Actvate Fullbook and enter Vlookup for dates
Windows("fullbook_Master.csv").Activate
Set ws = ActiveSheet 'Set like this, but you should designate the correct worksheet in the fullbook part above
lrow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
With ws
.Cells(2, 14).FormulaR1C1 = "=VLOOKUP(RC[-1],'[15.50.1.CID.csv]15.50.1.CID'!C[-13]:C[-11],3,0)"
.Cells(2, 14).AutoFill Destination:=.Range(.Cells(2, 14), .Cells(lrow, 14))
End With
End Sub
Something like this, couldn't test in detail because I'm missing the overview of how the books are set up.
Related
I am trying to copy data from the 2nd to last worksheet and paste it onto the last worksheet but I don't know how to get the worksheet name of the 2nd to last sheet:
Public Sub CNPPrevOOS()
' Previous day out of stock items
Worksheets(**ThisWorkbook.Worksheets(ThisWorkbook.Sheets.Count - 1)**).Select
c = Worksheets(**ThisWorkbook.Worksheets(ThisWorkbook.Sheets.Count - 1)**).Cells(Rows.Count, 1).End(xlUp).Row
' Filters the data where column 2 = x
ActiveSheet.Range(Cells(1, 1), Cells(c, 2)).AutoFilter field:=2, Criteria1:="x", Operator:=xlFilterValues
' Selects only the filtered cells and copy
Range(Cells(2, 1), Cells(c, 1)).SpecialCells(xlCellTypeVisible).Select
Selection.Copy
ThisWorkbook.Worksheets(ThisWorkbook.Sheets.Count).Select
ActiveSheet.Paste Destination:=Cells(Cells(Rows.Count, 1).End(xlUp).Row + 1, 1)
End Sub
To get the name of the 2nd to last sheet you can use:
Debug.Print Sheets(Sheets.Count - 1).Name
Implementing this in your code (without using Select) looks something like this:
Sub Shelter_In_Place()
Dim ws1 As Worksheet, ws2 As Worksheet
Dim lr1 As Long, lr2 As Long
Set ws1 = ThisWorkbook.Sheets(Sheets.Count) 'Last Worksheet
Set ws2 = ThisWorkbook.Sheets(Sheets.Count - 1) 'Second to Last Worksheet
lr1 = ws1.Range("A" & ws1.Rows.Count).End(xlUp).Offset(1).Row
lr2 = ws2.Range("A" & ws2.Rows.Count).End(xlUp).Row
ws2.Range("A1:B" & lr2).AutoFilter Field:=2, Criteria1:="x", Operator:=xlFilterValues
ws2.Range("A2:B" & lr2).SpecialCells(xlCellTypeVisible).Copy
ws1.Range("A" & lr1).PasteSpecial xlPasteValues
End Sub
i'm trying to make some changes in excel file using VBA, the file contains many sheets
the code should make changes for 1st sheet then go to the next and next,
but after makes the changes in 1st sheet and go to 2nd it shows:
Error no 1004 "Object error".
Here the code:
Sub AddRefNo()
'This code adds Reference Number to All BOQ sheets based on Worksheet Name
'select the first sheet
Worksheets(4).Select
' Work in One Sheet
Do While ActiveSheet.Index < Worksheets.Count
'add new Column
'the error happens here
Columns("A:A").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("A1").Select
ActiveCell.FormulaR1C1 = "Ref. No"
Range("A2").Select
'Find Sheet Name
MySheet = ActiveSheet.Name
'creat numbering system
Dim Noe As String
Noe = 0
' Find the last row
Dim LastRow As Integer
LastRow = Range("E" & Rows.Count).End(xlUp).Row
Range("E2").Select
'repeat steps to the last row
Do While ActiveCell.Row < LastRow
'checking if the cell is not blank
Do While ActiveCell.Value <> ""
ActiveCell.Offset(0, -4).Select
Noe = Noe + 1
ActiveCell.Value = MySheet & " - " & Noe
ActiveCell.Offset(0, 4).Select
ActiveCell.Offset(1, 0).Select
Loop
ActiveCell.Offset(1, 0).Select
Loop
Noe = 0
Range("A1").Select
ActiveSheet.Next.Select
Loop
Worksheets(1).Select
End Sub
Here is a way to reliable loop through your worksheet index numbers:
Sub AddRefNo()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet
Dim x As Long
For x = 4 To wb.Worksheets.Count - 1
Set ws = wb.Worksheets(x)
'Your code to work with ws as a parent
Next x
End Sub
This should do the trick if you want to loop from sheet 4:
Option Explicit
Sub AddRefNo()
'Declare a worksheet variable
Dim ws As Worksheet
'Loop every sheet in the workbook
For Each ws In ThisWorkbook.Worksheets
If ws.Index < 4 Or ws.Index = ThisWorkbook.Worksheets.Count Then GoTo nextWorksheet
'Reference always the sheet
With ws
'Calculate last row
Dim LastRow As Long
LastRow = .Cells(.Rows.Count, "E").End(xlUp).Row
'Insert a column
.Range("A:A").Insert
.Range("A1") = "Ref. No"
'Put the name sheet + reference starting from 1
With .Range("A2:A" & LastRow)
.FormulaR1C1 = "=" & Chr(34) & ws.Name & Chr(34) & "&ROW(RC)-1"
.Value = .Value
End With
End With
nextWorksheet:
Next ws
End Sub
This isn't complex by far but I'm only a novice at excel macros. I've found online and edited this for my use but I know it's so long. The single ranges all refer to the same cell which is just the value of =today(). I know that can be integrated, I just don't know how. The rest copies a row and pastes it over at the bottom of specific rows, one for each employee. I'm sure there are even better ways to do this since the rows being copied are only there for this code and isn't the main data source. But one step at a time. Lol
Sub LastRowDtDataTEST()
Dim wb As Workbook
Dim ws As Worksheet
Dim LastRow As Long
Set wb = ActiveWorkbook
Set ws = ThisWorkbook.Sheets("Buyer Trend Metrics")
ws.Select
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "J").End(xlUp).Row
Range("J" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B61:H61").Copy
LastRow = Cells(Rows.Count, "K").End(xlUp).Row ' get last row with data in column "K"
Range("K" & LastRow + 1).PasteSpecial Paste:=xlPasteValues ' paste values
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "S").End(xlUp).Row
Range("S" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B62:H62").Copy
LastRow = Cells(Rows.Count, "T").End(xlUp).Row
Range("T" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "AB").End(xlUp).Row
Range("AB" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B63:H63").Copy
LastRow = Cells(Rows.Count, "AC").End(xlUp).Row
Range("AC" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "AK").End(xlUp).Row
Range("AK" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B64:H64").Copy
LastRow = Cells(Rows.Count, "AL").End(xlUp).Row
Range("AL" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "AT").End(xlUp).Row
Range("AT" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B65:H65").Copy
LastRow = Cells(Rows.Count, "AU").End(xlUp).Row
Range("AU" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "BC").End(xlUp).Row
Range("BC" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B66:H66").Copy
LastRow = Cells(Rows.Count, "BD").End(xlUp).Row
Range("BD" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "BL").End(xlUp).Row
Range("BL" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B67:H67").Copy
LastRow = Cells(Rows.Count, "BM").End(xlUp).Row
Range("BM" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "BU").End(xlUp).Row
Range("BU" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B68:H68").Copy
LastRow = Cells(Rows.Count, "BV").End(xlUp).Row
Range("BV" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "CD").End(xlUp).Row
Range("CD" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B69:H69").Copy
LastRow = Cells(Rows.Count, "CE").End(xlUp).Row
Range("CE" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B58").Copy ' Copies the value of =Today() from a cell. Would be easier to just integrate today's date instead.
LastRow = Cells(Rows.Count, "CM").End(xlUp).Row
Range("CM" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
Range("B70:H70").Copy
LastRow = Cells(Rows.Count, "CN").End(xlUp).Row
Range("CN" & LastRow + 1).PasteSpecial Paste:=xlPasteValues
End Sub
Here are some things for you to look at...
ALWAYS use Option Explicit. See here for an explanation.
When you're performing an action such as copying data, it's extremely helpful to be very clear in defining the source and destination of the data. This includes defining which Workbook the data is going to. You'll thank me later for building this habit now.
As an example:
Dim srcWB As Workbook
Dim dstWB As Workbook
Set srcWB = ThisWorkbook
Set dstWB = ThisWorkbook
Dim srcWS As Worksheet
Dim dstWS As Worksheet
Set srcWS = srcWB.Sheets("Sheet1") ' <--- you didn't specify this in your code
Set dstWS = dstWB.Sheets("Buyer Trend Metrics")
When you're performing the same (or very similar) actions over and over, it's the perfect situation to create a separate function that will perform the action for you. When you break out this section of code, it's called "functional isolation". This means that if you have a problem to fix, you only have to fix it in one place instead of finding all the different spots in your code that do the same thing.
In your case, you are performing a copy from one range of cells to another range of cells. So breaking that out into a separate routine looks like this:
Private Sub CopyMyData(ByRef fromData As Range, ByRef toData As Range)
Dim lastrow As Long
With toData.Parent
lastrow = .Cells(.Rows.Count, toData.Column).End(xlUp).Row
End With
fromData.Copy
toData.Cells(lastrow).PasteSpecial Paste:=xlPasteValues
End Sub
Notice here how I'm using variable names that describe what the code does (fromData and toData). This makes it clear what's happening.
Put it all together and your code will look something like this:
Option Explicit
Public Sub StartCopying()
Dim srcWB As Workbook
Dim dstWB As Workbook
Set srcWB = ThisWorkbook
Set dstWB = ThisWorkbook
Dim srcWS As Worksheet
Dim dstWS As Worksheet
Set srcWS = srcWB.Sheets("Sheet1") ' <--- you didn't specify this in your code
Set dstWS = dstWB.Sheets("Buyer Trend Metrics")
CopyMyData fromData:=srcWS.Range("B58"), toData:=dstWS.Range("J:J")
CopyMyData fromData:=srcWS.Range("B61:H61"), toData:=dstWS.Range("K:K")
CopyMyData fromData:=srcWS.Range("B58"), toData:=dstWS.Range("S:S")
CopyMyData fromData:=srcWS.Range("B61:H62"), toData:=dstWS.Range("T:T")
End Sub
Private Sub CopyMyData(ByRef fromData As Range, ByRef toData As Range)
Dim lastrow As Long
With toData.Parent
lastrow = .Cells(.Rows.Count, toData.Column).End(xlUp).Row
End With
fromData.Copy
toData.Cells(lastrow).PasteSpecial Paste:=xlPasteValues
End Sub
There's a pattern to how you're copying/pasting.
Copying every row, pasting to every 9th column after column 10.
I've added two lines for finding the last row - either find it once and paste everything to that row, of find it before you copy each time. Uncomment whichever you prefer.
This will copy B61:H61 to K:P on the last row (with date in J), then B62:H62 to T:Z with the date in R.
The date will also appear correctly formatted rather than as a number.
Public Sub WhateverYouWantToCallIt()
Dim x As Long, y As Long
Dim lLastRow As Long
With ThisWorkbook.Worksheets("Buyer Trend Metrics")
'This will set the same last row for each copy.
lLastRow = .Cells(.Rows.Count, 10).End(xlUp).Row + 1
y = 10
For x = 61 To 70
'This will set the last row on each set of data.
'lLastRow = .Cells(.Rows.Count, y).End(xlUp).Row + 1
.Cells(lLastRow, y) = Date
.Range(.Cells(lLastRow, y + 1), .Cells(lLastRow, y + 7)) = _
.Range(.Cells(x, 2), .Cells(x, 8)).Value
'-OR-
'.Range(.Cells(x, 2), .Cells(x, 8)).Copy
'.Cells(lLastRow, y + 1).PasteSpecial Paste:=xlPasteValues
y = y + 9
Next x
End With
End Sub
Do not double space every single line. You should use these as strategic separators, not the standard. This isn't MLA.
Use a worksheet variable to quickly refer to your sheets (ws refers to the sheet that has the cells to be copied and ds (destination sheet) refers to the sheet where the cells are to be pasted
You can use a value transfer instead of a copy/paste which does not require multiple lines as well
In general, when shortening code, you want to look for repetitiveness. I can see that you are constantly copying the value from Range("B58") so you can also shorten this. You have comments saying you want the value to just be today so you can just do something like
ds.Range("?") = Today Repeat as needed
Option Explicit
Sub LastRowDtData()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim ds As Worksheet: Set ds = ThisWorkbook.Sheets("Buyer Trend Metrics")
Dim LR As Long
LR = ds.Range("J" & ds.Rows.Count).End(xlUp).Offset(1)
ds.Range("J" & LR).Value = ws.Range("B58").Value
LR = ds.Range("K" & ds.Rows.Count).End(xlUp).Offset(1)
ds.Range("K" & LR).Resize(1, 7).Value = ws.Range("B61:H61")
LR = ds.Range("S" & ds.Rows.Count).End(xlUp).Offset(1)
ds.Range("S" & LR).Value = ws.Range("B58").Value
'Repeat for below ranges
'------------------
Range("B62:H62").Copy
Range("B58").Copy
Range("B63:H63").Copy
Range("B58").Copy
Range("B64:H64").Copy
Range("B58").Copy
Range("B65:H65").Copy
Range("B58").Copy
Range("B66:H66").Copy
Range("B58").Copy
Range("B67:H67").Copy
Range("B58").Copy
Range("B68:H68").Copy
Range("B58").Copy
Range("B69:H69").Copy
Range("B58").Copy
Range("B70:H70").Copy
End Sub
I am trying to paste values from a bunch of tables into one long list. I have the tables spread across different sheets and the number of rows changes, but the columns do not. Then I am also trying to paste a string value that tells what sheet it came from, but having trouble with the active cell part of the code.
When I first tried it, it did not compile, hence why I came here, to figure out why it did not compile. Going back and forth with urdearboy, below, I was able to get the correct code working here.
I have the following:
sub copypaste()
Dim ws1 as worksheet
dim ws2 as worksheet
dim mas as worksheet
Set ws1 =ThisWorkbook.Sheets("Sheet1")
Set ws2=ThisWorkbook.Sheets("Sheet2")
Set mas=ThisWorkbook.Sheets("Master") 'where I create my list
For Each ws In Worksheets
If ws.Name <> mas.Name Then
LRow = mas.Range("A" & mas.Rows.Count).End(xlUp).Offset(1, 0).Row
wsLRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
ws.Range("A2:A" & wsLRow - 1).Copy
mas.Range("A" & LRow).PasteSpecial Paste:=xlPasteValues
ws.Range("B2:B" & wsLRow - 1).Copy
mas.Range("B" & LRow).PasteSpecial Paste:=xlPasteValues
mas.Range(mas.Cells(LRow, 4), mas.Cells(wsLRow + LRow - 2, 4)) = ws.Name 'I need my sheet value in the fourth column, not the third, but simply change the col coordinate in the Cells equation above
End If
Next ws
'In order to figure out the sheet name, I used the following:
Dim rng As Range
Set rng = mas.Range("D2", Range("D2").End(xlDown))
For Each Cell In rng
If Cell.Value = "Sheet 1" Then
Cell.Value = "S1"
ElseIf Cell.Value = "Sheet 2" Then
Cell.Value = "S2"
End If
Next Cell
end sub
This will loop through all sheets, with the exception of Master, and import the values on Column A to Master accompanied by the origin of the data (sheet name).
Option Explicit for good measure.
Option Explicit
Sub copypaste()
Dim mas As Worksheet: Set mas = ThisWorkbook.Sheets("Master")
Dim ws As Worksheet, LRow As Long, wsLRow As Long
Application.ScreenUpdating = False
For Each ws In Worksheets
If ws.Name <> mas.Name Then
LRow = mas.Range("A" & mas.Rows.Count).End(xlUp).Offset(1).Row
wsLRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
ws.Range("A2:A" & wsLRow).Copy mas.Range("A" & LRow)
mas.Range(mas.Cells(LRow, 2), mas.Cells(wsLRow + LRow - 2, 2)) = ws.Name
End If
Next ws
Application.ScreenUpdating = True
End Sub
To paste values change
ws.Range("A2:A" & wsLRow).Copy mas.Range("A" & LRow)
to this
ws.Range("A2:A" & wsLRow).Copy
mas.Range("A" & LRow).PasteSpecial xlPasteValues
I'm trying to copy data from columns AJ through AQ from one workbook and paste the values in a new workbook. The number of rows is variable (dependent on the user). I've tried implementing the following code, but it only pastes the first row into the new workbook:
Dim i, j, LastRow, LastRow2
Set OldBook = ActiveWorkbook
Set NewBook = Workbooks.Add(xlWBATWorksheet)
With NewBook
.ActiveSheet.Name = "GMD"
End With
OldBook.Activate
Sheets("Entry Sheet").Select
LastRow = ActiveSheet.Range("AJ" & Rows.Count).End(xlUp).Row ''Finds the last row of the column with text
LastRow2 = ActiveSheet.Range("AQ" & Rows.Count).End(xlUp).Row ''Finds the last row of the column with text
For i = 1 To LastRow ''Sets the range of rows to be copied including header
Range(Cells(i, 36), Cells(i, 43)).Select ''Selects relevant columns
Selection.Copy
NewBook.Activate
Range("A1").Select
Selection.PasteSpecial Paste:=xlPasteValues
OldBook.Activate
Sheets("Entry Sheet").Select
Next i
For j = 1 To LastRow ''Sets the range of Rows to be copied including header
Range(Cells(j, 43), Cells(j, 44)).Select ''Selects relevant columns
Selection.Copy
NewBook.Activate
Range("H1").Select
ActiveSheet.Paste
OldBook.Activate
Sheets("Entry Sheet").Select
Next j
Any observations on what I'm doing wrong?
The problem is that in you paste section you are only calling the first cell and it is in the loop so each time the loop will paste in cell A1.
Also if all you want is values, it is best to skip the clipboard and assign the values directly. With this you can avoid the loop all together.
Thirdly avoid using the select.
Edit: Removed loop and added the wrap text for the line breaks.
Dim i, LastRow
Dim ws As Worksheet
Set oldbook = ActiveWorkbook
Set ws = oldbook.Sheets("Entry Sheet")
Set newbook = Workbooks.Add(xlWBATWorksheet)
With newbook
.ActiveSheet.Name = "GMD"
End With
With ws
LastRow = .Range("AJ" & .Rows.Count).End(xlUp).Row ''Finds the last row of the column with text
newbook.Sheets("GMD").Range(newbook.Sheets("GMD").Cells(1, 1), newbook.Sheets("GMD").Cells(LastRow, 7)).Value = .Range(.Cells(1, 36), .Cells(LastRow, 43)).Value
End With
newbook.Sheets("GMD").Range("H:I").WrapText = True