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
Related
My Problem seems simple but i'm just not able to solve it alone. My VBA Code copies Data, based on a Filter and past it to another Workbook, starting in Row 1. What i want to change now is, that the Code checks the Number in Column 43 (AQ) from every Row he copies and paste the Row into the Row that matches that Number. For Example: If the Number 7 stands in AQ than the Row should be pasted in row 7. If the Number 3 stands there, it should be pasted into Row 3. In between some Numbers are not included so it can be, that some Rows in between are staying empty.
My intially Code to Copy/Paste data, that worked, was this one.
Sub SG7Stundenplan()
SG7Stundenplan
Sheets("Gruppenplanung").Select
Columns.EntireColumn.Hidden = False
Range("A2").Select
If ActiveSheet.FilterMode Then ActiveSheet.ShowAllData
ActiveSheet.Range("A2").AutoFilter Field:=19, Criteria1:="SG 7", Operator:=xlAnd
Rows("3:100").Select
Selection.Copy
Workbooks.Open "R:\BINplus\Langenthal\Stammgruppen\Stammgruppe 7\Stammgruppe 7_Unterrichtspläne Test.xlsm"
Worksheets("Stammdaten").Range("A1").PasteSpecial Paste:=xlPasteValues
Workbooks("Stammgruppe 7_Unterrichtspläne Test.xlsm").Close SaveChanges:=True
End Sub
I allready tried to create something new but i failed till now. Im pretty sure you need to copy the Rows singulary to put that trick off.
Sub SG7Stundenplan()
Dim Zelle As Range
Workbooks.Open "R:\BINplus\Langenthal\Stammgruppen\Stammgruppe 7\Stammgruppe 7_Unterrichtspläne Test.xlsm"
For Each Zelle In ThisWorkbook.Sheets("Gruppenplanung").UsedRange.Columns(19)
If Zelle.Text = "SG 7" Then
Zelle.EntireRow.Copy
Workbooks("Stammgruppe 7_Unterrichtspläne Test.xlsm").Worksheets("Stammdaten").Cells(Zelle.Offset(43 - Zelle.Column).Value, 1).PasteSpecial xlPasteValues
End If
Next
Workbooks("Stammgruppe 8_Unterrichtspläne Test.xlsm").Close True
End Sub
Thanks a lot for checking this Post and think about it. Your a great Community that allready helped me a lot.
Sincerely,
David from Switzerland
here is my best attempt at your problem.
My Input Sheet:
My Code:
Sub copyData()
Dim src As Worksheet: Set src = ThisWorkbook.Worksheets("Sheet1")
Dim wb As Workbook: Set wb = Workbooks.Open("c:\Desktop\Destination.xlsx")
Dim dest As Worksheet: Set dest = wb.Sheets("Sheet1")
Dim lastRow As Integer: lastRow = src.Cells(src.Rows.Count, 1).End(xlUp).Row
Dim lastCol As Integer: lastCol = src.Cells(1, src.Columns.Count).End(xlToLeft).Column
Dim r As Integer, sendRow As Integer
For r = 2 To lastRow
sendRow = src.Cells(r, 1).Value
src.Range(src.Cells(r, 1), src.Cells(r, lastCol)).Copy Destination:=dest.Range(dest.Cells(sendRow, 1), dest.Cells(sendRow, 1))
Next r
End Sub
My Output:
Good Luck!
I am trying to loop through all rows (there is 1000's of rows) in column 'AQ' and if value = "Salary Sacrifice" then I want to display "SALSC" in column 'AP' same row. Here is my code I have so far:
Dim payCodeDescription As String
Dim paycodevalue As String
payCodeDescription = Range("AQ52").Value
If payCodeDescription = "Salary Sacrifice" Then paycodevalue = "SALSC"
ElseIf payCodeDescription = "GrossPay-Overpaid" Then paycodevalue = "OVERP"
End If
Range("AP52").Value = paycodevalue
Is there any way I could turn this into a loop instead of hard coding?
I would use this if formuala...
=IF(AQ52="Salary Sacrifice","SALSC",IF(AQ52="GrossPay-Overpaid","OVERP",""))
but this replaces the values if the condition is false and I need it to do nothing if the value is false.
Any help would be greatly appreciated.
If you are still looking to use VBA, something like the code below will help:
Sub LoopThroughRows()
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sheet1")
'declare and set the worksheet you are working with, amend as required
LastRow = ws.Cells(ws.Rows.Count, "AQ").End(xlUp).Row
'get the last row with data on Column AQ
For i = 2 To LastRow
'loop from row 2 to the Last row
If ws.Cells(i, "AQ").Value = "Salary Sacrifice" Then ws.Cells(i, "AP").Value = "SALSC"
If ws.Cells(i, "AQ").Value = "GrossPay-Overpaid" Then ws.Cells(i, "AP").Value = "OVERP"
'process your conditional statements
Next i
'next row
End Sub
The faster method as mentioned in the comments would be Filtering the data instead of looping through individual rows, the code below is an example of that:
Sub FilterRows()
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sheet4")
'declare and set the worksheet you are working with, amend as required
ws.Cells.AutoFilter
If ws.FilterMode = True Then ws.AutoFilter.ShowAllData
'apply Autofilter and make sure we show all data
LastRow = ws.Cells(ws.Rows.Count, "AQ").End(xlUp).Row
'get the last row with data on Column AQ
ws.Range("$A$1:$AQ$" & LastRow).AutoFilter Field:=43, Criteria1:="Salary Sacrifice"
'filter by Criteria on Column 43, AQ
ws.Range("AP2:AP" & LastRow).SpecialCells(xlCellTypeVisible).Value = "SALSC"
'fill visible rows in Column AP with the desired text
ws.Range("$A$1:$AQ$" & LastRow).AutoFilter Field:=43, Criteria1:="GrossPay-Overpaid"
ws.Range("AP2:AP" & LastRow).SpecialCells(xlCellTypeVisible).Value = "OVERP"
If ws.FilterMode = True Then ws.AutoFilter.ShowAllData
'clear the Filter to show all data again.
End Sub
I have and excel workbook with multiple sheets and I need a range from each one to be copied into one "Main" sheet (one under another) if a condition is met.
Each sheet is different and the number of rows and cells may vary.
In all of the sheets (except the main sheet which is blank) cell B1 is a check cell that contains "yes" or is blank.
If cell B1 ="yes" the macro must migrate the range (from row 2 to the lat filled in row) into the main sheet.
The selected ranges must be copied one under another in the main sheet (so that it's like a list)
I am still a beginner in VBA and if anyone could help me a little with the code I would very much appreciate it :).
I tried to build in the code using "For Each - Next" but perhaps it would be better to make it with a Loop cicle or something else.
Sub Migrate_Sheets()
Dim wksh As Worksheet, DB_range As Range, end_row As Long, con_cell As Variant
con_cell = Range("B1")
'end_row = Range("1048576" & Rows.Count).End(xlUp).Rows
For Each wksh In Worksheets
If con_cell = "Yes" Then
Set DB_range = Range("2" & Rows.Count).End(xlDown).Rows
DB_range.Copy
wksh("Main").Activate
'row_end = Range("2" & Rows.Count).End(xlUp).Rows
Range("A1").End(xlDown).Offset(1, 0).Paste
End If
Next wksh
End Sub
There are quite a few issues here - I suggest you do some reading on VBA basics - syntax, objects, methods etc.
I've assumed you are only copying column B.
Sub Migrate_Sheets()
Dim wksh As Worksheet, DB_range As Range
For Each wksh In Worksheets
If wksh.Name <> "Main" Then 'want to exclude this sheet from the check
If wksh.Range("B1").Value = "Yes" Then 'refer to the worksheet in the loop
Set DB_range = wksh.Range("B2", wksh.Range("B" & Rows.Count).End(xlUp)) 'you need Set when assigning object variables
DB_range.Copy Worksheets("Main").Range("A" & Rows.Count).End(xlUp).Offset(1, 0) 'better to work up from the bottom and then go down 1
End If
End If
Next wksh
End Sub
See if this helps, though you might need to make some minor changes to match your data sets..
Sub Migrate_Sheets()
Dim wksh As Worksheet, mainWS As Worksheet
Dim DB_range As Range, con_cell As String
Dim lRow As Long, lCol As Long, lRowMain As Long
Set mainWS = ThisWorkbook.Worksheets("Main")
For Each wksh In Worksheets
con_cell = wksh.Range("B1").Value 'You want to use this variable within the loop
If wksh.Name <> "Main" And con_cell = "Yes" Then
lRowMain = lastRC(mainWS, "row", 1) + 1 'Add 1 to the last value to get first empty row
lRow = lastRC(wksh, "row", 1) 'Get the last row at column 1 - adjust to a different column if no values in column 1
lCol = lastRC(wksh, "col", 2) 'Get the last column at row 2 - adjust to a different row if no values in row 2
With mainWS
.Range(.Cells(lRowMain, 1), .Cells(lRowMain + lRow - 1, lCol)).Value = wksh.Range(wksh.Cells(2, 1), wksh.Cells(lRow, lCol)).Value
End With
End If
Next wksh
End Sub
Function lastRC(sht As Worksheet, RC As String, Optional RCpos As Long = 1) As Long
If RC = "row" Then
lastRC = sht.Cells(sht.Rows.Count, RCpos).End(xlUp).row
ElseIf RC = "col" Then
lastRC = sht.Cells(RCpos, sht.Columns.Count).End(xlToLeft).Column
Else
lastRC = 0
End If
End Function
So I have a problem that this is generating random results with the Qty.
I am trying to make each qty (in their qty's) a new line on a new spreadsheet.
It creates the new sheet, and references the old sheet...
the code copies and pastes the lines...
It just doesn't loop the do while in the correct amount of times. I have tried different operands (>= 0) and altering the variable values to make this work.
It does not seem to be patternized as to why it is happening. Sometimes it does it in the correct amount of loop cycles, others it does not. This occurs on multiple values. Any help is greatly appreciated.
Sub copyPasta()
'
' copyPasta Macro
' This will take the qty, if greater than one in Column C and copy the row
'to a new sheet the amount of time the qty.
'
'
'Set Variable Types
Dim lineItemQty As Integer
Dim newLineItemQty As Integer
Dim LastRow As Integer
Dim strSheetName As String
Dim newSheetName As String
Dim i As Integer
Application.DisplayAlerts = False
'name a variable after the existing active sheet
strSheetName = ActiveSheet.Name
'add a sheet in addition to the current
Sheets.Add After:=ActiveSheet
'set a variable used in loops to the sheet being copied to
newSheetName = ActiveSheet.Name
'Return to first sheet
Sheets(strSheetName).Activate
' Set For Loop to max row
LastRow = Sheets(strSheetName).Range("C:C").Find("*", searchdirection:=xlPrevious).Row
'for loop to run through all rows
For i = 3 To LastRow Step 1
'initializing variable to Qty value in table
lineItemQty = Range("C" & i).Value
'initializing variable within in line of for looping
newLineItemQty = lineItemQty
'do while loop to keep copying/pasting while there are still qty's
Do While newLineItemQty > 0
'do while looped copy and paste
'copy the active row
Sheets(strSheetName).Activate
Rows(i).Select
Selection.Copy
'paste active row into new sheet
Sheets(newSheetName).Select
Rows("3:3").Select
Selection.Insert Shift:=xlDown
newLineItemQty = newLineItemQty - 1
Loop
Next i
Application.DisplayAlerts = True
End Sub
You can consider using (or taking parts from) the below alternative. A couple of note worthy notes are
You should avoid using .Select and .Activate. See here for details
Life is easier when you declare short variables. Here we just have ws for worksheet and ns for newsheet. You then need to actively state what sheet you are refferring to in your code (instead of using .Select or .Activate to do so by prefixing all objects with the appropriate worksheet variable)
You do not need to add Step 1 in your loop. This is the default - you only need to add this when you are deviating from the default!
There are a few ways to add sheets. Nothing wrong with the way you did - here is just an alternative (yay learning) that happens to be my preferred method.
To copy n many times, just create a nested loop and for 1 to n. Notice we never really use the variable n inside the loop which means the exact same operation will execute, we just want it to execute n times.
Sub OliveGarden()
Dim ws As Worksheet: Set ws = ThisWorkbook.ActiveSheet
Dim ns As Worksheet: Set ns = ThisWorkbook.Sheets.Add(After:=Sheets(ThisWorkbook.Sheets.Count))
ns.Name = ws.Name & " New"
Dim i As Long, c As Long
'Application.ScreenUpdating = False
For i = 3 To ws.Range("C" & ws.Rows.Count).End(xlUp).Row
If ws.Range("C" & i) > 0 Then
For c = 1 To ws.Range("C" & i)
LRow = ns.Range("A" & ns.Rows.Count).End(xlUp).Offset(1).Row
ws.Range("C" & i).EntireRow.Copy
ns.Range("A" & LRow).PasteSpecial xlPasteValues
Next c
End If
Next i
'Application.ScreenUpdating = True
End Sub
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?