Hod to copy data from one sheet to another with limited selection of columns using VBA - excel

I need to copy data from one sheet to another with a limited selection of columns using VBA, not continuous and transpose the copied data in a column while pasting to another sheet. Also, I want to skip the empty cells while doing so.
I want to apply a loop but I am not able to declare the ranges of cells exactly as they should be. I am very new to VBA and below is the code which I am using trying to achieve the goal.
Option Explicit
Sub CopyPasteLoop()
Dim X As Long
Dim Y As Long
Dim Col As Long
Dim row1 As Long
'Dim A As Long
Col = 1
Sheets("Copy").Activate
'For A = 1 To 10000
row1 = Sheets("Copy").Range(.Cells(.Rows.Count, Col)).End(xlUp).row
Sheets("Key Entry Data").Activate
X = Sheet2.Range("A" & Rows.Count).End(xlUp).row
'Y = Sheet1.Cells(1, Columns.Count).End(xlToLeft).Column
Sheets("Copy").Activate
Sheet1.Range("Col" & 2, "Col" & row1).Select
Selection.Copy
'X = X + 1
Sheets("Key Entry Data").Activate
Sheet2.Cells(X).Select
Sheet2.Range("A" & X).PasteSpecial xlPasteValues
Col = ActiveCell.Next.EntireColumn.Cells(1).Select
'Next X
End Sub

In general you should avoid using .Acitvate and .Select as described here. In your code you can completely leave out those parts. This and the unqualified ranges (as mentioned in the comments) are most likely the cause of your problems. Here is your corrected code:
Option Explicit
Sub CopyPasteLoop()
Dim X As Long
Dim Y As Long
Dim Col As Long
Dim row1 As Long
'Dim A As Long
Col = 1
'For A = 1 To 10000
row1 = Sheets("Copy").Cells(Rows.Count, Col).End(xlUp).Row
X = Sheet2.Range("A" & Rows.Count).End(xlUp).Row
'Y = Sheet1.Cells(1, Columns.Count).End(xlToLeft).Column
Sheet1.Range(Sheet1.Cells(2, Col), Sheet1.Cells(row1, Col)).Copy Sheet2.Range("A" & X)
'X = X + 1
'Next X
End Sub
Please note that the For loop you commented out will not work. As it's unclear from your question what that loop is supposed to achieve I'm not able to correct it to what exactly you're trying to do. In general, you don't need X = X + 1 inside a For loop (it will skip every second integer this way), as the For ... To statement takes care of that.

Thank you for sharing this M.Schalk, I am using the below code to copy the data to another sheet. Can you look at the code and share an effective one with me?
Option Explicit
Sub EmailIDCopy()
Dim X As Long 'X is the value of Row
Dim Y As Long
Dim Col As Long 'Col is used to column of Sheet2
Dim row1 As Long 'row1 is currently being used for defining the last row of column
Dim M As Long
Col = 1
Sheets("Copy").Activate
For M = 1 To 5
row1 = Sheets("Copy").Cells(Rows.Count, Col).End(xlUp).row
Sheets("Key Entry Data").Activate
X = Sheet2.Range("A" & Rows.Count).End(xlUp).row
Sheets("Copy").Activate
Sheet1.Range(Cells(2, Col), Cells(row1, Col)).SpecialCells(xlCellTypeVisible).SpecialCells(xlCellTypeConstants).Copy
X = X + 1
Sheets("Key Entry Data").Activate
Sheet2.Cells(X).Select
Sheet2.Range("A" & X).PasteSpecial xlPasteValues
Col = Col + 2
Next M
End Sub
thank you.

Related

Getting unique values for multiple column separatly

