How to drag formulas in a loop on multiple worksheets - excel

I have a workbook with around 75 worksheets, that all contain different sorts of data that get updated every month. Some of the data gets updated automatically, but in nearly every worksheet, there are formulas that need to be dragged. I need to drag the formulas down 30 rows in every worksheet.
So I want to loop through each worksheet and then through each column that contains formulas to drag. I have already marked each column to drag with the letter "F" in row 1 of the column so that I can put an IF statement to only drag those columns.
My problem now is that I do not know how to select the last cell of column with a formula in it and then drag it down 30 rows.
Sub Drag_Formulas()
'Number of Worksheets
Dim i As Integer
Dim ws_num As Integer
ws_num = ThisWorkbook.Worksheets.Count
'Number of columns
Dim c As Integer
'Loop 1
For i = 1 To ws_num
ThisWorkbook.Worksheets(i).Activate
For c = 1 To 105
If Cells(1, c).Value = "F" Then
Cells(20000, c).Select 'I used 20000 since no worksheet has data going as far as 20000, so that way I am sure to get the last cell with data
Selection.End(xlUp).Select
Selection.Copy
Else
Next c
End If
Next c
End Sub
So I got as far as copying the last cell with a formula of a column, but I do not know how to drag it down 30 rows, since with this code I do not know what row the last cell is on.
Thanks for the help!

As mentioned, currently the macro doesn't actually do anything. However, assuming your formula for each column is in row 2, and you want to drag that down to the last row in that column, you could use the following.
Sub drag()
Dim i As Long, col As Long, lastCol As Long, lastRow As Long
Dim copyRowAmt
Dim ws As Worksheet
Dim fmlaCell As Range
copyRowAmt = 30
For Each ws In ThisWorkbook.Worksheets
With ws
' This assumes your column headers are in row 1,
' to get the total number of columns dynamically
lastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
For col = 1 To lastCol
If .Cells(1, col).Value = "F" Then
lastRow = .Cells(.Rows.Count, col).End(xlUp).Row
.Range(.Cells(lastRow, col), .Cells(lastRow + copyRowAmt, col)).Formula = _
.Cells(lastRow, col).Formula
End If
Next col
End With
Next ws
End Sub
Note this also avoids using .Select`.Activate`

Related

How to traverse to each Column in the same Row in Excel VBA

I'm trying to traverse each column in the same row, I'm new to VBA and any help would be appreciated..
Here's my code:
Sub dural()
Dim i As Long
Dim j As Long
i = 2
Cells(1, i).Select
For i = 2 To Columns.Count
Cells(1, i + j).Select
'Selection.Copy
j = i + 1
Next i
End Sub
Luan Yi,
Your question states "trying to traverse each column in the same row";
the code below shows how to loop through each Column, or loop through
each cell in Row 1 and use .EntireColumn to do something; without using .Select
'Use the With statement that meets your needs
'define your variables
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1") 'change worksheet name as needed
Dim lCol As Long: lCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column 'define last used column in row 1
For i = 2 To lCol
'If you want to loop through each column, you can use...
With ws.Columns(i)
'you can do something, for example using .Delete or .Copy, etc.
End With
'or
'If you want to loop through each cell in row 1, the you can use...
With ws.Cells(1, i)
'you can do something, for example using .EntireColumn.Delete or .EntireColumn.Copy, etc.
End With
Next i

How to copy data from a cell in sheet1 to sheet2, looping through each cell?

How can I cycle through sheet1 to see if there is data in that cell?
If there is no data then go to the next cell.
If there is data in the next cell paste it into sheet2.
The criteria are:
I cannot use a set range it will change as the data changes in sheet1.
I can keep sheet names a constant such as sheet1 and sheet2.
I found a way using columns and or rows yet that code has a major issue. If there is no starting data in the first cell it will not copy anything in the entire row and or column.
I am posting the code I worked with to check the data in columns but if there is no starting data it will skip the whole row.
Sub CopytoImport()
Dim wb As Workbook
Dim iCol As Long
Dim ws As Worksheet
Sheets("sheet2").Cells.ClearContents
' Loop through the column
For iCol = 1 To 22 ' Call out columns I cannot set this every time it should look threw all cells
With Worksheets("sheet1").Columns(iCol)
' Check tht column is not empty
If .Cells(1, 1).Value = "" Then
'Nothing in this column
'Do nothing
Else
' Copy the coumn to te destination
Range(.Cells(1, 1), .End(xlDown)).Copy _
Destination:=Worksheets("sheet2").Columns(iCol).Cells(1, 1)
End If
End With
Next iCol
ActiveWorkbook.Save
End Sub
Function runcode()
Call CopytoImport
End Function
Cells(1, 1) is just RANGE.("A1") you are only operating on this cell in your code. You would need Cells(1, iCol) to account for what column you are on during your loop.
You might also need a nested loop since you are looping through rows as well. The basic outline of a nested loop is as follows. Note the Cells(1,1) is replaced with the i and j representing what row and what column we are on. This might not be the fastest way to achieve the results you want but it sounds like this is what you are asking for help with. You will also need to define a lastrow (with a + 1 at the end to get the next blank cell) in your Sheet2 for when you paste the data. You would put this right under where the loop starts going through rows. This is so the lastrow of your sheet2 is recalculated each time data is being moved to that sheet. I am not going to re-write your code since you stated it is not complete but here is an example that should help you.
For j = 5 To lastcolumn
For i = 5 To lastrow
Dim lastrow2 As Long
lastrow2 = Worksheets(1).Range("A" & Rows.Count).End(xlUp).Row + 1
If Worksheets(2).Cells(i, j).Value <> 0 Then
Worksheets(1).Range("C" & lastrow2).Value = Worksheets(2).Cells(i, j).Value
Worksheets(1).Range("B" & lastrow2).Value = Worksheets(2).Cells(2, j).Value
End If
Next i
Next j
To find your lastrow:
dim lastrow as long
lastrow = Range("A" & rows.count).End(xlup).Row ' or whatever column contains the data
To find your last column
Dim lastcolumn As Long
lastcolumn = Worksheets(2).Cells(2, Columns.Count).End(xlToLeft).Column

