Range function sending data to wrong row - excel

I'm trying to add data to a worksheet, and while I know I've set up the Range function "correctly" (for a value of correctly that includes "worked every other time"), instead of labeling row 1 it's labeling row 2, and shifting the calculations in row 2 down to row 3. This is a problem only with this module in this worksheet.
I've tried the debugging tools, but they don't change the outcome or break anywhere. The first row hidden, nor is it frozen. And this happens whether or not I append ".value" after the range calls.
Weirdly, the second set of labels and calculations (starting at "With Calcs.UsedRange") are ending up in the correct cells. Code below:
Sub CalcGDD()
'Initialize
Dim nb As Workbook
Dim Clim, Vars, CC, Calc As Worksheet
Dim LRow, RowL As Long
'Setup
Set nb = ActiveWorkbook
Application.ScreenUpdating = False
Set Vars = nb.Sheets("Variables")
Set CC = nb.Sheets("CoverCrop")
Set Calcs = nb.Sheets("Summary")
Set Clim = nb.Sheets("Climate")
'Calculations in Climate Sheet
With Clim.UsedRange
LRow = Cells(Rows.Count, "A").End(xlUp).Row
.Range("H1") = "Plant Day"
.Range("I1") = "Harv Day"
.Range("J1") = "Fall GDDs"
.Range("K1") = "Spring GDDs"
.Range("H2:H" & LRow & "").FormulaR1C1 = (...calculations elided...)
End With
'Summarize
RowL = CC.Cells(Rows.Count, "A").End(xlUp).Row
With Calcs.UsedRange
.Range("A1") = "Year"
.Range("B1") = "Fall GDD"
.Range("C1") = "Spring GDD"
.Range("D1") = "Total GDD"
.Range("A2:A" & RowL & "").FormulaR1C1 = (...calculations elided...)
End With
End Sub
Any ideas why Range("H1") is printing to H2? Thanks much.