What is worng with my function its loading the two different column A and B and pasting the unique values of column A into Column M and N.
I want to repeat this function for the 7 columns.
I would appreciate your help in this regards.
Sub GetUniques()
Dim d As Object, c As Variant, i As Long, lr As Long, lr2 As Long, lr3 As Long, lr4 As Long, lr5 As Long, lr6 As Long
Set d = CreateObject("Scripting.Dictionary")
lr = Cells(Rows.Count, 1).End(xlUp).Row
c = Range("A2:A" & lr)
lr2 = Cells(Rows.Count, 2).End(xlUp).Row
e = Range("B2:B" & lr2)
For i = 1 To UBound(c, 1)
d(c(i, 1)) = 1
Next i
For i = 1 To UBound(e, 1)
d(e(i, 1)) = 1
Next i
Range("M2").Resize(d.Count) = Application.Transpose(d.keys)
Range("N2").Resize(d.Count) = Application.Transpose(d.keys)
End Sub
It looks like your plan is to have a lr variable for each column as well as loops and transpose statements. You can avoid this by nesting your code in a column loop.
The current Column range is hard coded here (A to E) but this can be updated to be dynamic as needed. The output is also hard coded to be dropped 9 columns to the right of the input column. This aligns with A to J, B to K, etc.
Sub GetUniques()
Dim c As Variant, i As Long, lr As Long, col As Long
Dim d As Object
For col = 1 To 5 'Column A to E
Set d = CreateObject("Scripting.Dictionary")
lr = Cells(Rows.Count, col).End(xlUp).Row
c = Range(Cells(2, col), Cells(lr, col))
For i = 1 To UBound(c, 1)
d(c(i, 1)) = 1
Next i
Cells(2, col + 9).Resize(d.Count) = Application.Transpose(d.keys)
Set d = Nothing
Next col
End Sub
I am adding the UNIQUE- solution - for completeness:
You can either use a manual formula in J2: =UNIQUE(A:E,TRUE) - the second parameter tells UNIQUE to put out unique values per column --> it will spill from J to N.
You can use this formula in a VBA-routine as well:
Public Sub writeUniqueValues(rgSource As Range, rgTargetTopLeftCell As Range)
With rgTargetTopLeftCell
.Formula2 = "=UNIQUE(" & rgSource.Address & ",TRUE)"
With .SpillingToRange
.Value = .Value 'this will replace the formula by values
End With
End With
End Sub
You can then use this sub like this:
Public Sub test_writeUniqueValues()
With ActiveSheet 'be careful: you should always use explicit referencing
Dim lr As Long
lr = .Cells(Rows.Count, 1).End(xlUp).Row
writeUniqueValues .Range("A2:E" & lr), .Range("J2")
End With
End Sub
It would be interesting to compare performance of both solutions (using the formula vs. using a dictionary) ...

VBA VLOOKUP with dynamic range

