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".
Related
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
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".
I've been trying to optimize some of my coding and managed to cut and speed it up a lot. However there are some things that are still quite clunky (and me still a noob). Backstory is that my code is opening source and target files, copies a lot of data of variable length, closes source and then does a lot of operations and finally saves target file.
One of the things Id like is to do if possible is a direct copy of data without using clipboard, activating workbooks, selecting sheets (whatever of this is possible to pack into more efficient code that I am currently having)
Windows("SOURCE.xlsm").Activate
Sheets("Data").Select
Range("A2:AX10").Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Windows("TARGET.xlsm").Activate
Range("A2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
Is it possible to do a selection (A2:AX10 and all the way down to last row) in SOURCE file-Data sheet and directly copy it to TARGET file-Data sheet cell A2 without using clipboard.
The reason why I use A2:AX10 and then selection down is because I have a lot of blank cells in the whole data set and this way I get entire data.
I would like to be able to to that selection and use it as a range in this line
Workbooks(“SOURCE”).Worksheets("Data").Range(“A2:AX10 & ALLTHEWAYDOWN”).Copy _Workbooks(“TARGET”).Worksheets("Data").Range(“A2")
I was trying to solve this but I dont end up with desired result. When I try doing selection and setting as range then both trying copy range with activitng workbooks and in the direct copy mode I get 1004 error.
Is it possible to optimize this chunk and make it work. It would improve a lot of my VBA.
Thanks,
You need something like this:
With Workbooks("SOURCE.xlsm").Sheets("Data")
.Range("A2:AX10", .Range("A2:AX10").End(xlDown)).Copy Workbooks("TARGET.xlsm").ActiveSheet.Range("A2")
End With
You could probably also use CurrentRegion rather than End(xlDown
You can set one range's values (the range where you would want to paste values) equal to a source range's values (the range which you would previously have copied).
Sub paste_values()
Dim wb_A As Workbook, ws_A As Worksheet
Dim wb_B As Workbook, ws_B As Worksheet
Dim last_row As Long
Set wb_A = ThisWorkbook
Set ws_A = wb_A.Sheets(1)
Set wb_B = Workbooks("WorkbookB")
Set ws_B = wb_B.Sheets(1)
With ws_A
last_row = .Range("A" & .Rows.Count).End(xlUp).Row
End With
ws_B.Range("A2:AX" & last_row).Value = ws_A.Range("A2:AX" & last_row).Value
End Sub
This code is setting the new range's values equal to the original range. It prevents the need to activate sheets or workbooks, whilst also copying data to a range without filling the clipboard.
I would also recommend using last_row = .Range("A" & .Rows.Count).End(xlUp).Row to find the last row of your data. Although you do need to ensure you use this on a column which you know contains continuous data.
I have data on multiple sheets in a workbook that I want copied all to one sheet in that same workbook. When I run the macro, I would like it to start by deleting the current data in the "iPage Data Export" sheet and then replacing it with data from the other sheets.
I want the process to occur one column at a time since I may not bring over everything. Right now I am trying to learn how to do just one column.
I was able to get it to copy all of the contents of a column from one sheet, but when it moves to the next sheet, it overwrites the existing data. In the end, I only get one sheets worth of data copied.
Here are my 4 problems:
How do I make it clear the data on this sheet before running the routine?
How can I make it start each copy function at the bottom of that row (i.e. after the last cell with a value)? I have tried many of the suggestions on this and other boards without success. I will admit I am not very experienced in this.
How can I make it copy to a particular column (currently it just seems to default to A.
How can I concatenate multiple columns during the paste function? I.e. what if I want it to insert: A2&", "B2 instead of just A2
Sub CombineData()
Dim Sht As Worksheet
For Each Sht In ActiveWorkbook.Worksheets
If Sht.Name <> "iPage Data Export" Then
Sht.Select
Range("C:C").Copy
Sheets("iPage Data Export").Select
ActiveSheet.Paste
Else
End If
Next Sht
End Sub
How do I make it clear the data on this sheet before running the routine?
Sht.Cells.ClearContents
How can I make it start each copy function at the bottom of that row (i.e. after the last cell with a value)? I have tried many of the suggestions on this and other boards without success. I will admit I am not very experienced in this.
Range("C" & Rows.Count).End(xlUp).Offset(1, 0)
In detail:
Rows.Count will return the number of rows in the sheet, so in the legacy style *.xls workbooks this would return the number 65,536. Therefore "C" & Rows.Count is the same as C65536
Range("C" & Rows.Count).End(xlUp) is the same as going to C65536 and pressing Ctrl + ↑ - The command End(xlDirection) tells the program to go the last cell in that range. In this case, we would end up at the last cell containing data in column C.
.Offset(1, 0) means that we want to return the range offset by an amount of rows and/or columns. VBA uses RC (Rows Columns) references, so whenever you see something like the Offset() function with two numbers being passed as the arguments, it usually relates to the row, and the column, in that order. In this case, we want the cell that is one row below the last cell we referenced.
All-in-all the phrase Range("C" & Rows.Count).End(xlUp).Offset(1, 0) means go to the last cell in column C, go up until we hit the last cell with data, and then return the cell below that - which will be the next empty cell.
How can I make it copy to a particular column (currently it just seems to default to A.
Range("C:C").Copy Destination:=Sheets("iPage Data Export").Range("A:A")
You can pass the Destination argument in the same line and actually bypass the clipboard (faster and cleaner)
How can I concatenate multiple columns during the paste function? I.e. what if I want it to insert: A2&", "B2 instead of just A2
Lets say you wanted to reference column A, B, and F - just use:
Range("A1, B1, F1").EntireColumn
To summarise, you could streamline your existing code to something like (untested):
Sub CombineData()
Dim Sht As Worksheet
For Each Sht In ActiveWorkbook.Worksheets
If Sht.Name <> "iPage Data Export" Then
Sht.Range("C1:C" & Cells(Sht.Rows.Count, 3).End(xlUp).Row).Copy Destination:=Sheets("iPage Data Export").Range("A:A")
End If
Next
End Sub
This should do for the copying:
Sub CombineData()
Dim sheet As Worksheet
For Each sheet In Worksheets
If (sheet.Name <> "iPage Data Export") Then
sheet.Select
Range("A1", ActiveCell.SpecialCells(xlLastCell)).Select
Selection.Copy
Worksheets("iPage Data Export").Activate
Cells(1, ActiveCell.SpecialCells(xlCellTypeLastCell).Column + 1).Select
ActiveSheet.Paste
End If
Next
End Sub
For the concatenation you need to be more specific - but I guess you should open a new question with a clearer focus if you need specific help on that.
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."