Excel VBA formula's not updating row - vba

So my code is to insert a row, copy its format from the previous row, and then insert the formulas that I have preset on a different row. So lets say I insert a new row, row 11, the formula should copy row 10's formats and insert the formulas from row 44 (which I designated as my formula row).
Now, the formulas will all reference row 10 instead of row 11. I'm not sure why that is.
Here is my code:
Dim i As Integer
'loop through position sheets and insert blank rows
For i = 1 To 4
Sheets(i).Select
Rows(row_to_insert).EntireRow.Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Next i
'loop through sheets and copy/paste formulas into new rows
For i = 1 To 4
Sheets(i).Select
Rows(blank_row_to_use + 1).EntireRow.Select
Selection.Copy
Rows(row_to_insert).EntireRow.Select
ActiveSheet.Paste
Next I
End Sub
This worked fine until I added a new sheet, and expanded from For i = 1 To 3 to For i = 1 to 4.
Any ideas why it suddenly stopped working?

the issue lays in those relative references to another sheet that don't get updated by any rows shifts taking place in the sheet where they are used
while they'd get updated if you shifted rows in the sheet they are referencing
so you have to play a little bit with relative /absolute references to mimic some referenced sheet rows shifting, but without doing it!
for instance you could use a Function that converts some range formulas to absolute or relative reference type, like the following:
Sub Convert(rng As Range, toReferenceType As XlReferenceType)
Dim cell As Range
For Each cell In rng.SpecialCells(XlCellType.xlCellTypeFormulas) ' loop thorugh passed range relevant cells (i.e. those containing formulas)
If InStr(cell.Formula, "!") > 0 Then cell.Formula = Application.ConvertFormula(cell.Formula, xlA1, xlA1, toReferenceType) ' if current cell has an explicit sheet reference, then convert its formula to the passed reference type
Next
End Sub
and the use it in your code
For i = 1 To 1
With ThisWorkbook.Sheets(i)
.Rows(blank_row_to_use).Copy .Rows(blank_row_to_use + 1) ' copy formulas "template" row one "helper" row below
Convert .Rows(blank_row_to_use + 1), xlAbsolute ' convert "helper" row formulas with some explicit sheet reference to absolute type so they don't get updated by any subsequent row shift
.Rows(blank_row_to_use + 1).Copy .Rows(blank_row_to_use) ' copy "helper" row converted formulas and paste them back to formula "template" row -> now you have a formula with an absolute row reference one below its own row
.Rows(blank_row_to_use + 1).ClearContents ' clear "helper" row
.Rows(row_to_insert).Insert Shift:=xlDown, opyOrigin:=xlFormatFromLeftOrAbove ' insert new row -> formulas "template" row references don't get updated and now you have a formula with an absolute row reference to its own row
Convert .Rows(blank_row_to_use + 1), xlRelative ' convert formulas "template" row formulas with some explicit sheet reference to relative type so they do get updated by any subsequent row shift
.Rows(row_to_insert).EntireRow.Formula = .Rows(blank_row_to_use + 1).EntireRow.Formula ' copy formulas "template" row formulas row to the new row and have them updated
End With
Next
Please note also that
.Rows(row_to_insert).EntireRow.Formula = .Rows(blank_row_to_use + 1).EntireRow.Formula
is better than any Copy and subsequent PasteSpecial approach in that it doesn't use the clipboard

Try the much shorter and cleaner version of what you are trying to achieve.
Note: try to avoid using Select, Selection and ActiveSheet, and use fully qualified Sheet objects.
Modified Code
'loop through position sheets and insert blank rows
For i = 1 To 4
With ThisWorkbook.Sheets(i)
.Rows(row_to_insert).Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
.Rows(blank_row_to_use + 1).EntireRow.Copy
.Rows(row_to_insert).EntireRow.PasteSpecial xlPasteFormulas
End With
Next i

Related

Loop through column values from one sheet and paste COUNTIF value from another column into another sheet