I am brand-new to VBA.
I have two worksheets in the same workbook. The first worksheet, shStudentInfo, contains all of the information for each of my students, one row per StudentID (B4 in the code). The second worksheet, shSchedData, contains their schedules where there may be 0-14 rows per StudentID, depending on how many courses each student is taking.
I am attempting to use a loop and VLOOKUP with a dynamic range to extract the course name from each row of shSchedData and copy it to the appropriate cell in shStudentInfo, then move down one row. Currently I've hardcoded cell "CO4" as the appropriate cell although I will also need to make that reference move one cell to the right for each pass through the loop.
Here is my inelegant code:
Option Explicit
Dim MyRow As Long
Sub StudentSchedules()
Dim EndRow As Long
Dim MyRng As Range
shSchedData.Activate
'hard code first row of data set
MyRow = 3
'dynamic code last row of data set
EndRow = shSchedData.Range("A1048575").End(xlUp).Row
'create a dynamic range, a single row from shSchedData
Set MyRng = ActiveSheet.Range(Cells(MyRow, 1), Cells(MyRow, 9))
'Loop through entire data set one line at a time
Do While MyRow <= EndRow
shSchedData.Select
MyRng = ActiveSheet.Range(Cells(MyRow,1),Cells(MyRow,9))
shStudentInfo.Select
'Import course name from shSchedData worksheet
Range("CO4").Select
ActiveCell.Clear
ActiveCell.Formula = "=VLOOKUP(B4,'Schedule Data'!& MyRng,6,0)"
'The above line results in a #NAME? error in CO4 of shStudentInfo
'Also tried:
'ActiveCell.Formula = "=VLOOKUP(B4,'Schedule Data'!& MyRng.Address,6,0)"
'increment counter
MyRow = MyRow + 1
Loop
End Sub
The following rewrite will get your code working to the extent that its purpose can be determined.
The VLOOKUP formula does not appear correct and in any event, there might be a better method of retrieving the data. However, I cannot determine your end purpose from your narrative or code. Sample data together with expected results would help.
Option Explicit
'I see no reason to put this here
'dim myRow As Long
Sub StudentSchedules()
Dim myRow, endRow As Long, myRng As Range
'no need to activate, just With ... End With block it
With shSchedData
'assigned a strarting value
myRow = 3
'dynamic code last row of data set
endRow = .Cells(.Rows.Count, "A").End(xlUp).Row
'Loop through entire data set one line at a time
Do While myRow <= endRow
'create a dynamic range, a single row from shSchedData
Set myRng = .Range(.Cells(myRow, 1), .Cells(myRow, 9))
'Import course name from shSchedData worksheet
shStudentInfo.Range("CO4").Offset(0, myRow - 3).Formula = _
"=VLOOKUP(B4, " & myRng.Address(external:=True) & ", 6, false)"
'increment counter
myRow = myRow + 1
Loop
End With
End Sub
I came up with this, see if it fits you
Dim a As Double
Dim b As Double
Dim ml As Worksheet
Dim arrayrng As Variant
Dim i As Integer
Dim x As String
Dim y As String
Set ml = Worksheets("Master Data")
a = ml.Cells(Rows.Count, 11).End(xlUp).Row
b = ml.Cells(Rows.Count, 1).End(xlUp).Row
For i = a To b - 1
a = ml.Cells(Rows.Count, 11).End(xlUp).Row
b = ml.Cells(Rows.Count, 1).End(xlUp).Row
arrayrng = "E" & a + 1
x = "=VLOOKUP(" & arrayrng
y = ",'Data Base'!I:J,2,0)"enter code here
Range("K" & a + 1) = x + y
Next

Populate blank cells in a column until all populated from repeating list

I need to use VBA code to populate a list of filtered blank cells. I decided to make a picture with small example to explain it easier. Column D should be populated with names from col A repeating until each ID has a name.
I have absolutely no idea how to loop it to make it work - it's mind boggling! I have been searching the web for hours so I am now asking for help. Please note that column C and D are filtered with criteria blanks for column D.
Here is working code to populate blank cells of a filtered list with the same 3 names alternating.
Sub Macro1()
Dim last As Long
Dim counter As Integer
Dim nameRange As Range
Dim cell As Range
last = Range("A2").End(xlDown).Row
Set nameRange = Range("D2:D" & last).SpecialCells(xlCellTypeVisible)
counter = 1
For Each cell In nameRange
If counter = 1 Then
cell.Value = "Carrie"
counter = counter + 1
ElseIf counter = 2 Then
cell.Value = "Lisa"
counter = counter + 1
Else
cell.Value = "Bob"
counter = 1
End If
Next
End Sub
thanks for everyone's input - Hopefully, this will help someone else in the future.
This will do it without the need of filtering the data.
Sub foo()
Dim ws As Worksheet
Dim lastrowa As Long
Dim lastrowd As Long
Dim counta As Long
Dim rng As Range
counta = 2 'First row of name list in column A
Set ws = Sheets("Sheet1")
With ws
lastrowa = .Range("A" & .Rows.Count).End(xlUp).Row
lastrowd = .Range("D" & .Rows.Count).End(xlUp).Row
For Each rng In .Range(.Cells(2, 5), .Cells(lastrowd, 5))
If rng.Value = "" Then
rng.Value = .Cells(counta, 1).Value
If counta = lastrowa Then
counta = 2
Else
counta = counta + 1
End If
End If
Next rng
End With
End Sub
Range("D2:D4").Value = Range("A2:A4").Value
Range("D2:D4").AutoFill Destination:=Range("D2:D11")
If you don't know where column C ends that is easy enough to work out. Something like
Range("D2:D4").Value = Range("A2:A4").Value
Range("D2:D4").AutoFill Destination:=Range(Range("D2"), _
Range("C2").End(xlDown).Cells(1, 2))
If you don't know how far the data extends in column A:
Dim last As Integer
last = Range("A2").End(xlDown).Row
Range("D2:D" & last).Value = Range("A2:A" & last).Value
Range("D2:D" & last).AutoFill Destination:=Range(Range("D2"), _
Range("C2").End(xlDown).Cells(1, 2))
My example doesn't work perfectly, or even well... Its late :)
Create a named range that encapsulates all your "names" (called namesRange in my example).
In your "assigned" column put the following formula:
=INDEX(namesList,ROW()-((INT(ROW()/ROWS(namesList))*ROWS(namesList))),1)
Update...
Thought about it, and remembered how to excel a little more.. The following is what I was trying to do in my first example.
=INDEX(namesList,MOD(ROW()-1,ROWS(namesList)-1)+1,1)