Insert one row between groups based on criteria in a column

I have a worksheet of data that has four columns. I want the spreadsheet to add 3 rows after each group based on column D. Column D has the department for the transactions. All department transactions are listed in a row. So Excel just needs to find the change in department and enter three rows after that section.
I have tried this code I found here. It puts a row after every line it sees the department in.
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("IMPORT-WIP") 'better define by name: ThisWorkbook.Worksheets("MySheet")
Dim LastRow_f As Long
LastRow_f = ws.Cells(ws.Rows.Count, "D").End(xlUp).Row
ws.Range("A1:D" & LastRow_f).AutoFilter Field:=12, Criteria1:="HR DEPARTMENT"
Dim FilteredData As Range
Set FilteredData = ws.Range("D2:D" & LastRow_f).SpecialCells(xlCellTypeVisible)
Dim iArea As Long
Dim iRow As Long
For iArea = FilteredData.Areas.Count To 1 Step -1 'loop from last to first area
For iRow = FilteredData.Areas(iArea).Rows.Count To 1 Step -1 'loop from last row to first row in each area
With FilteredData.Areas(iArea).Rows(iRow) '<-- this represents the current row we are in the loop
.Offset(RowOffset:=1).EntireRow.Insert Shift:=xlDown
.Offset(RowOffset:=1).EntireRow.Interior.Color = RGB(192, 192, 192)
End With
Next iRow
Next iArea
'remove filters
ws.Range("A1:D" & LastRow_f).AutoFilter
This code will insert 3 rows between groups of values (even unique values). The data does not need to be filtered. It will loop through Column D, test the cell above the current cell and, if not the same value, will insert 3 rows between them. You may have to sort the data first, depending on what you want.
Sub InsertRowsBetweenGroups()
Dim ws As Worksheet, lr As Long, i As Long
Set ws = ThisWorkbook.Sheets("Sheet1") 'Change as needed
lr = ws.Cells(ws.Rows.Count, 4).End(xlUp).Row
For i = lr - 1 To 2 Step -1
If Cells(i, "D") <> Cells(i - 1, "D") Then
Cells(i, "D").Resize(3).EntireRow.Insert Shift:=xlDown
End If
Next i
End Sub

Need some help using setting variables to determine which cells I want to select in my range

