Change from absolute to relative reference in Excel formula (VBA) - vba

Unfortunately I couldn’t find the answer to the below in the other questions – my problem is related to copying and pasting a formula that would use relative cell references instead of dynamic ones.
The general problem with the workbook I’m working on is the fact that it contains of a couple of different sheets with a potential dynamic range change. To give a better outline:
The column the formula has to be in, is based on an offset cell – I cannot give it a static value – and starts in row 2;
The formula itself is as follows: =CONCATENATE(LEFT(AA2,13), “:”, RIGHT(AA2,5) (and the values to be concatenated will always appear in the AA column)
The macro is supposed to insert the formula in the offset cell, copy it and paste it in the entire column, so the cell in row 3 refers to cell AA3 and so on:
Sub Copy1()
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.End(xlToRight).Select
ActiveCell.Offset(, 1).Select
Dim rng as Range
Set rng = ActiveCell
rng.Select
rng.Offset(1, 0).Select
ActiveCell.FormulaR1C1 = "=CONCATENATE(LEFT(R2C27,13), "":"", RIGHT(R2C27,5))"
rng.Offset(1, 0).Select
Selection.Copy
Range(Selection, Selection.End(xlDown)).Select
ActiveSheet.PasteSpecial
Selection.EntireColumn.Select
Application.CutCopyMode = False
End Sub
The problem is – upon trying to insert exact name of the cell, the macro populates it with the following:
=CONCATENATE(LEFT(‘AA2’,13), "":"", RIGHT(‘AA2’,5))
Because of the quotation marks, the formula doesn’t work.
Using the reference R2C27 results with absolute values being copied and thus every single cell in the column refers to cell AA2.
Is there any possibility make it create, copy and paste relative reference instead of absolute?

R1C1 reference is usually not needed as relative references are auto-adjusted if you copy+paste the formula or assign it to multiple cells. For example:
Range("A2:A9").Formula = "=CONCATENATE(LEFT(AA2,13), "":"", RIGHT(AA2,5)"

If I understand you want the column reference to be always $AA (absolute) while the row reference be relative. You can try this:
ActiveCell.Formula = "=CONCATENATE(LEFT($AA2,13), "":"", RIGHT($AA2,5))"
Then the autofill will adjust automatically the row number while keeping the column at "$AA".
That said, refactor your code to get rid of the select stuff. Look how shorter it will be in addition to using "Explicit references" (just replace "Sheet1" with the actual name of your worksheet):
Sub Copy1()
Dim rng As Range
Set rng = Worksheets("Sheet1").Range("A1").End(xlToRight).Offset(1, 1)
rng.Formula = "=CONCATENATE(LEFT($AA2,13), "":"", RIGHT($AA2,5))"
rng.Copy rng.Parent.Range(rng, rng.End(xlDown))
End Sub

Related

Excel VBA paste from visible cell selection error

I am still new to VBA, but I am trying to paste a copied selection of rows and columns from a different workbook to the current workbook. My issue is that it errors out when I try to paste I assume because the selection is larger than the destination selection. Below part of the code (I know, horrible and with selects):
dim i as long
Workbooks.Open Filename:="C:\Users\...\File1.xls"
Range("A15").Select
For i = 1 To n
ActiveCell.FormulaR1C1 = "=CONCATENATE(RC[1],RC[2])"
ActiveCell.Offset(1, 0).Select
Next i
Range("Q15").Select
For i = 1 To n
ActiveCell.FormulaR1C1 = "=VLOOKUP(RC[-16] ,'[file2.xlsm]DST'!C1:C18,1,0)"
ActiveCell.Offset(1, 0).Select
Next i
ActiveSheet.Range("$A$14:$Q$103").AutoFilter Field:=17, Criteria1:="#N/A"
Range("A1").End(xlDown).SpecialCells(xlCellTypeVisible).Copy
Windows("File2.xlsm").Activate
ThisWorkbook.Worksheets("sheet2").Activate
Range("B1").End(xlDown).Offset(1, -1).Select
'moves the active cell to the data end of column A
Debug.Print "Active cell is " & ActiveCell.Address(False, False)
'it puts the cursor correctly here, but it errors out after in the selection
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
Basically, this is part of a code that is adding a new column in a system export file(1), where a unique searching key composed of the second and third column is used later in a VLOOKUP formula to check if there are any missing products and if there are, those will be added in the reporting file(2), at the end of the data that is there. Column B is used as column A has a formula (another CONCATENATE that can't be used for the selection).
How can I make the selection work ?
The following code isn't the solution but it contains it.
Dim WbTarget As Workbook
Dim WsT As Worksheet
Dim Rng As Range
Set WbTarget = Workbooks("File2.xlsm") ' must be open
Set WsT = WbTarget.Worksheets("Sheet2")
Set Rng = WsT.Range("B1").End(xlDown).Offset(1, -1)
With ActiveSheet
.Range("$A$14:$Q$103").AutoFilter Field:=17, Criteria1:="#N/A"
.Range("A1").End(xlDown).SpecialCells(xlCellTypeVisible).Copy Destination:=Rng
End With
Basically, it avoids the PasteSpecial method which would require source and target ranges to be of identical size.
Its big flaw is its reference to ActiveSheet. You have code here to declare and set a workbook, a worksheet and a range. The target workbook, worksheet and range are never selected or activated. I recommend that you treat the source in the same way.
Set Option Explicit at the top of your code sheet. Remember that it is best practice to make all declarations at the beginning of a procedure and, if you like to allow me one more piece of advice, consider writing the results of worksheet functions into your worksheet rather than the worksheet functions.

Excel VBA copying a static range into a dynamic range on different sheet

I'm having a few issues working this out as I'm new to VBA but I'm sure it has a pretty simple solution.
I'm essentially wanting to automate the addition of new data to a sheet.
Sheet: INB BASKET Cells: A2:I76 contains live links to another worksheet.
Basically I want to copy these as Values to Sheet IND TOTAL below the latest entry on a button press (not continually updating).
I've created a dynamic named range (PasteRange) in excel that selects the 75 rows below the last entry that I want to paste into:
=OFFSET('IND TOTAL'!$A$1,COUNTA('IND TOTAL'!$A:$A),0,75,9)
I've then created a module with the following:
Sub CopyRange()
Dim CopyFrom As Range
Set CopyFrom = Sheets("IND BASKET").Range("A2", [I76])
et PasteArea = Sheets("IND TOTAL").Range("PasteRange")
CopyFrom.Copy
PasteArea.PasteSpecial xlPasteValues
End Sub
But to no success as of yet, please advise.
If you are only interested in pasting the values, then a direct value transfer is more efficient and does not involve the clipboard.
with Sheets("IND BASKET").Range("A2:I76")
Sheets("IND TOTAL").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Resize(.Rows.Count, .Columns.Count) = .Value
end with
With your own Copy, Paste Special xlPasteValues you only need to specify the cell in the top-left corner of the destination and allow the copied area to define the size and shape.
Sheets("IND BASKET").Range("A2:I76").Copy
Sheets("IND TOTAL").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
The definition of your named range might be better without the volatile OFFSET function like,
=INDEX('IND TOTAL'!$A:$A, MATCH("zzz",'IND TOTAL'!$A:$A )+1):INDEX('IND TOTAL'!$I:$I, MATCH("zzz",'IND TOTAL'!$A:$A ) + 75)
'or for just the first cell
=INDEX('IND TOTAL'!$A:$A, MATCH("zzz",'IND TOTAL'!$A:$A )+1)
That assumes that column A contains text which I deduced by your use of COUNTA and not COUNT. If column A contains numbers, swap 1e99 for "zzz".

VBA Paste Values [duplicate]

I'm having a few issues working this out as I'm new to VBA but I'm sure it has a pretty simple solution.
I'm essentially wanting to automate the addition of new data to a sheet.
Sheet: INB BASKET Cells: A2:I76 contains live links to another worksheet.
Basically I want to copy these as Values to Sheet IND TOTAL below the latest entry on a button press (not continually updating).
I've created a dynamic named range (PasteRange) in excel that selects the 75 rows below the last entry that I want to paste into:
=OFFSET('IND TOTAL'!$A$1,COUNTA('IND TOTAL'!$A:$A),0,75,9)
I've then created a module with the following:
Sub CopyRange()
Dim CopyFrom As Range
Set CopyFrom = Sheets("IND BASKET").Range("A2", [I76])
et PasteArea = Sheets("IND TOTAL").Range("PasteRange")
CopyFrom.Copy
PasteArea.PasteSpecial xlPasteValues
End Sub
But to no success as of yet, please advise.
If you are only interested in pasting the values, then a direct value transfer is more efficient and does not involve the clipboard.
with Sheets("IND BASKET").Range("A2:I76")
Sheets("IND TOTAL").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Resize(.Rows.Count, .Columns.Count) = .Value
end with
With your own Copy, Paste Special xlPasteValues you only need to specify the cell in the top-left corner of the destination and allow the copied area to define the size and shape.
Sheets("IND BASKET").Range("A2:I76").Copy
Sheets("IND TOTAL").Range("A" & Rows.Count).End(xlUp).Offset(1, 0).PasteSpecial xlPasteValues
The definition of your named range might be better without the volatile OFFSET function like,
=INDEX('IND TOTAL'!$A:$A, MATCH("zzz",'IND TOTAL'!$A:$A )+1):INDEX('IND TOTAL'!$I:$I, MATCH("zzz",'IND TOTAL'!$A:$A ) + 75)
'or for just the first cell
=INDEX('IND TOTAL'!$A:$A, MATCH("zzz",'IND TOTAL'!$A:$A )+1)
That assumes that column A contains text which I deduced by your use of COUNTA and not COUNT. If column A contains numbers, swap 1e99 for "zzz".

How to paste value of a sheet using VBA?

I have always used following to make a sheet to contain only values:
Sheets("NameOfTheTab").Activate
Cells.Select
Selection.Copy
Selection.PasteSpecial Paste:= xlPasteValues
But this is not safe, if someone/event change the selection, the program runs into random behaviour. How can can I get rid of this pattern?
Well, for one thing, you can avoid selecting the cells, just directly copy them:
Sheets("NameOfTheTab").Activate
Cells.Copy
Cells(1,1).PasteSpecial Paste:= xlPasteValues
Although this might not be the fastest way, depending on your sheet/actual problem.
You should always avoid using select method, beacuse it is not reliable. The sub below is a sample to copy data from a worksheet and paste only values to another one. This sample sub assumes you are running this macro from your target workbook if not change ThisWorkbook to your target workbook.
Sub copy_paste_only_values()
'will copy all cells in your tab that contain data
ThisWorkbook.Worksheets("NameOfTheTab").Cells.Copy
'will paste only values to your target worksheet
ThisWorkbook.Worksheets("NameOfTheTargetTab").Range("A1")._
PasteSpecial Paste:=xlPasteValues
'empty the clipboard
Application.CutCopyMode = False
End Sub

excel click object stores value from one cell to another

I'm trying to work on something in excel VBA but I can't seem to make it work fine.
Here's how it should work:
I need to copy and paste value of "J21" cell from one sheet to another. BUT, value of J21 keeps on changing every week. So I thought what if I create a code where I'll just press an object (say "STORE!") and it copies the value of "J21" from Sheet1 to "C3" Sheet 2. Then when the value of J21 changes, I just press "STORE!" again and it will copy the value of J21 and paste it on "C4" Sheet 2 without changing the previous value on "C3" Sheet 2.
Here's my latest attempt:
Dim myCell As Range, myRange As Range, i As Long
i = 3
Set myRange = Sheets("Summary").Range("C3")
Set myRange = Range(myRange, myRange.End(xlDown))
Sheets("Sheet1").Select
Range("J21").Copy
Sheets("Summary").Select
Cells(i, 3).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone,
SkipBlanks:=False, Transpose:=False
i = i + 1
myCell and myRange were used for my previous attempts, but it always go on an infinite copy-paste.
Selection and copy-paste in VBA is usually not needed. If you want to modify the value of a cell it is better to just directly use the value property of a range object. You seem to want to establish a reference to the first blank cell below C2 on Sheet2. The problem with your code is that Range(myRange, myRange.End(xlDown)) selects an entire block of cells (above the cell you want) rather than a single cell. While it would be possible to use .End(xlDown) appropriately to get to the cell you want, it is somewhat tricky to get right since it behaves differently depending on whether or not the cell underneath the current cell is blank. A while loop is one way to go. Something like:
Sub store()
Dim target As Range, source As Range
Set source = Sheets("Sheet1").Range("J21")
Set target = Sheets("Sheet2").Range("C3")
Do While Not IsEmpty(target.Value)
Set target = target.Offset(1)
Loop
target.Value = source.Value
End Sub
Chip's suggestion that you learn the basics of VBA is a good one. If you are someone (like me) who learns through books better than with online tutorials, I would recommend almost anything by John Walkenbach -- I first learned to program Excel by reading an early edition of his "Excel VBA Programming for Dummies."