Inserting VBA formula into a defined Range

I'm looping through a table (Sheet4) in a worksheet and inserting an empty column between each original column. In the new, empty columns, I want to insert a VLookup function.
I has successfully inserted the columns and I have successfully held the proper range (proper number of rows too) in a variable called FormulaRange.
I'm having problems with the VLookup. I don't know if it's the way I'm storing my variables or if I need to have a paste function after my Vlookup. Can someone take a look and give me a hand?
*note - I stored FormulaRange as String becuase As Range wouldn't let me pass my code into the variable. As a result I can't use the FormulaRange.Formula Method.
If I were to manually input the VLookup I would write it as =VLOOKUP(B1,RosettaStone_Employees!$A$1:$B$5,2,FALSE) and then copy down the range.
Sub InsertColumnsAndFormulasUntilEndOfProductivityTable()
Dim ActivityRange As Range
Dim UserName As String
Dim FormulaRange As String
Dim i As Integer
Dim x As Long
Dim y As Long
Dim Startrow As String
Dim Lastrow As String
Sheet6.Activate
Set ActivityRange = Range("A1", Range("B1").End(xlDown))
Sheet4.Activate
Range("A1").Select
y = Sheet4.Cells(Rows.Count, 1).End(xlUp).Row - 1
x = (Sheet4.Cells(1, Columns.Count).End(xlToLeft).Column) * 2
For i = 1 + 2 To x Step 2
Columns(i).EntireColumn.Insert
Startrow = 2
Lastrow = y
UserName = Cells(1, i - 1)
FormulaRange = Cells(Startrow, i).Address & ":" & Cells(Lastrow + 1, i).Address
FormulaRange = "=VLookup(UserName, ActivityRange, 2, False)"
Next
End Sub
Thanks
Jonathan
I changed your code a little to get rid of the sheet activates. Also I changed a few things to ranges and included with blocks.
This is untested:
Sub InsertColumnsAndFormulasUntilEndOfProductivityTable()
Dim ActivityRange As Range
Dim UserName As String
Dim FormulaRange As Range
Dim i As Long
Dim x As Long
Dim y As Long
Dim Startrow As Long
Dim Lastrow As Long
With Sheet6
Set ActivityRange = .Range("A1", .Range("B1").End(xlDown))
End With
With Sheet4
y = .Cells(.Rows.Count, 1).End(xlUp).Row - 1
x = (.Cells(1, .Columns.Count).End(xlToLeft).Column) * 2
For i = 1 + 2 To x Step 2
.Columns(i).EntireColumn.Insert
Startrow = 2
Lastrow = y
UserName = .Cells(1, i - 1)
Set FormulaRange = .Range(.Cells(Startrow, i), .Cells(Lastrow + 1, i))
FormulaRange.FormulaR1C1 = "=VLookup(R1C[-1],'" & ActivityRange.Parent.Name & "'!" & ActivityRange.Address(1, 1, xlR1C1) & ", 2, False)"
'If you do not want dynamic formulas and just want the value
'then comment out the above and use the below.
'FormulaRange.Value = Application.Vlookup(UserName,ActivityRange,2,False)
Next
End With
End Sub
The R1C1 is a relative nomenclature. When it fills the formulas into the columns it will return the cell relative to the one into which the formula will be filled.
For example, above I use R1C[-1]. This says get the first row of the column directly to the left. So if the formula was being entered into B2 it would return A$1.
The [] denotes the relative address. Without the [] eg R1C1 it would indicate an absolute address and would return $A$1. So R1C1:R4C2 would return a range of $A$1:$B$4.