I have two sheets in an Excel file and need to perform a COUNTIF formula from one sheet and paste the respective information in another sheet. The original sheet just has the type in 1st column with an empty 2nd column. I am trying to loop through the Type from Sheet 1, in each increment loop through the Type from Sheet 2, and past the Count of column 2 from Sheet 2 into Column 2 of sheet 1.
My current VBA code is as follows:
Sub TestOE()
'For loop to go until end of filled cells in 1st column of each sheet
a = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
b = Worksheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row
'Loop
For i = 2 To a
For j = 2 To b
If Worksheets("Sheet1").Cells(i, 1).Value = Worksheets("Sheet2").Cells(j, 1).Value Then
Worksheets("Sheet1").Cells(i, 2).Value = Application.WorksheetFunction.CountIf(Range("B:B"), 1)
End If
Next j
Next i
End Sub
This code is only pasting 0's in the desired outcome on Sheet 1.
Sheet to extract information from
Sheet to paste information in
Desired Outcome in destination sheet
You can simply use sumif function to sum the values based on criteria.
here is the formula
=COUNTIF(Sheet1!$A$2:$A$20,Sheet2!A2)
if you want to sum the col B then
=SUMIF(Sheet1!$A$2:$A$20,Sheet2!A2,Sheet1!$B$2:$B$20)
In a few steps, you can accomplish what you want without VBA, and just use a pivot table. Just do as follows.
Select your data set, including the header.
Click on insert tab, then PivotTable. See example for Office 365
Since you want a different worksheet, set PivotTable to be "New Worksheet" See example.
You'll need to drag the TYPE field into the rows, and binary into the values. CountIF is the same as summing binary, so you can leave as sum. See Example
And you'll have an output nearly identical to what you're looking for:

Excel vba - paste below header

I need to copy a column from one workbook to another.
y.Sheets("data").Range("A2:A1048576").Clear 'delete contents of target columns first
x.Sheets("file").Range("C:C").Copy 'copy column from another sheet
y.Sheets("data").Range("A1").End(xlDown).Offset(1, 0).PasteSpecial xlPasteValues
I'm trying to paste it to starting from A2 since A1 is my header.
I'm getting a application-defined or object-defined error
It's best practice not to reference entire columns (some million cells) when you don't need to:
With y.Sheets("data") ' reference sheet "data" in workbook 'y'
.Range("A2", .Cells(.Rows.Count, "A").End(xlUp)).ClearContents ' clear 'referenced sheet column "A" cells from row 2 down to last not empty one
End With
With x.Sheets("file") ' reference sheet "file" in workbook 'x'
With .Range("C1", .Cells(.Rows.Count, "C").End(xlUp)) 'reference referenced sheet column "C" cells from row 1 down to last not empty one
y.Sheets("data").Range("A2").Resize(.Rows.Count).Value = .Value ' paste referenced range values to workbook "y" sheet "data" starting from cell A2
End With
End With
Or the following
With y.Sheets("data")
Intersect(.UsedRange, .Columns("A")).Clear
Intersect(x.Sheets("file").UsedRange, x.Sheets("file").Columns("C")).Copy .Range("A2")
End With
The issue here is you copy a complete column Range("C:C").Copy and that means you have to paste to a complete column otherwise it would not fit in and exceed Excel's maximum row count.
Therefore I suggest to copy only that part of column C that contains data:
With x.Sheets("file")
.Range("C1", .Cells(.Rows.Count, "C").End(xlUp)).Copy
End With
This copies only from C1 to the last used cell. And then you can paste it directly to A2
y.Sheets("data").Range("A2").PasteSpecial xlPasteValues

VBA Excel Copy and Insert Varying Number of Rows with Values and Formatting

I am attempting to write a macro that would work for various worksheets. These are updated on a monthly basis. In these worksheets we have between 30 and 100 rows at the top of the sheet with formulas regarding the current month. Below we have all of the previous months numbers but without formulas.
Each month we copy the top set of rows and insert them as values w/ same formatting below the rows with formulas so that we may start the month again, but have a record of last months numbers.
In summary, I need all of the columns, and (X number of rows) copied and inserted starting in row (X+1) as only the values and formatting. Also row (X+1) is not the end of the sheet.
I have some start on the code below, but the first column does contain blank values.
Sub MonthlyReset()
Dim TotalImpacts As Worksheet
Dim LastImpacts As Range
Dim Counter As String
Set TotalImpacts = Worksheets("Total Impacts")
Counter = Application.WorksheetFunction.Match("STOP", ThisWorkbook.Sheets(TotalImpacts).Column(1), 0)
LastImpacts = ThisWorkbook.Sheets(TotalImpacts).Rows("1:" & Counter)
Rows(Counter).Resize(Counter).Insert
'Copying Impacts
ThisWorkbook.Sheets(TotalImpacts).LastImpacts.Copy
'Paste Values then Formatting
ThisWorkbook.Sheets(TotalImpacts).Range("A" & Counter + 1).PasteSpecial Paste:=xlPasteValues
ThisWorkbook.Sheets(TotalImpacts).Range("A" & Counter + 1).PasteSpecial Paste:=xlPasteFormats
'Clear Clipboard
Application.CutCopyMode = False
End Sub
This isn't the most efficient way, but inserting entire rows can be a pain in excel, interestingly enough. But trying to be true to your original ideas, this should work.
Sub MonthlyReset()
Dim TotalImpacts As Worksheet
Dim LastImpacts As Range
Dim Counter As String
'Set the worksheet we are working with
Set TotalImpacts = Worksheets("Total Impacts")
'Find the row that STOP is on
Counter = Application.WorksheetFunction.Match("STOP", TotalImpacts.Columns(1), 0)
'Set the range for the data we want to copy
Set LastImpacts = TotalImpacts.Rows("1:" & Counter)
'Copy and insert
LastImpacts.Copy
LastImpacts.Offset(Counter).Insert shift:=xlShiftDown
'Paste Values then Formatting
TotalImpacts.Range("A" & Counter + 1).PasteSpecial Paste:=xlPasteValues
TotalImpacts.Range("A" & Counter + 1).PasteSpecial Paste:=xlPasteFormats
'Clear Clipboard
Application.CutCopyMode = False
End Sub
In the end, the range is pasted twice, the first time with the formulas to be able to insert the correct amount of rows. The second time is to paste values and then formulas alone, as you had done in your original code.

