Forum Discussion
VBA or Power Query help: Iterate copy/paste from one sheet to another and save each iteration
Hello,
I have 3 sheets within a workbook for which I am trying to establish an "iterative connection". The relevant names are listed below:
- Workbook name: Test_Iterations
- Sheet 1 name: All Inputs
- Sheet 1 Table Name: Inputs
Model | Color | Weight | Volume | Change Group |
59603 | Blue | 17 | 384 | 59603,97196,41444,72306,61772 |
97196 | Blue | 97 | 637 | 59603,97196,41444,72306,61772 |
41444 | Red | 93 | 275 | 59603,97196,41444,72306,61772 |
72306 | Red | 42 | 618 | 59603,97196,41444,72306,61772 |
61772 | Green | 39 | 782 | 59603,97196,41444,72306,61772 |
- Sheet 2 name: Analysis
- Sheet 2 Table Name: Analysis_T
Model | Color | Weight | Volume | Change Group | Parts | Calculation 1 | Calculation 2 | Calculation 3 | Calculation 4 | Calculation 5 | Calculation 6 | Result 1 | Result 2 | Result 3 |
X | X | X | X | X | ||||||||||
- Sheet 3: Summaries
Model | Parts | Result 1 | Result 2 | Result 3 |
My simplified use-case is the following:
Each row in "Inputs" is a set of data that I want to paste into "Analysis_T" in the first row (in the columns that match the same name). It needs to only happen in the first row of "Analysis_T". I have designated the cells that the row data should be copied into with "X".
"Analysis_T" performs calculations that take between 4 and 10 seconds to complete. When they complete, I want all the rows in "Analysis_T" to be copied into sheet "Summaries" for only the columns shown above. (I do not know if calculation time is a factor that needs to be considered). Finally, I want to keep only rows whose value in 'Result 2" is equal to "Yes".
I want this action to be repeated for every row in "Inputs". To summarize, each iteration should do the following:
For i = 1 to i = # of rows in "Inputs"
- Copy row i
- Clear cells in "Analysis_T" (denoted by "X" in this post)
- Paste row i into row 1 of "Analysis_T" (in respective columns)
- Wait for data in columns "Result 1"-"Result 3" to populate (if applicable)
- Copy all rows of "Analysis_T" (only columns shown above) and paste them into sheet "Summaries". (it should add to the existing data, not overwrite)
- Delete all rows whose value in "Result 2" is equal to "No".
End
May someone please help me get started with this task? I have few experience with VBA code and Power Query but understand code (background with Python and Matlab).
I am not sure if "copy/paste" are the actions that need to occur, but they are what is currently used to manually run this process.
You can started with the VBA code to achieve your task.
Here's an example VBA code that you can use as a starting point:
Sub IterateAndCopyPaste() Dim wb As Workbook Dim wsInputs As Worksheet Dim wsAnalysis As Worksheet Dim wsSummaries As Worksheet Dim tblInputs As ListObject Dim tblAnalysis As ListObject Dim tblSummaries As ListObject Dim inputRow As ListRow Dim analysisRow As ListRow Dim lastRow As Long Dim i As Long ' Set references to the workbook and worksheets Set wb = ThisWorkbook Set wsInputs = wb.Worksheets("All Inputs") Set wsAnalysis = wb.Worksheets("Analysis") Set wsSummaries = wb.Worksheets("Summaries") ' Set references to the tables Set tblInputs = wsInputs.ListObjects("Inputs") Set tblAnalysis = wsAnalysis.ListObjects("Analysis_T") Set tblSummaries = wsSummaries.ListObjects("Summaries") ' Loop through each row in the Inputs table For i = 1 To tblInputs.DataBodyRange.Rows.Count ' Get the current input row Set inputRow = tblInputs.ListRows(i) ' Clear the cells in Analysis_T tblAnalysis.DataBodyRange.ClearContents ' Copy the input row to the first row of Analysis_T inputRow.Range.Copy tblAnalysis.DataBodyRange.Rows(1) ' Wait for calculations to complete (if necessary) ' Add code here to wait for the calculations to complete ' Copy all rows from Analysis_T to Summaries lastRow = tblSummaries.DataBodyRange.Rows.Count tblAnalysis.DataBodyRange.Copy Destination:=tblSummaries.DataBodyRange.Offset(lastRow) ' Delete rows from Summaries where Result 2 is "No" DeleteRowsWithNoResult2 wsSummaries, tblSummaries ' Clear the clipboard Application.CutCopyMode = False Next i End Sub Sub DeleteRowsWithNoResult2(ws As Worksheet, tbl As ListObject) Dim result2Column As Range Dim cell As Range ' Set the Result 2 column range Set result2Column = tbl.ListColumns("Result 2").DataBodyRange ' Loop through each cell in the Result 2 column For Each cell In result2Column.Cells ' Check if the value is "No" and delete the entire row If cell.Value = "No" Then cell.EntireRow.Delete End If Next cell End Sub
Please note that this is a basic example, and you may need to modify it based on your specific workbook structure and requirements. You'll also need to add code to wait for the calculations to complete, as indicated in the comments.
To run the code, press Alt+F11 to open the VBA editor in Excel, insert a new module, and paste the code into the module. You can then run the IterateAndCopyPaste macro to perform the desired iterations.
You can achieve the desired task using Power Query too in Excel.
Here's a step-by-step solution using Power Query:
- Open your Excel workbook and go to the "Data" tab.
- Click on "Get Data" and select "From Other Sources" -> "Blank Query". This will open the Power Query Editor.
- In the Power Query Editor, go to the "Home" tab and click on "Advanced Editor".
- Replace the existing code with the following Power Query code:
let Source = Excel.CurrentWorkbook(){[Name="Inputs"]}[Content], #"Filtered Rows" = Table.SelectRows(Source, each [#"Result 2"] = "Yes"), #"Removed Columns" = Table.RemoveColumns(#"Filtered Rows", {"Result 2"}), #"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Model", "Parts"}, {"Calculation 1", "Result 1"}, {"Calculation 2", "Result 2"}, {"Calculation 3", "Result 3"}}), #"Appended Queries" = Table.Combine({#"Renamed Columns", #"Renamed Columns", #"Renamed Columns"}) // Replace the number of repetitions here in #"Appended Queries"
5. In the code above, replace "Inputs" with the actual name of your table in the "All Inputs" sheet.
6. Replace the comment // Replace the number of repetitions here with the actual number of times you want to repeat the rows.
7. Click on "Done" to close the Power Query Editor.
This Power Query code will filter the rows based on "Result 2" column, remove the "Result 2" column, rename the columns accordingly, and append the resulting table multiple times based on the specified number of repetitions.
Once you've completed the above steps, Power Query will load the transformed data into a new table in Excel. The table will contain the desired iterations based on your requirements.
You can refresh the data in the table whenever needed by clicking on "Data" -> "Refresh All".
I hope the proposal solutions, with AI helps, using VBA or Power Query meets your requirements.
9 Replies
- NikolinoDEGold Contributor
You can started with the VBA code to achieve your task.
Here's an example VBA code that you can use as a starting point:
Sub IterateAndCopyPaste() Dim wb As Workbook Dim wsInputs As Worksheet Dim wsAnalysis As Worksheet Dim wsSummaries As Worksheet Dim tblInputs As ListObject Dim tblAnalysis As ListObject Dim tblSummaries As ListObject Dim inputRow As ListRow Dim analysisRow As ListRow Dim lastRow As Long Dim i As Long ' Set references to the workbook and worksheets Set wb = ThisWorkbook Set wsInputs = wb.Worksheets("All Inputs") Set wsAnalysis = wb.Worksheets("Analysis") Set wsSummaries = wb.Worksheets("Summaries") ' Set references to the tables Set tblInputs = wsInputs.ListObjects("Inputs") Set tblAnalysis = wsAnalysis.ListObjects("Analysis_T") Set tblSummaries = wsSummaries.ListObjects("Summaries") ' Loop through each row in the Inputs table For i = 1 To tblInputs.DataBodyRange.Rows.Count ' Get the current input row Set inputRow = tblInputs.ListRows(i) ' Clear the cells in Analysis_T tblAnalysis.DataBodyRange.ClearContents ' Copy the input row to the first row of Analysis_T inputRow.Range.Copy tblAnalysis.DataBodyRange.Rows(1) ' Wait for calculations to complete (if necessary) ' Add code here to wait for the calculations to complete ' Copy all rows from Analysis_T to Summaries lastRow = tblSummaries.DataBodyRange.Rows.Count tblAnalysis.DataBodyRange.Copy Destination:=tblSummaries.DataBodyRange.Offset(lastRow) ' Delete rows from Summaries where Result 2 is "No" DeleteRowsWithNoResult2 wsSummaries, tblSummaries ' Clear the clipboard Application.CutCopyMode = False Next i End Sub Sub DeleteRowsWithNoResult2(ws As Worksheet, tbl As ListObject) Dim result2Column As Range Dim cell As Range ' Set the Result 2 column range Set result2Column = tbl.ListColumns("Result 2").DataBodyRange ' Loop through each cell in the Result 2 column For Each cell In result2Column.Cells ' Check if the value is "No" and delete the entire row If cell.Value = "No" Then cell.EntireRow.Delete End If Next cell End Sub
Please note that this is a basic example, and you may need to modify it based on your specific workbook structure and requirements. You'll also need to add code to wait for the calculations to complete, as indicated in the comments.
To run the code, press Alt+F11 to open the VBA editor in Excel, insert a new module, and paste the code into the module. You can then run the IterateAndCopyPaste macro to perform the desired iterations.
You can achieve the desired task using Power Query too in Excel.
Here's a step-by-step solution using Power Query:
- Open your Excel workbook and go to the "Data" tab.
- Click on "Get Data" and select "From Other Sources" -> "Blank Query". This will open the Power Query Editor.
- In the Power Query Editor, go to the "Home" tab and click on "Advanced Editor".
- Replace the existing code with the following Power Query code:
let Source = Excel.CurrentWorkbook(){[Name="Inputs"]}[Content], #"Filtered Rows" = Table.SelectRows(Source, each [#"Result 2"] = "Yes"), #"Removed Columns" = Table.RemoveColumns(#"Filtered Rows", {"Result 2"}), #"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Model", "Parts"}, {"Calculation 1", "Result 1"}, {"Calculation 2", "Result 2"}, {"Calculation 3", "Result 3"}}), #"Appended Queries" = Table.Combine({#"Renamed Columns", #"Renamed Columns", #"Renamed Columns"}) // Replace the number of repetitions here in #"Appended Queries"
5. In the code above, replace "Inputs" with the actual name of your table in the "All Inputs" sheet.
6. Replace the comment // Replace the number of repetitions here with the actual number of times you want to repeat the rows.
7. Click on "Done" to close the Power Query Editor.
This Power Query code will filter the rows based on "Result 2" column, remove the "Result 2" column, rename the columns accordingly, and append the resulting table multiple times based on the specified number of repetitions.
Once you've completed the above steps, Power Query will load the transformed data into a new table in Excel. The table will contain the desired iterations based on your requirements.
You can refresh the data in the table whenever needed by clicking on "Data" -> "Refresh All".
I hope the proposal solutions, with AI helps, using VBA or Power Query meets your requirements.
- Antonino2023Brass Contributor
I have made some modifications to your template code to fit my needs. I am now at a point where I would like to paste as values instead of the traditional copy./paste. Do you have any suggestions for doing that? I suspect it will require modifying line 64. I have attached a copy of the xlsm file to this post.
Also, do you have any suggestions for improving the speed of this code?
Sub IterateAndCopyPaste_V2() Dim wb As Workbook Dim wsInputs As Worksheet Dim wsAnalysis As Worksheet Dim wsSummaries As Worksheet Dim tblInputs As ListObject Dim tblModel As ListObject Dim tblAnalysis As ListObject Dim tblSummaries As ListObject Dim inputRow As ListRow Dim analysisRow As ListRow Dim lastRow As Long Dim i As Long ' Temporary ovewrite value Dim Temp As String Temp = "Temp" ' Set references to the workbook and worksheets Set wb = ThisWorkbook Set wsInputs = wb.Worksheets("Inputs") Set wsAnalysis = wb.Worksheets("Analysis") Set wsSummaries = wb.Worksheets("Summaries") ' Set references to the tables Set tblInputs = wsInputs.ListObjects("Inputs_T") Set tblModel = wsAnalysis.ListObjects("Model_T") Set tblAnalysis = wsAnalysis.ListObjects("Analysis_T") Set tblSummaries = wsSummaries.ListObjects("Summaries_T") ' Helper variables num_Inputs_rows = tblInputs.DataBodyRange.Rows.Count On Error Resume Next ' This is a way to handle the error when SpecialCells(xcellTypeBlanks) is empty and returns an error num_Inputs_empty_rows = tblInputs.DataBodyRange.SpecialCells(xlCellTypeBlanks).Rows.Count On Error GoTo 0 data_num_Inputs_rows = num_Inputs_rows - num_Inputs_empty_rows ' Clear tblSummaries before beginning first/new iteration tblSummaries.Range(2, 1).Value = Temp ' This is a temporary fix to allow table to clear in next line tblSummaries.DataBodyRange.ClearContents tblSummaries.DataBodyRange.Delete tblSummaries.Range(2, 1).Value = Temp ' Temp is added back in to allow the For loop to identify LastRow for i = 1 (throws an error without this) ' Loop through each row in tblInputs For i = 1 To data_num_Inputs_rows ' Get the current input row Set inputRow = tblInputs.ListRows(i) ' Clear the cells in Model_T tblModel.DataBodyRange.ClearContents ' This prevents a pop-up on every iteration asking to replace cells with existing data ' Copy the input row to the first row of Model_T inputRow.Range.Copy tblModel.DataBodyRange.Rows(1) ' Wait for calculations to complete (if necessary) ' (In testing this is a buffer to observe impact of code modifications) Application.Wait (Now + TimeValue("0:00:05")) ' Determine which row the Analysis data should be pasted in based on current iteration (i) lastRow = tblSummaries.ListRows.Count ' Copy all rows from tblAnalysis to tblSummaries tblAnalysis.DataBodyRange.Copy Destination:=tblSummaries.DataBodyRange.Offset(lastRow - 1) If i = data_num_Inputs_rows Then tblModel.DataBodyRange.ClearContents ' Clear tblModel MsgBox "Analysis complete. Go to the Summaries sheet and make an offline copy." End If ' Clear the clipboard Application.CutCopyMode = False Next i End Sub 'Sub DeleteBlankRows_V2(ws As Worksheet, tbl As ListObject) ' Dim AllSummaries As Range ' Set AllSummaries = tbl.DataBodyRange ' AllSummaries.SpecialCells(xlCellTypeBlanks).EntireRow.Delete 'End Sub
- Antonino2023Brass Contributor
This file is the right one.
Also, you can disregard the comment about speed for now. It is likely tied to Application.Wait
- Antonino2023Brass ContributorNikolinoDE
Thank you for your detailed response. I will implement your suggestions and get back to you with any questions/issues that may arise!
Regards,