The amount of cells in my data table changes every week so I'm using a count function to determine the number of cells with data then using that count as a variable to put into my range(cells(x,x),cells(x,x) function to select. But I'm having an issue with taking the count and converting it to a variable to use. This is a basic macro I'm putting together for something else i'm doing.
Sub format_table()
Dim x As Long
Dim y As Long
''count the number of rows in rawdata table
Dim LastRow As Integer
With ActiveSheet
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
x = LasRow
''count the number of columns in rawdata table
Dim LastCol As Integer
With ActiveSheet
LastCol = .Cells(1, .Columns.Count).End(xlToLeft).Column
End With
y = LastCol
'''use the counted cells to determine a range to select
ActiveSheet.Range(Cells(1, 1), Cells(x, y)).Select
End Sub
I think you are having trouble trying to get the column number as the correct letter, right? Try something like this:
Sub Test()
Dim wb As Workbook
Set wb = ThisWorkbook
Dim ws As Worksheet
Set ws = wb.Sheets("Sheet1") '(replace with whatever sheet name is)
Dim lastRow as Integer, lastCol as Integer, lastColLet as Integer
'get the number value of the last row and column
lastRow = ws.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
lastCol = ws.Cells.Find("*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column
'uncomment the debug.print statements to see what it's getting for last row/column
'Debug.Print lastRow
'Debug.Print lastCol
'get the letter that the column number corresponds to
lastColLet = Letter(lastCol)
'Debug.Print lastColLet
ws.Range("A1:" & lastColLet & lastRow).Select
End Sub
Function Letter(ByVal lngCol As Long) As String
Dim vArr
vArr = Split(Cells(1, lngCol).Address(True, False), "$")
Letter = vArr(0)
End Function
It uses the function found here: Function to convert column number to letter? in order to convert the column # to a letter, then you can concat the letter and last row to select the way you wanted.
I guess your real issue is to decide what cells you actually need to select
your approach assumes that the left-upmost data cell is always in cell(1,1) and the down-right one is in the intersection of:
last non empty row in column 1, last non empty column in row 1
should that be the case, then you can go on with your code provided you change x = LasRow to x = LastRow...
should not that be the case then you could assume that the range is the one delimited by:
first non empty row in column 1, first non empty column in row 1
last non empty row in column 1, last non empty column in row 1
then you could use this code:
Function GetData() As Range
Dim firstRow As Long, firstColumn As Long
Dim LastRow As Integer, lastColumn As Long
With ActiveSheet
firstRow = .UsedRange.Rows(1).Row '<--| get first used row index
firstColumn = .UsedRange.Columns(1).Column '<--| get first used column index
LastRow = .Cells(.Rows.Count, firstColumn).End(xlUp).Row '<--| get the first used column last non empty cell row index
lastColumn = .Cells(firstRow, .Columns.Count).End(xlToLeft).Column '<--| get the first used rows last non empty cell column index
'return the range
Set GetData = .Range(Cells(firstRow, firstColumn), Cells(LastRow, lastColumn))
End With
End Function
and exploit it in your main code as follows:
Sub format_table()
With GetData '<-- use With-End With block to reference wanted object (Range) and avoid Select/Selection/Activate/ActiveXXX
'format the referenced range
.Font.Name=..
.Interior.Color=..
End With
End Sub
but the GetData() function may still be not the one you need, should data be "jagged" in columns and or/rows with first row/column not hosting the last column/cell
so maybe you simply need:
Sub format_table()
With ActiveSheet.UsedRange
'format the referenced range
' .Font.Name=..
' .Interior.Color=..
End With
End Sub

Find, copy and paste all possible values of a cell range

I have a row of cells (the row elements may vary) and another sheet with several columns of data. Let's say on sheet 1 we have 7 columns with data(first column with titles) and on sheet 2 we have some of those titles transposed on the first row. The task is to find all possible values for each title in sheet 2. Let's say in sheet 2 on the first cell we have title X, then I need to find all values corresponding to title X in sheet 1 and to take out the results from the 8th column of sheet 1. then do the same for cell 2 in sheet 2 and so on till the end of the row.
Can someone share a hint or any suggestions that might help me.
Actually I used the following code:
Sheets("sheet2").Select
Dim Lcola As Long
Dim rng As Range
With ActiveSheet
Lcola = .Cells(1, .Columns.Count).End(xlToLeft).Column
Set rng = .Range(.Cells(2, 1), .Cells(2, Lcola))
With rng
Range("A2").Select
ActiveCell.Formula = "=VLOOKUP(A$1,MAP!$A$1:$I$" & lRowc & _
",8,FALSE)"
Selection.AutoFill Destination:=rng, Type:=xlFillDefault
End With
End With
The thing is that I'm not sure how to repeat the function several times, or as much repetitions as I have on each variable from sheet 2 in sheet 1. And another issue that I'm facing is the vlookup function always gives me the first found item.
Use a For loop, with your last Column from Sheet2 as your counter Max.
use iCol to keep track of which Column on Sheet2 you are copying and reading from.
use iRow to keep track of which ROW has the data you want on Sheet1.
Since you know you need the 8th column on the Sheet 1, it will always be Sheets("Sheet1"),Cells(iRow, 8)
and since you know the ROW that the column headers are located in Sheet2, Sheets("Sheet2"),Cells( 1, iCol) - if the header row is 1.
Then just grab a LastRow check on the Sheet2 Column in question and add to it one at a time.
Dim iCol As Integer
Dim lastCol As Integer
Dim lastRow1 As Integer
Dim lastRow2 As Integer
Dim matchRow As Integer
Dim tempVal As String
Dim iRow As Integer
Dim nRow As Integer
Private Sub IndexMatchLoop()
lastCol = Sheets("Sheet2").Cells(1, Columns.Count).End(xlToLeft).Column
For iCol = 1 To lastCol
'Assuming your row on Sheet2 is 1.
tempVal = Sheets("Sheet2").Cells(1, iCol)
iRow = 1
Call GetLastRow
nRow = lastRow2 + 1
'Looks up the value from Sheet2 Column Header on Column1 of Sheet1 one Row at a Time
For iRow = 1 to lastRow1
If Sheets("Sheet1").Cells(iRow, 1) = tempVal Then
'Copy the data from Sheet1 Column 8 in the Rows with the value to Sheet2, the nextRow of the Col
Sheets("Sheet2").Cells(nRow, iCol) = Sheets("Sheet1").Cells(iRow, 8)
nRow = nRow + 1
End If
Next iRow
Next iCol
End Sub
Private Sub GetLastRow()
lastRow1 = Sheets("Sheet1").Cells(65532, 1).End(xlUp).Row
lastRow2 = Sheets("Sheet2").Cells(65532, iCol).End(xlUp).Row
End Sub
EDIT: typo in formula (was relying on autoComplete for "Int" instead of "Integer"
EDIT: Adding Screenshots

Resources