How to copy and paste always one row below

I have been working on code to copy and paste from one worksheet to another. The data that I need to copy will always be at A1:E1, however, I need to always paste one row below. I will run it everyday, so for instance if today I paste on cells A1:E1, then tomorrow I would need to paste on A2:E2 and on the next day A3:E3... I wrote the code below which works but is not as dynamic as I need it to be. I would appreciate your help
Thank you
Sub Copy_range()
Worksheets("Dividends").Range("A1:E1").copy
Worksheets("Draft").Range("A1:E1").PasteSpecial
End Sub
This will make it more modular by skipping down past all used cells then pasting the value on the next empty cell.
Sub Copy_range()
' edit line below to change where data will be copied from
Worksheets("Dividends").Range("A1:E1").Copy ' copy the value
' select the first cell on the "Draft" sheet
Worksheets("Draft").Select
ActiveSheet.Range("A1").Select
Dim count As Integer
count = 1
'skip all used cells
Do While Not (ActiveCell.value = None)
ActiveCell.Offset(1, 0).Range("A1").Select
count = count + 1
Loop
' edit line below to change alphabetical values of where data will be placed
Worksheets("Draft").Range("A" & count & ":E" & count).PasteSpecial ' paste the value
' at Acount:Ecount where count is the current row i.e. A11:E11
End Sub

Looking to select an undetermined number of rows in excel as part of larger VBA macro

