Is there a macro or a way to conditionally copy rows from one worksheet to another in Excel 2003?
I'm pulling a list of data from SharePoint via a web query into a blank worksheet in Excel, and then I want to copy the rows for a particular month to a particular worksheet (for example, all July data from a SharePoint worksheet to the Jul worksheet, all June data from a SharePoint worksheet to Jun worksheet, etc.).
Sample data
Date - Project - ID - Engineer
8/2/08 - XYZ - T0908-5555 - JS
9/4/08 - ABC - T0908-6666 - DF
9/5/08 - ZZZ - T0908-7777 - TS
It's not a one-off exercise. I'm trying to put together a dashboard that my boss can pull the latest data from SharePoint and see the monthly results, so it needs to be able to do it all the time and organize it cleanly.
This works: The way it's set up I called it from the immediate pane, but you can easily create a sub() that will call MoveData once for each month, then just invoke the sub.
You may want to add logic to sort your monthly data after it's all been copied
Public Sub MoveData(MonthNumber As Integer, SheetName As String)
Dim sharePoint As Worksheet
Dim Month As Worksheet
Dim spRange As Range
Dim cell As Range
Set sharePoint = Sheets("Sharepoint")
Set Month = Sheets(SheetName)
Set spRange = sharePoint.Range("A2")
Set spRange = sharePoint.Range("A2:" & spRange.End(xlDown).Address)
For Each cell In spRange
If Format(cell.Value, "MM") = MonthNumber Then
copyRowTo sharePoint.Range(cell.Row & ":" & cell.Row), Month
End If
Next cell
End Sub
Sub copyRowTo(rng As Range, ws As Worksheet)
Dim newRange As Range
Set newRange = ws.Range("A1")
If newRange.Offset(1).Value <> "" Then
Set newRange = newRange.End(xlDown).Offset(1)
Else
Set newRange = newRange.Offset(1)
End If
rng.Copy
newRange.PasteSpecial (xlPasteAll)
End Sub
Here's another solution that uses some of VBA's built in date functions and stores all the date data in an array for comparison, which may give better performance if you get a lot of data:
Public Sub MoveData(MonthNum As Integer, FromSheet As Worksheet, ToSheet As Worksheet)
Const DateCol = "A" 'column where dates are store
Const DestCol = "A" 'destination column where dates are stored. We use this column to find the last populated row in ToSheet
Const FirstRow = 2 'first row where date data is stored
'Copy range of values to Dates array
Dates = FromSheet.Range(DateCol & CStr(FirstRow) & ":" & DateCol & CStr(FromSheet.Range(DateCol & CStr(FromSheet.Rows.Count)).End(xlUp).Row)).Value
Dim i As Integer
For i = LBound(Dates) To UBound(Dates)
If IsDate(Dates(i, 1)) Then
If Month(CDate(Dates(i, 1))) = MonthNum Then
Dim CurrRow As Long
'get the current row number in the worksheet
CurrRow = FirstRow + i - 1
Dim DestRow As Long
'get the destination row
DestRow = ToSheet.Range(DestCol & CStr(ToSheet.Rows.Count)).End(xlUp).Row + 1
'copy row CurrRow in FromSheet to row DestRow in ToSheet
FromSheet.Range(CStr(CurrRow) & ":" & CStr(CurrRow)).Copy ToSheet.Range(DestCol & CStr(DestRow))
End If
End If
Next i
End Sub
The way I would do this manually is:
Use Data - AutoFilter
Apply a custom filter based on a date range
Copy the filtered data to the relevant month sheet
Repeat for every month
Listed below is code to do this process via VBA.
It has the advantage of handling monthly sections of data rather than individual rows. Which can result in quicker processing for larger sets of data.
Sub SeperateData()
Dim vMonthText As Variant
Dim ExcelLastCell As Range
Dim intMonth As Integer
vMonthText = Array("January", "February", "March", "April", "May", _
"June", "July", "August", "September", "October", "November", "December")
ThisWorkbook.Worksheets("Sharepoint").Select
Range("A1").Select
RowCount = ThisWorkbook.Worksheets("Sharepoint").UsedRange.Rows.Count
'Forces excel to determine the last cell, Usually only done on save
Set ExcelLastCell = ThisWorkbook.Worksheets("Sharepoint"). _
Cells.SpecialCells(xlLastCell)
'Determines the last cell with data in it
Selection.EntireColumn.Insert
Range("A1").FormulaR1C1 = "Month No."
Range("A2").FormulaR1C1 = "=MONTH(RC[1])"
Range("A2").Select
Selection.Copy
Range("A3:A" & ExcelLastCell.Row).Select
ActiveSheet.Paste
Application.CutCopyMode = False
Calculate
'Insert a helper column to determine the month number for the date
For intMonth = 1 To 12
Range("A1").CurrentRegion.Select
Selection.AutoFilter Field:=1, Criteria1:="" & intMonth
Selection.Copy
ThisWorkbook.Worksheets("" & vMonthText(intMonth - 1)).Select
Range("A1").Select
ActiveSheet.Paste
Columns("A:A").Delete Shift:=xlToLeft
Cells.Select
Cells.EntireColumn.AutoFit
Range("A1").Select
ThisWorkbook.Worksheets("Sharepoint").Select
Range("A1").Select
Application.CutCopyMode = False
Next intMonth
'Filter the data to a particular month
'Convert the month number to text
'Copy the filtered data to the month sheet
'Delete the helper column
'Repeat for each month
Selection.AutoFilter
Columns("A:A").Delete Shift:=xlToLeft
'Get rid of the auto-filter and delete the helper column
End Sub
This is partially pseudocode, but you will want something like:
rows = ActiveSheet.UsedRange.Rows
n = 0
while n <= rows
if ActiveSheet.Rows(n).Cells(DateColumnOrdinal).Value > '8/1/08' AND < '8/30/08' then
ActiveSheet.Rows(n).CopyTo(DestinationSheet)
endif
n = n + 1
wend
If this is just a one-off exercise, as an easier alternative, you could apply filters to your source data, and then copy and paste the filtered rows into your new worksheet?
Related
Rather simple question that I seem to be struggling with.
I have 2 columns. column1 has dates in it where each cell is the day after the previous. column 2 occasionally has data in it. i need to apply an auto filter show all dates except the 15th and 26th of the month for column 1 and all blank cells in column2. I can do the column2 filter with the code
ws1.Range(Cells(4, 1), Cells(x, 2)).AutoFilter field:=2, Criteria1:="="
but i cant figure out how to filter column 1.
any help would be appreciated.
Thank you.
i need to apply an auto filter show all dates except the 15th and 26th of the month for column 1
You can achieve what you want using an array of relevant dates.
Logic: Create an array and then use Criteria2 paramenter to filter. For example if you record a macro you will get something like this Criteria2:=Array(2, "1/1/2020", 2, "1/4/2020", 2, "1/6/2020").... First dimension of array is the time period group. 2 is for Days.
Is this what you are trying?
Option Explicit
Sub Sample()
Dim ws As Worksheet
Dim rng As Range
Dim lRow As Long, i As Long
Dim DateArray As Variant
Dim tmpDateString As String: tmpDateString = "2"
'~~> Set your worksheet here
Set ws = Sheet2
With ws
'~~> Remove any autofilter
.AutoFilterMode = False
'~~> Find the last row
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'~~> Check if there is any data
If lRow > 1 Then
'~~> Construct your range
Set rng = .Range("A1:A" & lRow)
'~~> Create a string with relevant dates
For i = 2 To lRow
Select Case Day(.Range("A" & i).Value)
Case 15, 16
Case Else
tmpDateString = tmpDateString & "," & .Range("A" & i).Value & ",2"
End Select
Next i
End If
'~~> Split and store in an array
tmpDateString = Mid(tmpDateString, 1, Len(tmpDateString) - 2)
DateArray = Split(tmpDateString, ",")
'~~> Autofilter using an array
rng.AutoFilter Field:=1, Criteria2:=DateArray, Operator:=xlFilterValues
End With
End Sub
In Action
If i could get it to show only 15th and 26th that would work as well as im filtering to delete unused dates. – matthew wilcox 1 hour ago
Swap the Case code in Select Case. Give it a try ;)
I have a "Data" worksheet that holds loads of data. It has 17 columns A-Q and in the G column is the date that is meant for dd/mm/yyyy. I have a separate worksheet called "NoEntry" and here is where I would like the dates to be entered by the user (Start-date L15 and End-date in L16) and once a button clicked all the data between and including the start and end date will go into another worksheet called "DateData".
The code I have below kind of works. The problem is that for some reason the data transferred over is not correct. Firstly, not all data keeps within the boundaries - some gets copied over with dates that are before the "start date". Another thing is that in the data there are blank records (A-F has data and onwards is blank) and some of them get copied over also - even though they have no date.
I feel like either its not looping correctly through all records or perhaps its a formatting issue. Perhaps is there a way to convert all the date column into a specific format before it does the copying - has to be dd/mm/yyyy. Or could just be something I'm missing?
from testing it seems only one record got through that is before the start date but blank data still gets copied over the date used was 16/09/2019 to 07/10/2019
Any help would be much appreciated,
Thanks :)
Private Sub CommandButton2_Click()
Application.ScreenUpdating = False
Dim wsData As Worksheet, wsDate As Worksheet, wsNoEntry As Worksheet
Dim dSDate As Date, dEDate As Date
Dim lRowStart As Long, lRowEnd As Long
Dim aData() As Variant
Dim i As Long
'set the worksheet objects
Set wsData = ThisWorkbook.Sheets("Data")
Set wsDate = ThisWorkbook.Sheets("DateData")
Set wsNoEntry = ThisWorkbook.Sheets("NoEntry")
'required variables
dSDate = wsNoEntry.Range("L15").Value
dEDate = wsNoEntry.Range("L16").Value
'set the array - you can make this dynamic!
aData = wsData.Range("A1:Z1000").Value
'for loop to find start
For i = 1 To 1000
If aData(i, 7) = dSDate Then
lRowStart = i
Debug.Print "Start row = " & lRowStart
Exit For
End If
Next i
'now loop backwards to find end date
For i = 1000 To 1 Step -1
If aData(i, 7) = dEDate Then
lRowEnd = i
Debug.Print "End row = " & lRowEnd
Exit For
End If
Next i
'now we have start and end dates
'going to use copy/ paste for simplicity
wsData.Range("A" & lRowStart, "Z" & lRowEnd).Copy
'paste in date sheet
wsDate.Range("A1").PasteSpecial Paste:=xlPasteValues
'clear clipboard
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
Input
Output - blacked out due to private information (G5 date shouldn't be there and you can see blanks
I have a excel vba workflow to enter data into a table from a data input sheet (inputwks). This would be as follows:
Press button, adds a new row to table.
Enters time stamp into specific column header name "Date/Time" column. (column M in the code below)
Enters input data from inputwks into specific table header name "data record" column. (shown as column 3 in the code below)
I don't want to use column letters or numbers because I may change the order (e.g. date/time may look better to the user in column A instead of M.).
How do I change the code below so the macro will search for "date/Time" columns instead of going to column M and the same for "data record"?
Thank you for any help given.
Sub UpdateLogWorksheet()
'Dim historyWks As Worksheet
Dim ccarWks As Worksheet
Dim inputWks As Worksheet
Dim nextRow As Long
Dim oCol As Long
'======================Named range setup=========================
Dim myCopy As Range
Dim myTest As Range
Dim lRsp As Long
'=====================worksheet name setup=======================
Set inputWks = Worksheets("Input (Modded)")
Set ccarWks = Worksheets("CCAR - VB Template Ver2.0")
oCol = 3
'===================Copy/paste data commands==================
Set myCopy = inputWks.Range("inputvalue")
With ccarWks
nextRow = .Cells(.Rows.Count, "A").End(xlUp).Offset(1, 0).Row
End With
With ccarWks
With .Cells(nextRow, "M") 'was "A"
.Value = Now
.NumberFormat = "dd/mm/yyyy hh:mm:ss" 'enter date and time stamp in record
End With
myCopy.Copy
.Cells(nextRow, 3).PasteSpecial Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
End With
End Sub
I've had to deal with this in the past too, where you can't be certain that the field with be in the same column because the source table has changed.
If you would always have the same field header (column header) then you can use the code I've used before.
Public Function FindColumn(ws As Worksheet, name As String, Optional headerRow As Integer = 1) As Integer
On Error GoTo FUNC_ERR
Dim sRng As Range: Set sRng = ws.Rows(headerRow).Find(what:=name, _
LookIn:=xlValues, _
lookat:=xlWhole)
If sRng Is Nothing Then
'Handle if not found
Else
FindColumn = sRng.Column
End If
FUNC_EXIT:
Exit Function
FUNC_ERR:
'Handle error
End Function
HeaderRow is optional and assumed to be row 1, but you can also call out a different row if necessary.
Then instead of using the column letter in the .cell() callout, you can use the returned column number.
dim columnNumber as Integer: columnNumber = FindColumn(ccarWks, "Header Name")
With ccarWks
With .Cells(nextRow, columnNumber)
.Value = Now
.NumberFormat = "dd/mm/yyyy hh:mm:ss"
End With
'...more code...
End With
Hope this helps you.
I added this code to ensure it was able to dynamically change the column number it was looking for:
Datetimecol = Application.WorksheetFunction.Match("date/time", CCARWKS.Range("A4:AZ4"), 0)
With .Cells(nextRow, datetimecol)
This now changes the column value automatically and prevents breaking the code.
I am trying to create a single VBA that searches seven different sheets for a particular entry in Column E and then copy the entire row into a 8th Sheet and placing them in order by column A.
I got the point for it to search for one spreadsheet and copying the items over to the other in the exact same row they are located on the spreadsheet
Sub Test()
Dim rw As Long, Cell As Range
For Each Cell In Tues.Range("E:E")
rw = Cell.Row
If Cell.Value = "No" Then
Cell.EntireRow.Copy
Sheets("Completed").Range("A" & rw).PasteSpecial
End If
Next
End Sub
The Spreadsheets I want to search for are:
Mon
Tues
Wed
Thurs
Fri
Sat
Sun
The sheet I want to move it to is called Completed, then I want it to sort by Column A.
Any Ideas?
How about this:
Sub loop_through_WS()
Dim rw As Long, i As Long, lastRow As Long, compLastRow&
Dim cel As Range
Dim mainWS As Worksheet, ws As Worksheet
Dim sheetArray() As Variant
sheetArray() = Array("Mon", "Tues", "Weds", "Thurs", "Fri", "Sat", "Sun")
Set mainWS = Sheets("Completed")
compLastRow = mainWS.Cells(mainWS.Rows.Count, 1).End(xlUp).row
For i = LBound(sheetArray) To UBound(sheetArray)
With Sheets(sheetArray(i))
lastRow = .Cells(.Rows.Count, 5).End(xlUp).row
For Each cel In .Range("E1:E" & lastRow)
rw = cel.row
If cel.Value = "No" Then
cel.EntireRow.copy
mainWS.Range("A" & compLastRow).pasteSpecial
compLastRow = mainWS.Cells(mainWS.Rows.Count, 1).End(xlUp).row + 1
End If
Next
End With
Next i
Application.CutCopyMode = False
End Sub
It basically uses the code you gave, but I added the worksheet loop (it'll loop through each of the day worksheets) and paste back onto the "Completed" WS.
See if you can work out how I looped through the worksheets - I use this type of thing often so it'd be good to learn if you are doing much of this. It also allows you to add another sheet (say "Weekend") to your workbook and all you have to do is add "Weekend" after "Sun" in the Array. That's the only place you'll need to add it.
One note is that I changed your for each Cell in Range(E:E) to be from E1 to the last Row in column E - which makes the macro run way faster.
Edit: As mentioned in my comment above, it's generally not recommended to use Cell as a variable name. (Same goes for Column, Row, Range, etc.) because these all mean something specifically to VBA (i.e. Cell([row],[column]). Instead, as you see, I like to use cel or rng or iCell,etc.
Something like this should work for you based on what you've described. It uses a For Each loop to iterate through the sheets and uses the AutoFilter method to find what it's looking for from column E. The code assumes headers are in row 1 on each sheet. I attempted to comment it for clarity.
Sub tgr()
Dim wb As Workbook
Dim ws As Worksheet
Dim wsCompleted As Worksheet
Dim bHeaders As Boolean
Set wb = ActiveWorkbook
Set wsCompleted = wb.Sheets("Completed")
bHeaders = False
'Comment out or delete the following line if you do not want to clear current contents of the Completed sheet
wsCompleted.Range("A2", wsCompleted.Cells(Rows.Count, Columns.Count)).Clear
'Begin loop through your sheets
For Each ws In wb.Sheets
'Only perform operation if sheet is a day of the week
If InStr(1, " Mon Tue Wed Thu Fri Sat Sun ", " " & Left(ws.Name, 3) & " ", vbTextCompare) > 0 Then
'If headers haven't been brought in to wsCompleted yet, copy over headers
If bHeaders = False Then
ws.Rows(1).EntireRow.Copy wsCompleted.Range("A1")
bHeaders = True
End If
'Filter on column E for the word "No" and copy over all rows
With ws.Range("E1", ws.Cells(ws.Rows.Count, "E").End(xlUp))
.AutoFilter 1, "no"
.Offset(1).Resize(.Rows.Count - 1).EntireRow.Copy wsCompleted.Cells(wsCompleted.Rows.Count, "A").End(xlUp).Offset(1)
.AutoFilter
End With
End If
Next ws
'Sort wsCompleted by column A
wsCompleted.Range("A1").CurrentRegion.Sort wsCompleted.Range("A1"), xlAscending, Header:=xlGuess
End Sub
EDIT: Here is the sample workbook that contains the code. When I run the code, it works as intended. Is your workbook data setup drastically different?
https://drive.google.com/file/d/0Bz-nM5djZBWYaFV3WnprRC1GMnM/view?usp=sharing
The answers posted earlier have some great stuff in them, but I think this will get you exactly what you after with no issues and also with great speed. I made some assumptions on how your data is laid out, but commented them. Let me know how it goes.
Sub PasteNos()
Dim wsComp As Worksheet
Dim vSheets() As Variant
Application.ScreenUpdating = False
vSheets() = Array("Mon", "Tues", "Weds", "Thurs", "Fri", "Sat", "Sun")
Set wsComp = Sheets("Completed")
For i = LBound(vSheets) To UBound(vSheets)
With Sheets(vSheets(i))
.AutoFilterMode = False
.Range(.Range("E1"), .Cells(.Rows.Count, 5).End(xlUp)).AutoFiler 1, "No"
'assumes row 1 has headers
.Range(.Range("E2"), .Cells(.Rows.Count, 5).End(xlUp)).SpecialCells(xlCellTypeVisible).EntireRow.Copy
'pastes into next available row
With wsComp
.Range("A" & .Rows.Count).End(xlUp).Offset(1).PasteSpecial xlPasteValues 'assumes copy values over
End With
End With
Next i
'assumes ascending order, headers in row 1, and that data is row-by-row with no blank rows
wsComp.UsedRange.Sort 1, xlAscending, Header:=xlYes
Application.ScreenUpdating = True
End Sub
I import a massive amount of data from SharePoint as a new worksheet (“The Pull”) on an existing book that has four other sections. I am trying to develop a macro that will, when run, a.) automatically filter the data by a field in the Pull; b.) copy/”paste values” of that filtered data into an existing sheet starting at cell A5; c.) reset the filter on the Pull for the next sheet.
So for example, in the Pull (default worksheet name “owssvr”), each row has a date in Column AR showing when the item in that row was created. How do I automatically filter for all items from the previous month in the pull (or alternatively, give the user the option to choose the month), and copy/paste values of the filtered result into a worksheet called “Monthly Report” starting at cell A5 (allowing for the header to not change)? Is this possible?
This is how I would write that:
Option Explicit
Sub MonthFilter()
Dim LR As Long, MyDate As Date, d1 As Date, d2 As Date
MyDate = Application.InputBox("Enter any date in the month you wish to pull", "Enter Date", Date - 30, Type:=2)
If MyDate = 0 Then
Exit Sub
Else
d1 = DateSerial(Year(MyDate), Month(MyDate), 1)
d2 = DateSerial(Year(MyDate), Month(MyDate) + 1, 1) - 1
End If
With Sheets("The Pull")
.AutoFilterMode = False
.Rows(1).AutoFilter
.Rows(1).AutoFilter 44, Criteria1:=">=" & d1, _
Operator:=xlAnd, Criteria2:="<=" & d2
LR = .Cells(.Rows.Count, 44).End(xlUp).Row
If LR > 1 Then .Range("A2:A" & LR).EntireRow.Copy Sheets("Monthly Report").Range("A5")
.AutoFilterMode = False
End With
End Sub
You can use AutoFilter and ShowAllData to filter and unfilter. Here is an example.
Sub CopyLastMonthFromThePull(shtCopyTo As Worksheet)
Dim rngPullTable As Range, iColumnToFilter As Integer, strMonth As String
' this assumes that the pull data is the first Excel Table on ThePull worksheet named owssvr
Set rngPullTable = ThisWorkbook.Worksheets("owssvr").ListObjects(1).Range
rngPullTable.Parent.Activate
' determine the filter details
strMonth = CStr(DateSerial(Year(Date), Month(Date) - 1, Day(Date))) ' one month prior to today
iColumnToFilter = 44 ' Column AR is the 44th column
' filter the table
rngPullTable.AutoFilter Field:=iColumnToFilter, Operator:=xlFilterValues _
, Criteria2:=Array(1, strMonth)
DoEvents
' copy the filtered results. (This also copies the header row.)
rngPullTable.Copy
With shtCopyTo
.Activate
.Range("A5").PasteSpecial xlPasteFormulasAndNumberFormats
.Columns.AutoFit
.Range("A1").Select
End With
Application.CutCopyMode = False
' remove filter
With rngPullTable.Parent
.Activate
.ShowAllData
End With
rngPullTable.Range("A1").Select
' End with the sheet being copied to active
shtCopyTo.Activate
End Sub