I want to copy data from one table to another, from one workbook to another.
I know the table names, they are identical.
The source table has an unknown number of data rows plus an unknown number of empty rows. The destination table (same name, same sheet) has only empty rows, but not necessarily the same overall number of rows as the origin.
i know i can do something like
sourceBook.Activate
ActiveSheet.ListObjects(knownTableName).DataBodyRange.Select
Selection.Copy
destinationBook.Activate
ActiveSheet.ListObjects(knownTableName).DataBodyRange.Select
ActiveSheet.Paste
However there are a number of problems:
The table is not on the activeSheet. How do i find the sheet that the table is on? or is there a better way to reference it (ideally without having to find the sheet first)?
I know .Activate and Selection.Copy is slow and bad. How can i do it better?
How do i find the "used" data range of both tables without looping through the table rows?
Is it possible to copy the data row by row (so that only non empty rows are copied)? ideally, i would like to just insert all non-empty source rows to the destination table and subsequently delete all empty rows in the destination table
To answer question 2:
Dim loSource as ListObject
Dim loDestination as ListObject
Set loSource = ... 'To do
Set loDestination = ... 'To do
loDestination.Range(2,1).Resize(loSource.ListRows.Count, loSource.ListColumns.Count).Value = loSource.DataBodyRange.Value
Answer to your first problem (maybe you could break your question up and ask different questions for different problems)
Since ListObjects is a child of WorkSheet -- I don't see of any way to avoid iterating through the workbooks looking for the sheet containing the table. Something like this:
Function FindTable(WB As Workbook, TableName As String) As String
Dim ws As Worksheet
Dim wsName As String
On Error Resume Next
For Each ws In WB.Sheets
wsName = ws.ListObjects(TableName).Parent.Name
Next
If Len(wsName) = 0 Then
FindTable = "Table Not Found"
Else
FindTable = wsName
End If
End Function
To test it I created a table named "Hidden Table" and put it on sheet 3. Then I ran this:
Sub test()
Debug.Print FindTable(ActiveWorkbook, "Hidden Table")
Debug.Print FindTable(ActiveWorkbook, "Nonexistant Table")
End Sub
Which printed:
Sheet3
Table Not Found
Related
I am using the code below to copy tables from another workbook into my "extract" workbook.
This code works, but I need to specify which table I am looking for. I was hoping to use a program that could find the table in the specified sheet, or all the cells which contain data and copy those cells.
Sub SelectingTable()
Set Extract = Workbooks("Test1")
Set Pastdue = Workbooks("Past Due Data")
'Look for Past Due table
Pastdue.Activate
Pastdue.Worksheets("Sheet1").ListObjects("Table4").DataBodyRange.Copy
'Paste table in extract
Extract.Activate
Extract.Paste Destination:=Worksheets("Sheet1").Range("B10")
End Sub
In this code I am basically looking for table4 in the Past Due workbook and pasting it in my Extract. I am new to excel vba so I hope you could help me. Thanks.
Hmm do you want to extract a particular table or copy all the tables? For the latter you can just loop through all the tables
Sub SelectingTable()
Dim tbl as listObject
Set Extract = Workbooks("Test1")
Set Pastdue = Workbooks("Past Due Data")
'Loop through table
pasteRow = 1 'set which row to paste
For each tbl in Pastdue.Worksheets("Sheet1").ListObjects
rowsCount = tbl.range.rows.count - 1 'minus header
tbl.DataBodyRange.Copy extract.worksheets("Sheet1").cells(pasteRow,1)
pasteRow = rowsCount +3
next tbl
End Sub
Use case: I want to copy data from column A to Column B (where column A, B are arbitrary columns). Once the data is in Column B, I want to remove duplicate entries within column B.
Make a loop that moves data from column A to column B and then removes duplicates for each sheet in a workbook.
`Sub Copy()
For i = 1 To Sheets.Count
Worksheets(i).Range("A1:A100")
Destination:=Worksheets(i).Range("B1")
Next
End Sub
`
For testing I separated the tasks into two different Sub(). Sub Copy() is working and correctly copies my data. Sheet1 is also named "Sheet1" for my specific workbook
`Sub RemoveStuff()
Dim rng As Range
For j = 1 To Sheets.Count
Set rng = Worksheets("Sheet1").Range(Range("B1"),Range("B1").End(xlDown)).Select
rng.RemoveDuplicates Columns:=(1), Header:=xlGuess
Next
End Sub
`
My error seems to be in defining the range correctly. Each sheet will have a different number of entries to remove duplicates from. Sheet1 might have 50 rows and reduce to 6. Sheet2 could have 70 and reduce to 3. Sheet3 could have 20 rows and reduce to 12 uniques. Excel does not let you remove duplicates from range (B:B!)
How can I properly define my range so I can remove duplicates in a loop for a dynamically defined range for each sheet(sheet=tabs in workbook)?
EDIT 2-23-17
New code from Y0wE3K
Sub RemoveStuff()
Dim ws As Worksheet
For Each ws In Worksheets
ws.Columns("P:P").RemoveDuplicates,Columns:=1, Header:=xlYes
Next
End Sub
Still does not work. If I manually select Column P before I run the macro, it works. But it only goes for the one sheet I have selected, it does not seem to execute the loop. Definitely does not automatically do each sheet, or prompt me for each one.
EDIT: 3/4
Make sure that you do not have any protected data, I also experienced issues with pivot tables but I think this may be permissions thank you for help.
Your RemoveStuff subroutine can be rewritten as:
Sub RemoveStuff()
Dim ws As Worksheet
For Each ws In Worksheets ' Use Worksheets instead of Sheets,
' in case there are any Charts
'You can just select the whole column, rather than selecting
'specific rows
ws.Columns("B:B").RemoveDuplicates Columns:=1, Header:=xlGuess
Next
End Sub
Sub RemoveStuff()
Dim ws As Worksheet
For Each ws In Worksheets
ws.Columns("P:P").RemoveDuplicates,Columns:=1, Header:=xlYes
Next
End Sub
This code will work. As a final note, please make sure you have no Protected Data, or pivot tables inside of the sheets you need to run the remove script on. For whatever reason that caused mine to fail, but running my script on the correct sheets that are unprotected worked GREAT.
I have a Data Validation list in cell T3 in Sheet3 of my workbook. The list contains location names. In sheet1 of my workbook I have all the data for all locations in tables next to each other, e.g
location 1|date|score|percentage|target| |location 2|date|score|percentage|target| etc....
I am looking to select a location from the drop down list and that will copy in the relevant table to sheet3. So you just select a location and can see the data. I'm wondering if the best way to go about this is formulas or to use VBA (my experience with using drop down lists in VBA is limited). Here is something that I am currently working on but it is incomplete at the moment and still leads to the question of 'is there a faster way to do this in VBA'. Any help or advice is greatly appreciated! (my validation list is called List1)
=IF(ISNUMBER(A2),IF(ISERROR(VLOOKUP(A2,Sheet1!$A:$EG,MATCH(List1,Sheet1!$1:$1,0),FALSE)),0),"")
The idea is that i could have a table of formulas so depending on the list value, different data would appear.
This isn't complete but it should get you started / give you some ideas
Sub CopyTable()
Dim colNo, lastRow As Integer
Dim ws1, ws3 As Worksheet
Set ws1 = Sheets("Sheet1") ' assign the worksheet variables
Set ws3 = Sheets("Sheet3")
colNo = Application.Match(ws1.Range("T1"), ws1.Range("A1:R1")) ' work out which column the required table starts in
lastRow = ws1.Cells(10000, colNo).End(xlUp).Row ' work out the last row of the table
ws1.Range(ws1.Cells(1, colNo), ws1.Cells(lastRow, colNo + 4)).Copy ws3.Range("A1") ' copy the table
End Sub
So, I've explored a few answered VBA Questions, but I'm still stuck. I have three sheets "By_Oppt_ID", "Top_Bottom" and "Non_Top_Bottom". The first two have a large amount of columns each with a unique name. Now there are some columns in By_Oppt_ID that aren't in "Top_Bottom". So I want to compare each column name in By_Oppt_ID to every column name in "Top_Bottom", and if the column name isn't found, copy that column name and all the rows beneath it, to a third worksheet "Non_Top_Bottom".
So Here's what I have:
Sub Copy_Rows_If()
Dim Range_1 As Worksheet, Range_2 As Worksheet
Dim c As Range
Set Range_1 = Workbooks("Complete_Last_Six_Months_Q_Results.xlsx").Sheets("Top_Bottom")
Set Range_2 = Workbooks("Complete_Last_Six_Months_Q_Results.xlsx").Sheets("By_Oppt_ID")
Application.ScreenUpdating = False ' Stays on the same screen even if referencing different worksheets
For Each c In Range_2.Range("A2:LX2")
' Checks for values not in Range_1
If Application.WorksheetFunction.CountIf(Range_1.Range("A1:CR1"), c.Value) = 0 Then
' If not, copies rows to new worksheet
' LR = .Cells(Row.Count, c).End(xUp).Row
c = ActiveCell
Sheets("By_Oppt_ID").Range("Activecell", "ActiveCell.End(xlDown)").Copy Destination:=Workbooks("Complete_Last_Six_Months_Q_Results.xlsx").Sheets("Non_Top_Bottom").Range("A1:A6745")
Set rgPaste = rgPaste.Offset(0, 1) 'Moves to the next col, but starts at the same row position
End If
Next c
End Sub
I've compiled this many ways and keep getting a series of errors: Subscript Out of Range/ Method "Global_Range" Failure. What am I doing wrong?
If you are going to have this code within the same workbook every time, try using
ThisWorkbook.Sheets("Top_Bottom")
instead of
Workbooks("Complete_Last_Six_Months_Q_Results.xlsx").Sheets("Top_Bottom")
replicate that through your code and see if that fixes the problem.
What do you mean by c = Activecell? Do you mean to say c.activate?
You might then also want to change the next line to
Sheets("By_Oppt_ID").Range(Activecell, ActiveCell.End(xlDown)).Copy Workbooks("Complete_Last_Six_Months_Q_Results.xlsx").Sheets("Non_Top_Bottom").Range("A1")
I have an XL file with some data to be manipulated. I think I will need to use a VB script to do this - but perhaps there is a simpler way with a formula. Just the same, could someone point out BOTH ways of achieving the following?
I have a column of numeric values (ID) in Sheet 1.
I want to use each ID as an index to lookup a list in Sheet 2.
Sheet 2 has two columns
First column is the index and Second column is the Text String
e.g.
1 Apple
2 Orange
3 Pear
What I want is to replace the column of IDs in sheet 1 with the looked up text string from Sheet 2!
Thats all...
Please help!
Not a tough situation there. Here are some solutions...
With VBA:
I know you said you're a little new with VB so I tried to explain each line as I went along. Also, the code is free-handed so forgive me if I left an error in there somewhere.
Sub replaceData()
dim i as integer, j as integer 'These are just some variables we'll use later.
dim sheetOne as worksheet, sheetTwo as worksheet, myWb as workbook
dim myData as string, myId as string
set myWB = excel.activeworkbook 'These three lines set your workbook/sheet variables.
set sheetOne = myWB.worksheets("Old Data")
set sheetTwo = myWB.worksheets("New Data")
for i = 1 to sheetTwo.usedrange.rows.count 'This loops through the rows on your second sheet.
myId = sheetTwo.cells(i,1).value 'This assigns the value for your id and the data on your second sheet.
myData = sheetTwo.cells(i,2).value
for j = 1 to sheetOne.usedrange.rows.count 'This loops through the rows on your first sheet.
if sheetOne.cells(j,1).value = myId then 'This checks each row for a matching id value.
sheetOne.cells(j,1).value = myData 'This replaces that id with the data we got from the second sheet.
end if
next j
next i
end sub
With an Excel formula:
Place the following formula in cell C1 of the first worksheet (the
sheet with the IDs you will be replacing). **Note that you will
have to replace the "InsertSheetTwoNameHere" portion with the name
of your second sheet (don't remove those single quotes though). Also
note you will need to replace the "1000" with the number of the last
used row in sheet two.
=vlookup(A1,’InsertSheetTwoNameHere’!$A$1:$B$1000,2,FALSE)
Next simply drag the handle on the cell that makes it copy itself
(whatever the heck it's called) all the way down to the end of your
range.
Next, copy those cells and then paste them over the IDs using the
Values Only setting.
Hope this helps and good luck.