I'm working with an excel book containing a large number of sheets; the first sheet is linked to an external program and pulls in data via an external function, and the number of lines imported varies significantly.
This block data is the disseminated over a number of subsequent sheets. The first step has been to populate column A (row name) with the number of rows in sheet 1. From here the data is split over a number of columns (currently B->L). The top row uses an IF() function to populate the first row, and I'm looking to write a clean macro to copy this formula to row x (which varies with each data import refresh) and then paste values for a manageable file size.
Here's what I've got so far; it works, but it's fairly (read: VERY!) clumsy:
Sub Refresh_Data()
Sheets("Sheet2").Select
ActiveWindow.ScrollWorkbookTabs Sheets:=13
Sheets(Array("Sheet2" ... "Sheet25")).Select
Sheets("Sheet2").Activate
Sheets("Sheet25").Select Replace:=False
Range("B1:L1").Select
Selection.Copy
Range("__B2:B1000__").Select
ActiveSheet.Paste
Application.Calculate
ActiveWindow.ScrollWorkbookTabs Position:=xlFirst
Sheets(Array("Sheet2" ... "Sheet25")).Select
Sheets("Sheet2").Activate
Sheets("Sheet25").Select Replace:=False
Sheets("Sheet2").Select
Range("B3").Select
Sheets(Array("Sheet2" ... "Sheet25")).Select
Sheets("Sheet2").Activate
Sheets("Sheet25").Select Replace:=False
Range("B3:L4").Select
Range("__B2:L1000__").Select
Application.CutCopyMode = False
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Sheets("Check_sheet").Select
MsgBox "Update complete"
End Sub`
The main thing I'm looking to achieve is to replace the code B2:L1000 with something that can assess the number of rows in column A and select a range in rows B to L accordingly.
Since column L is the last populated column, I don't see why this can't also be done horizontally rather than defining "B:L" incase future columns need to be added.
Although the earlier answer has merits:
1) I would not use COUNTA because if there are empty cells in the row or column, the cells at the bottom or the right will be ignored.
2) I would never rely on the user picking the correct sheet to be used before running a macro; particularly one with so many sheets.
My reaction to the question is that you have set Macro Record, wandered around your workbook and then stopped the record. You select one thing, then another. You scroll through the sheets. To me most of the statements are not clumsy they are pointless.
The following does include an answer to your question about finding the last row of column A but it is more a tutorial about finding the dimensions of a range, getting data out of the range and then putting it somewhere else. This seems to be most of what you are trying to do with the most minimal understanding of VBA. I am sorry if this criticism is unfair but that is the impression your question gives to me.
Sub Test()
Dim RowS01Max As Integer
Dim Sheet1Data() As Variant
' With Sheets("Sheet1") allows you to access data within worksheet Sheet1
' without selecting it.
' Range("A1:C11") refers to a range within the active sheet
' .Range("A1:C11") refers to a range within the sheet identified in the
' With statement.
' ^ Note the dot
With Sheets("Sheet1")
' Rows.Count is the number of rows for the version of Excel you are using.
' .Cells(Rows.Count, "A") address the bottom row of column A of worksheet
' Sheet1.
' .Cells(Rows.Count, 1) refer to column A by number.
' End(xlUp) is the VBA equivalent of Ctrl+Up.
' If you positioned the cursor at the bottom of column A and pressed
' Ctrl+Up, the cursor would jump to the last row in column A with a value.
' The following statement gets that row number without actually moving
' the cursor.
RowS01Max = .Cells(Rows.Count, "A").End(xlUp)
' The following statement loads the contents of range A1:C11 of
' Sheets("Sheet1") into array Sheet1Data.
Sheet1Data = .Range("A1:C11").Value
' This is the same statement but the range is specified in a different way.
' .Cells(Row,Column) identifies a single cell within the sheet specified in
' the With statement. .Cells(1,1) identifies row 1, column 1 which is A1.
'. Cells(11, "C") identifies row 11, column C which is C11.
Sheet1Data = .Range(.Cells(1, 1), .Cells(11, "C")).Value
' This statement uses RowS01Max to specify the last row
Sheet1Data = .Range(.Cells(1, 1), .Cells(RowS01Max, 1)).Value
' In all three examples above, the contents of the specified range will
' be loaded to array Sheet1Data. Whichever range you pick, Sheet1Data
' will always be a two dimensional array with the first dimension being
' the row and the second dimension being the column.
' In the first two examples Sheet1Data(5,3) contains the contents
' of cell C5. In the third example, I have only loaded column A but the
' array will still has two dimensions but the only permitted value for the
' second dimension is 1.
' The following statement writes the contents of Sheet1Data to column "E"
.Range(.Cells(1, 5), .Cells(RowS01Max, 5)).Value = Sheet1Data
End With
With Sheets("Sheet2")
' The following statement writes the contents of Sheet1Data to column "E"
' of worksheet Sheet2.
.Range(.Cells(1, 5), .Cells(RowS01Max, 5)).Value = Sheet1Data
End With
End Sub
Don't despair! Most of us started with the macro recorder and still use it to discover the syntax for an unfamiliar command. Look through other questions. Some ask about exotic functionality but many are about moving data around in, to the experienced programmer, simple ways. Set up some workbooks with the questioner's problem. Copy and paste the solution into a module. Step through it using F8 (see the debugger), switch between Excel and Editor, watch what is happening to the worksheet and move the cursor over a variable to see its current value. Spend half a day playing. You will be amazed at how quickly it starts to make sense. Good luck and good programming.
The following should do the trick:
Sub Refresh_Data()
Dim lastRow As Integer
Dim lastCol As Integer
Dim entireRange As Range
Dim targetRange As Range
lastRow = Excel.Evaluate("COUNTA(A:A)") ''// count the rows in column A
lastCol = Excel.Evaluate("COUNTA(1:1)") ''// count the columns in row 1
Set entireRange = Range(Cells(1, 2), Cells(lastRow, lastCol))
Set targetRange = Range(Cells(2, 2), Cells(lastRow, lastCol))
entireRange.FillDown
Application.Calculate
targetRange.Copy
targetRange.PasteSpecial Paste:=xlPasteValues
End Sub
Notes:
Excel.Evaluate(...) allows you to use the result of worksheet functions in your VBA macros.
COUNTA(range) is a worksheet function that counts the number of non-blank cells in a given range. In this case, it can be used to determine the total number of rows in your data set, as well as the number of columns in row 1 that have a formula in them.