The .UsedRange is likely offsetting your addressing. Remove it in both With statements. If the UsedRange starts in row 2, then "A1" in that range refers to the top-left cell in that range. If you want to write to absolute cell address A1 (i.e. not relative to where UsedRange starts), work off the actual worksheet cells instead.
'Calculations in Climate Sheet
With Clim.UsedRange
LRow = Cells(Rows.Count, "A").End(xlUp).Row
That Cells call is implicitly going against whatever the ActiveSheet happens to be. Qualify it with the Worksheet object you mean to work with - in this case, most likely the With block variable:
'Calculations in Climate Sheet
With Clim
LRow = .Cells(Rows.Count, "A").End(xlUp).Row
See if Rubberduck (free, open-source VBIDE add-in project I manage) can spot more implicit ActiveSheet references (and other potential issues in your code, like these implicit Variant variables:
Dim Clim, Vars, CC, Calc As Worksheet
Dim LRow, RowL As Long
Also:
And this happens whether or not I append ".value" after the range calls
That's because the .Value member call is implicit if it's not specified.

Related

Copy last row between A and I to row below

I'm trying to look for the last row of data between column A and I and then duplicate the value to the row below which is empty.
Every time I run it, Excel crashes
Sub insert_row()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
LastRow = LastRow
Dim lastrow_start As String
Dim lastrow_end As String
lastrow_start = "A" & LastRow
lastrow_end = "I" & LastRow
Dim lastrowregion As String
lastrowregion = lastrow_start & ":" & lastrow_end
Dim lastrowrange As Range
Set lastrowrange = Range(lastrowregion)
Dim rng As Range
Set rng = Range(lastrow_start)
Do While (rng.Value <> "")
rng.Offset(1).insert
lastrowrange.Copy rng.Offset(1)
Set lastrowrange = rng.Offset(2)
Loop
End Sub
Is it just copying too much and causing a crash? It's only nine columns and they're all text apart from one cell which is a shape (button).
You are trying to set a String to a range object. To get the range use:
Set rng = Range(lastrowregion)
The Range you are getting is A2:I2. So your Do While will error because rng.Value is actually returning an Array. You could either loop through either the Range or the Array at that point if you intended on it being multiple cells.
If the goal is simply to copy the last row of data down one row then this method can be much simpler. You can simply set the Offset to equal the value of the last row. Since they are the same size it will just work.
To show this I used CurrentRegion but you could also do it with your A2:I2 Range.
Public Sub copyLastRowDown()
Dim region As Range
Set region = ThisWorkbook.Worksheets("Sheet1").Range("A1").CurrentRegion
With region.Rows(region.Rows.Count)
.Offset(1).Value = .Value
End With
End Sub
Additional Notes
Use Option Explicit to ensure all variables are explicitly declared.
Declare and assign variables next to where they are going to be used, but place them in a reasonable place.
Do not use underscore case as this has special meaning with events and interfaces.

trouble declaring a variable as a specific cell on a worksheet

Very new to VBA. i am having trouble declaring a variable as a specific cell on a worksheet.
I have tried defining the cell by rows and columns but when I put a watch on the line it says Value is out of context. The variable is testname and it is in cell E2 of the worksheet I have set as the variable raw.
Sub findcomponents()
Dim raw As Worksheet
Dim res As Worksheet
Dim temp As Worksheet
Dim testname As String
Dim finalrow1 As Integer
Dim finalrow2 As Integer
Dim i As Integer
Set raw = Worksheets("rawdata")
Set res = Worksheets("resultcomponents")
Set temp = Worksheets("uploadtemplate")
testname = raw.Range("E2").Value
finalrow1 = raw.Range("A10000").End(xlUp).Row
finalrow2 = res.Range("A10000").End(xlUp).Row
For i = 2 To finalrow2
If res.Cells(i, 4) = testname Then
Range(Cells(i, 2), Cells(i, 4)).Copy
temp.Range("A10000").End(xlUp).Cells("A2").Paste
End If
Next i
End Sub
I expect the value to be the string in the E2 cell
Edit: I added the rest of the code. When I run it doesn't do anything.
It is supposed to take the string testname and loop through a list on the res worksheet and return the matches. I put a watch on the testname line because i thought it would show me that it was comparing the correct string and the Value in the watch line says
yes the paste line is incorrect. I also tried temp.Range("A10000").End(xlUp).Offset(1, 0).Paste and this makes it angry also.
The fix works with an edit on the worksheet name. But there is more than 1 match on the res worksheet. That is why I thought finding the the last row (but I should have offset 1 row) would return all the matches. This does work to return all values.
temp.Range("A10000").End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
Is there a better way to do this not using Range("A10000").End(xlUp)?
Your key problem is with the paste statement.
You can use one of the two following methods to paste (although it should be noted that there are others)
Range.Copy PasteRange
or
Range.Copy
PasteRange.PasteSpecial (paste type (values, formats, etc.))
This has also been updated with more standard variable blocks/variable names for Last Row calculations. Also, notice that I have also updated the Last Row calculation to be a little more dynamic. Lastly, swapping Integer for Long
Option Explicit
Sub findcomponents()
Dim raw As Worksheet: Set raw = ThisWorkbook.Sheets("rawdata")
Dim res As Worksheet: Set res = ThisWorkbook.Sheets("resultcomponents")
Dim temp As Worksheet: Set temp = ThisWorkbook.Sheets("uploadtemplate")
Dim testname As String
Dim LR1 As Long, LR2 As Long, LR3 As Long, i As Long
LR1 = raw.Range("A" & raw.Rows.Count).End(xlUp).Row '<-- This variable is never used??
LR2 = res.Range("A" & res.Rows.Count).End(xlUp).Row '<-- Updated for standard Last Row (LR) calculation
For i = 2 To LR2
If res.Cells(i, 4) = raw.Range("E2") Then
res.Range(res.Cells(i, 2), res.Cells(i, 4)).Copy '<-- Qaulified Ranges!!
LR3 = temp.Range("A" & temp.Rows.Count).End(xlUp).Offset(1).Row
temp.Range("A" & LR3).PasteSpecial xlPasteValues '<-- Correct Paste Method
End If
Next i
End Sub
The naming conventions used are just my preference. To an extent, you are free to name variables however you see fit

unintended autonomous changing a1 / r1c1 notation in vba excel 2010

i have an excel/vba issue which seems to occur in excel2010 but not excel2016. for me it is a non comprehensible conversion between a1 and r1c1 notation.
i have a range that is dynamic
Dim rng As Range
rng = Application.Range("worksheet!A4:A" & _
Worksheets("worksheet").Range("A" & rows.Count).End(xlUp).Row
also i have a name-variable (called "Norm") i use as a dropdown option in cells and would like to update it according to the dynamic range using
With Application.Names("Norm")
.Name = "Norm"
.RefersTo = rng.Address
.Comment = ""
End With
both run on Workbook_BeforeSave.
when saving while in vba editing mode everything works as expected, the name-variable has the correct range in a1-notation and the content of Norm is according to the range.
but saving in pure excel-mode results in the range in r1c1-notation which can not be processed by the name-variable leaving it empty. unfortunately i can't find any explanation or solution for that. is this an excel2010 issue or what can i do about that?
Range is a member of worksheet.
Names us a member of workbook.
You Set a range object.
RefersTo should point to the range object, not its address.
Revised code:
Dim rng As Range
WITH THISWORKBOOK.WORKSHEETS("worksheet")
SET rng = .Range(.cells(4, "a"), .cells(.rows.count, "a").end(xlup))
end with
With thisworkbook.Names("Norm")
.Name = "Norm" 'totally redundant, it already has a name identified in the line above
.RefersTo = rng 'no address, just rng
.Comment = ""
End With
Name has two properties RefersTo and RefersToR1C1, which means that you should assign appropriate address style. If you want to be sure you get correct notation, you should use ReferenceStyle parameter:
Names("Norm").RefersTo = "=" & Range("A1").Address(ReferenceStyle:=xlA1)
Names("Norm").RefersToR1C1 = "=" & Range("A1").Address(ReferenceStyle:=xlR1C1)
First, you are not setting your rng object correctly:
rng = Application.Range("worksheet!A4:A" & _
Worksheets("worksheet").Range("A" & rows.Count).End(xlUp).Row
should give you an error, you need to Set your rng object, see code below:
Dim Sht As Worksheet
Dim Rng As Range, LastRow As Long
' set the worksheet object
Set Sht = ThisWorkbook.Worksheets("worksheet")
With Sht
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row ' get last row with data in column A
' set the Range object
Set Rng = .Range("A4:A" & LastRow)
End With
' updating the range that "Norm" refres to
With ThisWorkbook.Names("Norm")
.RefersTo = Rng
End With

Copy/Paste dynamic range

Starting from Sheet "DATA" range B4:Hx, where x is my last row taking by a row count. I need to copy this range and paste it as values on sheet "bat" starting at A1.
Going forward I need to offset columns in 6. So my second copy will be I4:Ox and so one copying appending into bat sheet.
I know where I must stop and I'm informing it using the Funds value.
The first error I'm having is when I try set Column2 = Range("H" & bottomD) value that is giving me "overflow".
And sure I don't know yet if my For loop would work.
Sub Copy_bat()
Dim bottomD As Integer
Dim Column1 As Integer
Dim Column2 As Integer
Dim i As Integer
Dim Funds As Integer
Funds = Sheets("bat").Range("u3").Value
Sheets("DATA").Activate
bottomD = Range("A" & Rows.Count).End(xlUp).Row
Column1 = Range("B4")
Column2 = Range("H" & bottomD)
For i = 1 To Funds
Range(Column1 & ":" & Column2).Copy
Sheets("Data").Cells(Rows.Count, "A").End(xlUp)(2).PasteSpecial Paste:=xlPasteValues, SkipBlanks:=True, Transpose:=False
Column1 = Colum1.Range.Offset(ColumnOffset:=6)
Column2 = Colum2.Range.Offset(ColumnOffset:=6)
Next i
End Sub
Always use Option Explicit at the beginning of every module to prevent from typos. Always! You had typos at the bottom - Colum1 and Colum2.
Avoid Activate and Select (you had Sheets("DATA").Activate) - better performance, smaller error chance. Instead, you should always explicitly tell VBA which sheet you are referring to.
While pasting values you can simply do something like Range2.value = Range1.value. No need to .Copy and then .Paste.
I did my best to understand what you need. From my understanding you did not use Range data type, while you needed that. This caused you errors.
Option Explicit
Sub Copy_bat()
Dim bottomD As Integer
Dim i As Integer
Dim Funds As Integer
Dim rngArea As Range
Funds = Sheets("bat").Range("u3").Value
With Sheets("Data")
bottomD = .Range("A" & .Rows.Count).End(xlUp).Row
Set rngArea = Range(.Range("B4"), .Range("H" & bottomD))
End With
For i = 1 To Funds
Sheets("bat").Cells(Rows.Count, "A").End(xlUp)(2).Resize(rngArea.Rows.Count, rngArea.Columns.Count).Value = _
rngArea.Value
Set rngArea = rngArea.Offset(, 7)
Next
End Sub
I made one rngArea variable of type Range instead of 2 variables (Column1 and Column2). This code takes info from "Data" sheet and puts that to "bat" sheet. Then offsets to right by 7(!) columns in "Data" sheet and puts data in "bat" sheet below the data that was put previously.

VBA to add totals and formula to multiple sheets

I have an excel sheet with around 200 work sheets each containing a list of products sold to a company.
I need to add
A total at the bottom of row D-G where the bottom can be a different value. I.E. E4
below the total a formula based on the total. I.E. if E4 (being the bottom of the above row) is below $999 the display text "samples", if between 1000-3000 then multiply E4 by 2%, 3001-7500 x 5% etc.
I need to be able to add it to the entire workbook easily using vba. Since I must do this to numerous ss it would literally save me 15-20 hours a month.
Edit:
So I have something that seems to be the right path.
Sub Split_Worksheets()
Dim rRange As Range, rCell As Range
Dim wSheet As Worksheet
Dim wSheetStart As Worksheet
Dim strText As String
Set wSheetStart = ActiveSheet
wSheetStart.AutoFilterMode = False
'Set a range variable to the correct item column
Set rRange = Range("A1", Range("A65536").End(xlUp))
'Delete any sheet called "UniqueList"
'Turn off run time errors & delete alert
On Error Resume Next
Application.DisplayAlerts = False
Worksheets("UniqueList").Delete
'Add a sheet called "UniqueList"
Worksheets.Add().Name = "UniqueList"
'Filter the Set range so only a unique list is created
With Worksheets("UniqueList")
rRange.AdvancedFilter xlFilterCopy, , _
Worksheets("UniqueList").Range("A1"), True
'Set a range variable to the unique list, less the heading.
Set rRange = .Range("A3", .Range("A65536").End(x2Up))
End With
On Error Resume Next
With wSheetStart
For Each rCell In rRange
strText = rCell
.Range("A1").AutoFilter 1, strText
Worksheets(strText).Delete
'Add a sheet named as content of rCell
Worksheets.Add().Name = strText
'Copy the visible filtered range _
(default of Copy Method) and leave hidden rows
.UsedRange.Copy Destination:=ActiveSheet.Range("A1")
ActiveSheet.Cells.Columns.AutoFit
Next rCell
End With
With wSheetStart
.AutoFilterMode = False
.Activate
End With
On Error GoTo 0
Application.DisplayAlerts = True
Dim colm As Long, StartRow As Long
Dim EndCell As Range
Dim ws As Worksheet
StartRow = 3
For Each ws In Worksheets
Set EndCell = ws.Cells(Rows.Count, "c").End(xlUp).Offset(1, 1)
If EndCell.Row > StartRow Then EndCell.Resize(, 4).Formula = "=SUM(R" & StartRow & "C:R[-1]C)"
Set EndCell = ws.Cells(Rows.Count, "D").End(xlUp)
If EndCell.Row >= 1000 Then
Range(J2) = Formula = ((EndCell.Row) * (0.05))
Range(J3) = "5% Discount"
ElseIf EndCell.Row >= 3000 Then
Range(J2) = Formula = ((EndCell.Row) * (0.1))
Range(J3) = "10% Discount"
End If
Next ws
End Sub'
Just need to figure out how to display the results and text to the right cells (J2 in this case)
I will supply the logic and all the references you need to put this one together; and will let you try to put it together on your own :). Come back for more help if needed.
You need to loop through all the worksheets in your workbook (Microsoft Tutorial)
You need to find the last row for the given columns (Online tutorial)
You need to use an IF statement to choose which formula to use (MSDN reference)
UPDATE
What's wrong with your code is this line :
Range(J2) = Formula = ((EndCell.Row) * (0.1))
What you're telling the computer is :
Multiply EndCell.Row by 0.1 (which has the number of the row below and to the right of the last cell in column C)
Compare Formula with the result previously obtained
Store the result of that logical expression at the range stored in variable J2
First of all, what you want is to put the result of the equation, and want to change J2 to "J2" so it gets the cell J2, instead of the what's contained in J2 (which has nothing at that point)
Also, you seem to say that you're not getting the right cells, maybe it is caused by this :
Set EndCell = ws.Cells(Rows.Count, "c").End(xlUp).Offset(1, 1)
In that line, you're finding the last cell of column C, but then you select the cell below, and to the right of it.
There are so many things wrong with your code it's hard to say what's not working properly.

Resources