is it possible to loop on column letters?
For col = A to Z
column(col:col).select
selection.copy
Next
Or am I oblige to use a function to transform letters into numbers?
To convert Formulas to Values:
Dim cols As Range, c As String
Set cols = UsedRange.Columns
For Each c In Split("N Q T") ' add the rest of the column letters
cols(c).Value = cols(c).Value ' or .Value2 if no dates or currencies in the range
Next
If it is every third column from column N, another approach can be:
Dim col As Range, i As Long
Set col = UsedRange.Columns("N")
For i = 1 To 17 ' to repeat 17 times
col.Value = col.Value
Set col = col.Offset(, 3)
Next
No need to transform letters into numbers as you can pass letters to Columns and Cells:
Columns("B") 'the same as Columns(2)
Cells(1, "B") 'same as Cells(1, 2)
However looping through letters is kind of a hassle and you'd have to transform a number into a letter first, for example using Chr(64 + Num)
I don't know if it take a lot of calculating time but I actually have
Columns("N:N").Select
selection.Copy
selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Columns("Q:Q").Select
selection.Copy
selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Columns("T:T").Select
selection.Copy
selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
I have 17 time this group of rows, do you think it's a huge waste of time?
EDIT
answer with the link in the comment below, thanks to #Rdster
I suggest one of these two solutions :
1- The Column A is the first column, and Z is the 26th column
'Declaration
Dim iFirstCol as integer
Dim iLastCol as integer
iFirstCol = 1 'the first column (A)
iLastCol = 26 'the last column (Z)
'Looping
FOR col = iFirstCol to iLastCol
Columns(col:col).Select
Selection.Copy
'....
LOOP col
2- The ASCII values of the letters A to Z are 65 to 90.
'Declaration
Dim Cols as string
Your loop can be easily transformed into:
'Looping
FOR col = 65 to 90
Cols=CHR(col) & ":" & CHR(col)
Columns(Cols).Select
Selection.Copy
'...
LOOP col
Hope this can help!
Related
I'm recording a macro and need some help. I'd like copy and paste the values from the column G of the "SalesData" worksheet into cells A2, A12, A22 etc of the "Results" worksheet until there's no more values in the column G.
VBA is pretty new to me, I've tried using Do/Until, but everything crashed. Could you please help me? Please see the code I've recorded below. Thank you!
Sub(x)
Sheets("SalesData").Select
Range("G2").Select
Selection.Copy
Sheets("Results").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("A12").Select
Sheets("SalesData").Select
Range("G3").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Results").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("A22").Select
Sheets("SalesData").Select
Range("G4").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Results").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Range("A32").Select
Sheets("SalesData").Select
Range("G5").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Results").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
I prefer to find the last cell in the column first then use a For loop.
Since you are only doing the values we can avoid the clipboard and assign the values directly.
Since you paste is every 10 cells we can use a separate counter to move down 10 each loop.
Sub x()
Dim ws As Worksheet
Dim lst As Long
Dim i As Long, j As Long
'use variable to limit the number of times we type the same thing
Set ws = Worksheets("Results")
'First row of the output
j = 2
'using with and the "." in front of those items that belong to it also limits the typing.
With Worksheets("SalesData")
'Find the last row with values in Column G
lst = .Cells(.Rows.Count, 7).End(xlUp).Row
'Loop from the second row to the last row.
For i = 2 To lst
'Assign the value
ws.Cells(j, 1).Value = .Cells(i, 7).Value
'Move down 10 rows on the output
j = j + 10
Next i
End With
End Sub
here is the same thing but using range variables
Sub x()
Dim src As Range
Dim dst As Range
Set dst = Worksheets("Results").Range("a2") ' point to top cell of destination
With Worksheets("SalesData")
For Each src In Range(.Cells(2, "g"), .Cells(.Rows.Count, "g").End(xlUp)) ' loop through used cell range in column G
dst.Value = src.Value
Set dst = dst.Offset(10) ' move destination pointer down 10 rows
Next src
End With
End Sub
This is just for fun/practice for another way to do it:
Sub copyFromG()
Dim copyRng As Range, cel As Range
Dim salesWS As Worksheet, resultsWS As Worksheet
Set salesWS = Sheets("SalesData")
Set resultsWS = Sheets("Results")
Set copyRng = salesWS.Range("G2:G" & salesWS.Range("G2").End(xlDown).Row) ' assuming you have a header in G1
For Each cel In copyRng
resultsWS.Range("A" & 2 + 10 * copyRng.Rows(cel.Row).Row - 30).Value = cel.Value
Next cel
End Sub
I have data that looks like the table shown below. The number of observations in this dataset varies each month. The columns remain the same. I would like to loop my code through each row until the row is empty. I think a do while loop would be appropriate, but I have not been successful in executing it thus far (of note, I am a complete VBA newbie.)
A couple of other notes: The only thing that will change as the code runs through each observation of data is the Range selected in line 2 (I will want to move down to the next row of observations) and the final range selected for the Paste Special step in the final line of the code (again, I will want to move down to the next row of observations with each iteration).
Sample Data:
Sex Age Race Total Cholesterol HDL-Cholesterol Systolic Blood Pressure Treatment for High Blood Pressure Diabetes Smoker
F 50 AA 300 90 200 Y Y Y
M 55 AA 290 90 200 Y Y Y
F 50 AA 300 90 200 N N N
Code that I need to loop through each non-empty row:
Sub ASCVD()
Sheets("Sheet1").Select
Range("A2:I2").Select
Selection.Copy
Sheets("Omnibus").Select
Range("C3").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Range("B13").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet1").Select
Range("J2").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
Thank you very much in advance for your help!!!
On second thought, what you are really asking is how to use a Do While loop:
Sub ASCVD()
Dim row As Integer
row = 2
Do While ThisWorkbook.Sheets("Sheet1").Cells(row, 1) <> "" 'Loop until first cell is empty
ThisWorkbook.Sheets("Sheet1").Range("A" & row & ":I" & row).Select
Selection.Copy
Sheets("Omnibus").Select
Range("C3").Select
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Range("B13").Select
Application.CutCopyMode = False
Selection.Copy
Sheets("Sheet1").Select
Range("J" & row).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
row = row + 1
Loop
End Sub
The code loops throw rows 2, 3, 4, 5 .... and stops when it finds a row where the first cell is empty
Create an example of your desired end result, it is extremely unclear what you want to achieve at the moment. (Right now you are only describing a mess of implementation, not what the big picture is)
Anyway I am assuming all you want to do is transpose your data, this code does the job:
Sub ASCVD()
Dim Data() As Variant
Dim nrow As Integer
Data() = ThisWorkbook.Sheets("Sheet1").Range("A1").CurrentRegion.Value
nrow = UBound(Data(), 1)
ThisWorkbook.Sheets("Omnibus").Activate
DoEvents
'Previous two lines needed so that the .Range(Cells(3.3), ... part works below
ThisWorkbook.Sheets("Omnibus").Range(Cells(3, 3), Cells(16 + 2, nrow + 2)) = Application.WorksheetFunction.Transpose(Data())
'Cells(rownumber, columnnumber). Cells(1,1) is cell A1
'Cells(3, 3) is same as cell C3.
'Cells(16 + 2, nrow + 2) in your example case will be cell F18, the last cell of your data.
'+2 because you want to start from C3, meaning all your data is shifted two cells down and two cells right
End Sub
I am trying to loop the following
Dim x As Integer
Dim y As Integer
x = Range("AE4")
y = Range("AD4")
If x >= y Then
Range("AE4").Select
Selection.Copy
Range("AD4").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Else
End If
Once this cell AE4 has been checked and then copied or not depeding of it is greater or = to AD4 i would like this to then move on to AE5, AE6 etc to the end of the data set. any ideas what i need to do next? I currently have the rest of the script executed before this checking iof the a cell date is below 4 weeks and then 5 weeks, 6 weeks old up to 10 weeks. and is currenlty working as expected checking the date of the cell and then checking and copying the first cell in the data.
Full script is as follows.
Sub Test()
Range("AE4").Select
ActiveCell.Formula = _
"=IF(RC[-2]>=TODAY()-28,""1"",IF(AND(RC[-2]<TODAY()-28,RC[-2]>=TODAY()-35),""4"",IF(AND(RC[-2]<TODAY()-35,RC[-2]>=TODAY()-42),""5"",IF(AND(RC[-2]<TODAY()-42,RC[-2]>=TODAY()-49),""6"",IF(AND(RC[-2]<TODAY()-49,RC[-2]>=TODAY()-56),""7"",IF(AND(RC[-2]<TODAY()-56,RC[-2]>=TODAY()-63),""8"",IF(AND(RC[-2]<TODAY()-63,RC[-2]>=TODAY()-70),""9"",IF(RC[-2]<TODAY()-70,""10""))))))))"
Range("AE4").Select
Selection.AutoFill Destination:=Range("AE4:AE200")
Range("AE4:AE200").Select
Dim x As Integer
Dim y As Integer
x = Range("AE4")
y = Range("AD4")
If x >= y Then
Range("AE4").Select
Selection.Copy
Range("AD4").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Else
End If
End Sub
Below is some code that'll do what I think you're asking. It looks as though you're relying on the macro generator quite heavily which tends to 'select' a lot more than a developer needs to do. Have a play with your code and look at other posts to see how others do it.
Sub Test()
Dim ws As Worksheet
Dim startCell as Range
Dim fullRng As Range
Dim thisCell As Range
Dim leftCell as Range
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set startCell = ws.Range("AE4")
Set fullRng = startCell.Resize(196)
startCell.Formula = "=IF(RC[-2]>=TODAY()-28,""1"",IF(AND(RC[-2]<TODAY()-28,RC[-2]>=TODAY()-35),""4"",IF(AND(RC[-2]<TODAY()-35,RC[-2]>=TODAY()-42),""5"",IF(AND(RC[-2]<TODAY()-42,RC[-2]>=TODAY()-49),""6"",IF(AND(RC[-2]<TODAY()-49,RC[-2]>=TODAY()-56),""7"",IF(AND(RC[-2]<TODAY()-56,RC[-2]>=TODAY()-63),""8"",IF(AND(RC[-2]<TODAY()-63,RC[-2]>=TODAY()-70),""9"",IF(RC[-2]<TODAY()-70,""10""))))))))"
startCell.AutoFill fullRng
For Each thisCell In fullRng.Cells
Set leftCell = thisCell.Offset(, -1)
Debug.Print("Before If: " & thisCell.Address(False, False) & "=" & thisCell.Value2 & " v. " & leftCell.Address(False, False) & "=" & leftCell.Value2)
If thisCell.Value2 >= leftCell.Value2 Then
leftCell.Value2 = cell.Value2
Debug.Print("After If: " & thisCell.Address(False, False) & "=" & thisCell.Value2 & " v. " & leftCell.Address(False, False) & "=" & leftCell.Value2)
End If
Next
End Sub
Easiest way is probably a lopp that just repeats what you are doing.
Instead of defining x and y as ranges, you would only need a count variable:
dim lastrow as integer
lastrow = Cells(Rows.count, "AE").End(xlUp).row 'counts the amount of cells you have with values in the row
for i = 2 to lastrow 'set 2 = whatever, but I guess you have header rows, if you want to start in the 4th row set it 4
if CELLS(i,31).Value >= CELLS(i,30).Value THEN 'the cell commands uses 1-indexed numbers to refer to cells on an x-y axis, rows go on the x axis so Cells(2,1) is "B1" for some reason.
'insert your loop here
Cells(i,31).Select
Selection.Copy
Cells(i,30).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End if
Next i
As you can see down, I am copy 4 columns of data from one workbook to another. I am stuck at a case where the destination has 8 columns and my area of columns are 1,2,5,7. can you suggest me some changes in the code please. The one below will work only for first 4 columns. Thanks.
Sub Copymc()
Dim x As Workbook
Dim y As Workbook
Dim rng As Range
Set x = Workbooks.Open("H:\testing\Q4 2014\US RMBS Q4.xlsx")
Set y = Workbooks.Open("H:\testing\demo\test1.xlsx")
Dim LastRow As Long
Dim NextRow As Long
x.Worksheets("RL Holdings").Activate
Range("A65536").Select
ActiveCell.End(xlUp).Select
LastRow = ActiveCell.Row
Range("A2:D" & LastRow).Copy
y.Worksheets("Sheet1").Range("a65536").End(xlUp).Offset(1, 0)
Application.CutCopyMode = False
End sub
The line Range("A2:D" & LastRow).Copy has column D hardcoded into it. This means that it will always copy A2 to D65536. If you want specific columns(A, B, E, G) then I would recommend simply repeating your code for each column.
For example
Range("A65536").Select
ActiveCell.End(xlUp).Select
Selection.Copy
y.Worksheets("Sheet1").Range("a65536").End(xlUp).Offset(1, 0).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
then copy the code four times and replace the A to whatever column you want to copy or paste to. If this isn't what you are looking for please elaborate on what you want.
I've managed to create an easy to update dashboard in Excel using VBA. It's pretty solid, but I require a weekly updated trendline to add to this data.
What i'd like is a macro that does the following:
Write data to range X (e.g. A1:A5)
Copy data from range X to Range Y (e.g. A10:A15)
And then when I run step 1 and 2 again
Write data to range X (overwrite data in X A1:A5)
Copy Data from range Y to range Y+1 (e.g. B10:B15)
repeat ad infinitum (each time moving one column to the right)
What I get is that i need to define the column line as an integer and then refer to it.
(e.g.
Sub Trend()
Dim i As Integer
i = 2
Sheets("Data").Select
Range("A1:A5").Select
Selection.Copy
Sheets("Trendline data").Select
ActiveSheet.Cells(1, i).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets("Data").Select
i = i + 1
End Sub
However repeating this macro does not increment i for me.
~~Also column 2 is filled completely with a repeat of the data in (Data!A1:A5)~~
This is fixed with an update to the code.
Pretty much what I need to fix is that The line
"Dim i As integer"
i = 2
becomes
"Dim i As integer"
i = 3
Permanently, and repeat the next time for i = 4, i = 5 etc.
After that for me it is easy to create a line chart from this range
Thank you.
edit: wrote what I thought would work, but apparently doesn't
Edited :
What about that?
Sub Trend()
Dim i as integer
If Sheets("Data").Cells(1,1).Value = "" Then
Sheets("Data").Cells(1,1).Value = 1
End if
i = Sheets("Data").Cells(1,1).Value
Sheets("Data").Select
Range("A1:A5").Select
Selection.Copy
Sheets("Trendline data").Select
ActiveSheet.Cells(1, i).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets("Data").Select
Sheets("Data").Cells(1,1).Value = i + 1
End Sub