Copy three columns into one column in Excel VBA

I need help to create a Excel VBA macro. I have a workbook contains 4 worksheets. Coulmn "A" in worksheet number 1, 2 and 3 are filled with data. I need to copy these data into Sheet 4 Column "A". I already done this by using this code but it dosn't work (it only copy the data by replacing ..).
EXAMPLE (I need to do following)
(Sheet 1 Col. A)
1
2
3
4
(Sheet 2 Col. A)
5
6
(Sheet 3 Col. A)
7
8
9
Need to copy all above in sheet 4 Col. A as follows
1
2
3
4
5
6
7
8
9
So, I wrote a code as follows
Sub CopyColumnToWorkbook()
Dim sourceColumn As Range, targetColumn As Range
Set sourceColumn = Worksheets("Sheet1").Columns("A")
Set targetColumn = Worksheets("Sheet4").Columns("A")
sourceColumn.Copy Destination:=targetColumn
End Sub
Sub CopyColumnToWorkbook2()
Dim sourceColumn As Range, targetColumn As Range
Set sourceColumn = Worksheets("Sheet2").Columns("A")
Set targetColumn = Worksheets("Sheet4").Columns("A")
sourceColumn.Copy Destination:=targetColumn
End Sub
Sub CopyColumnToWorkbook2()
Dim sourceColumn As Range, targetColumn As Range
Set sourceColumn = Worksheets("Sheet3").Columns("A")
Set targetColumn = Worksheets("Sheet4").Columns("A")
sourceColumn.Copy Destination:=targetColumn
End Sub
This above coding is not work as I need. Someone please help me to do as in above EXAMPLE.
Thank you very much.
This is quick code I threw together just to get you on the right track. It can be cleaned up. Basically you want to look through each sheet and see what the last column used is, then copy the entire used range for column A, and paste it onto the master sheet, starting from the last cell used in column A. You don't want to paste entire columns, so I used "End(xlUp)" which find the last cell used in column A.
Sub ColumnAMaster()
Dim lastRow As Long, lastRowMaster As Long
Dim ws As Worksheet
Dim Master As Worksheet
Application.ScreenUpdating = False
Set Master = Sheets.Add
Master.Name = "Master"
lastRowMaster = 1
For Each ws In ThisWorkbook.Sheets
If ws.Name <> "Master" Then
lastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
ws.Range("A1:A" & lastRow).Copy Destination:=Master.Range("A" & lastRowMaster)
lastRowMaster = Master.Range("A" & Rows.Count).End(xlUp).Row + 1
End If
Next
Application.ScreenUpdating = True
MsgBox "Done!"
End Sub
Sorry StackOverflow is not indenting the code as it should...
Things you may want to do: check if there is any data at all inside each sheet before copying A over to the master, loop through worksheets in a specific order, check if a 'master' sheet exists or not already, etc.
Here is another way, very quick and basic but does the job
You could obviously combine all of those 3 do loops into one loop
Dim x As Integer
Dim y As Integer
x = 1
y = 1
Do Until Worksheets("Sheet1").Range("A" & x) = ""
Worksheets("Sheet4").Range("A" & y) = Worksheets("Sheet1").Range("A" & x)
y = y + 1
x = x + 1
Loop
x = 1
Do Until Worksheets("Sheet2").Range("A" & x) = ""
Worksheets("Sheet4").Range("A" & y) = Worksheets("Sheet2").Range("A" & x)
y = y + 1
x = x + 1
Loop
x = 1
Do Until Worksheets("Sheet3").Range("A" & x) = ""
Worksheets("Sheet4").Range("A" & y) = Worksheets("Sheet3").Range("A" & x)
y = y + 1
x = x + 1
Loop

Resources