I have a VBA related question which has to do with extending formulas based on the data inserted to another sheet but with some implications. More specifically, I would like formulas in sheet "Calculation" to extend from cells A3:AB3 based on the number of rows populated in column A in the sheet "Responses". Then delete the content of cells from this point below (this is to dynamically adjust populated formulas in sheet "Calculation" in case less rows are populated in sheet "Responses" compared to the last time). The tricky part is that sheet "Responses" could be either empty (so we don't want an endless loop); populated with data through copy paste, or the user can delete it completely and insert a new tab with the same name downloaded from a database (I avoid an error in my formulas using INDIRECT).
Finally because sheet "Calculation" is always hidden, and as mentioned sheet "Responses" might be deleted and re-inserted don't think the code could run by targeting changes in sheet "Responses". What could work is inserting a button into a sheet called "Output" or run the code every time this sheet ("Output") is active (so maybe save the code there).
What I have is very simple and doesn't do what I need at all. I can't get it to read from another sheet only from column AD within the same sheet.
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("AD:AD")) Is Nothing Then
Application.EnableEvents = False
lastrow = Range("AD3000").End(xlUp).Row
Range("A3:AB3").AutoFill Destination:=Range("A3:AB" & lastrow), Type:=xlFillDefault
Application.EnableEvents = True
End If
End Sub
Thank you!!
In case your sheet will be deleted, you can use Workbook_SheetChange event, inside ThisWorkbook module, and check if sh.Name = "Responses" to apply the code's logic.
Code (inside ThisWorkbook module)
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Dim LastRow As Long
Dim CalcSht As Worksheet
' set Worksheet object
Set CalcSht = ThisWorkbook.Sheets("Calculations")
With Sh
If .Name = "Responses" Then ' check if changes were made in a worksheet named "Responses"
Application.EnableEvents = False
' --- First: clear formulas form all cells (below row 3) ---
LastRow = CalcSht.Cells(CalcSht.Rows.Count, "A").End(xlUp).Row ' get the last row in column A
If LastRow < 4 Then LastRow = 4
CalcSht.Range("A4:AB" & LastRow).ClearContents ' clear contents (formulas) from row 4 and below
' --- Second: populate formulas on all rows after row 3 (where there is data in column A) ---
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row ' get the last row in column A
If Not Intersect(Target, .Range("A1:A" & LastRow)) Is Nothing Then
Application.EnableEvents = False
' drag formulas until last row with data in column A (in "Responses" worksheet)
CalcSht.Range("A3:AB3").AutoFill Destination:=CalcSht.Range("A3:AB" & LastRow), Type:=xlFillDefault
End If
End If
End With
Application.EnableEvents = True
End Sub
Related
My requirement is whenever there is an update to my main workbook's (main.xlsm)sheet1 "A1" cell, I need to copy that entire row of data into a different excel(say working.xlsm). The main sheet has columns from A to M and data capture should occur depends upon A1 cell data change. All data get preserved in the second excel and all new data will be added to next row.
I have added below code to my second workbook(working.xlsm), where I need to save all the data, but it's not working. I am not sure how to use a range with with function
Private Sub Worksheet_Calculate()
With Sheet1
With .Cells(.Rows.Count, "B").End(xlUp)
If .Value <> Workbooks("main.xlsm").Worksheets("Sheet1").Range("A1").Value Then
.Offset(1).Value = Sheet1.Range("A:M").Value
End If
End With
End With
End Sub
This code will, if put in the sheet on main.xlsm, copy A1:M1 of main.xlsm to the first blank row of working.xlsm's Sheet1 whenever A1 of the sheet is changed. This assumes that working.xlsm is currently open as well, for reference.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ws As Worksheet
Set ws = Workbooks("working").Sheets("Sheet1")
If Not Intersect(Target, Range("A1")) Is Nothing Then
Range("A1:M1").Copy
ws.Range("A" & ws.Cells(ws.Rows.Count, "A").End(xlUp).Row + 1).PasteSpecial xlPasteValues
End If
End Sub
Is this what you were looking for?
I am quite new to Excel Macro and need some help to achieve the following task.
I have two sheets in the same workbook; one is the main sheet that can be edited, and the other one is to extract certain columns from the main sheet. Since the main sheet may have columns inserted or deleted, my approach is to input specific titles that I would extract to sheet 2 (blank sheet initially), look up/match these texts/column titles in sheet 1 (main sheet); then, copy the entire column under that match column title and paste it to sheet 2.
I have the following code, but errors still pop up. Since I am not quite familiar with Macro syntax, I am not so sure if this approach is applicable. I do appreciate any help, comment, or suggestion. Thanks in advance.
Private Sub CommandButton1_Click()
Dim i As Long
Dim j As Long
Dim r As Long
For i = 1 To 30
For j = 1 to 30
If Sheets(2).Cells(1, j).Value = Sheets(7).Cells(1, i).Value Then
For r = 2 To 1000
Sheets(2).Cells(r, j).Copy
Sheets(7).Cells(r, i).PasteSpecial Paste:=xlPasteFormats
Sheets(7).Cells(r, i).PasteSpecial Paste:=xlPasteValue
Next r
End If
Next j
Next i
End Sub
you'd better use Find() method of Range object to find values in a range
so you may want to use this code
Option Explicit
Private Sub CommandButton1_Click()
Dim f As Range, mainShtHeaderRng As Range, blankShtHeaderRng As Range, cell As Range
Dim mainSht As Worksheet, blankSht As Worksheet
Set mainSht = Worksheets("mainSht") '<--| set your "main" sheet
Set blankSht = Worksheets("blankSht") '<--| set your "blank" sheet
Set mainShtHeaderRng = mainSht.Rows(1).SpecialCells(XlCellType.xlCellTypeConstants, xlTextValues) '<--| set your header range in the "main" sheet
Set blankShtHeaderRng = blankSht.Rows(1).SpecialCells(XlCellType.xlCellTypeConstants, xlTextValues) '<--| set your header range in the "blank" sheet
For Each cell In blankShtHeaderRng '<--| loop through "blank" sheet headers...
Set f = mainShtHeaderRng.Find(what:=cell.Value, LookIn:=xlValues, lookat:=xlWhole, MatchCase:=False) '<--|... and search them between the "main" sheet headers
If Not f Is Nothing Then '<--| if found...
Range(f, mainSht.Cells(mainSht.Rows.Count, f.Column).End(xlUp)).Copy '<--| copy "main" sheet corresponding column doqwn to its last non empty cell...
cell.PasteSpecial Paste:=xlPasteFormats '<--| ... and paste formats...
cell.PasteSpecial Paste:=xlPasteValues '<--| ... and values to "blank" sheet current header column
End If
Next cell
End Sub
Hi I have code which is meant to
Loop through all worksheets which begin with "673"
Copy all the rows which have data from row 5 onwards
Paste the entries on the next empty row in the "Colours" worksheet
I'm having the following issues:
Code only runs in the worksheet that is active
Doesn't loop through all worksheets
When it pastes in the "Colours" worksheet, it pastes directly over the headings in row 2. The first blank row is row 3 onwards and I would like the logic to paste at the next available blank row as it loops through the sheets.
Sub Consolidate()
Dim lastrow As Long
Dim report As Worksheet
Set report = Excel.ActiveSheet
For Each Sheet In ActiveWorkbook.Worksheets
If InStr(Sheet.Name, "673") > 0 Then
With report
.Range(.Cells(5, "K"), .Cells(.Rows.Count, "K").End
(xlUp)).EntireRow.Copy
End With
Worksheets("Colours").Select
lastrow = Worksheets("Colours").Cells(Worksheets("Colours").Rows.Count, 1).End(xlUp).Row
Worksheets("Colours").Cells(lastrow + 1, 1).Select
ActiveSheet.Paste
End If
Next
End Sub
Your help would be greatly appreciated.
KS is right, to get your code functioning you just need to reference the sheet. I'd started modifying it further so I'll post what I've done in totality:
Firstly I removed the 'Set report = ' line, that's not needed (alternatively you could have 'Set report' at the beginning of the loop, but it's easier to work directly 'With Sheet' as KS says).
CHANGED1 = You said it should loop through worksheets that 'begin' with 673, so this new line checks for the first three characters matching 673, rather than just looking to see if 673 appears anywhere in the sheet name.
NEW = Activates the sheet, this makes the next copy command work.
CHANGED2 = With Sheet as explained above.
CHANGED3 = You said it should copy the rows that have data from row 5 onwards (previously your code would copy rows 1-5).
Sub Consolidate()
Dim lastrow As Long
Dim report As Worksheet
For Each Sheet In ActiveWorkbook.Worksheets
If Left(Sheet.Name, 3) = "673" Then 'CHANGED1
Worksheets(Sheet.Name).Select 'NEW
With Sheet 'CHANGED2
.Range("A5", Range("A" & 65536).End(xlUp)).EntireRow.Copy 'CHANGED3
End With
Worksheets("Colours").Select
lastrow = Worksheets("Colours").Cells(Worksheets("Colours").Rows.Count, 1).End(xlUp).Row
Worksheets("Colours").Cells(lastrow + 1, 1).Select
ActiveSheet.Paste
End If
Next
End Sub
Hope this helps!
try the following code
Sub Consolidate()
Dim sheet As Worksheet, coloursSheet As Worksheet
Set coloursSheet = ActiveWorkbook.Worksheets("Colours")
For Each sheet In ActiveWorkbook.Worksheets
If Left(sheet.Name, 3) = "673" Then
sheet.Range("K5:K" & sheet.Cells(sheet.Rows.Count, "K").End(xlUp).Row).SpecialCells(xlCellTypeConstants).EntireRow.Copy _
Destination:=coloursSheet.Cells(coloursSheet.Rows.Count, "A").End(xlUp).Offset(1)
End If
Next
End Sub
it:
avoids useless selections and variables
copies non blank cells only (assuming data are "constants", i.e. not formulas)
This is the code which I used to copy data from multiple sheets to single sheet.
I want to know if there is any way by which I can copy the data into "Report" sheet starting from 3rd Column, i.e, the data should be pasted into sheet from 3rd column onwards.
Sub AppendDataAfterLastColumn()
Dim sh As Worksheet
Dim DestSh As Worksheet
Dim Last As Variant
Dim CopyRng As Range
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
' Delete the summary worksheet if it exists.
Application.DisplayAlerts = False
On Error Resume Next
ActiveWorkbook.Worksheets("Report").Delete
On Error GoTo 0
Application.DisplayAlerts = True
' Add a worksheet with the name "Report"
Set DestSh = ActiveWorkbook.Worksheets.Add
DestSh.Name = "Report"
' Loop through all worksheets and copy the data to the
' summary worksheet.
For Each sh In ActiveWorkbook.Worksheets
If sh.Name <> DestSh.Name Then
lastcol = DestSh.Cells(1, DestSh.Columns.Count).End(xlToLeft).Column
' Find the last column with data on the summary
' worksheet.
Last = lastcol
lastCol3 = sh.Cells(1, sh.Columns.Count).End(xlToLeft).Column
' Fill in the columns that you want to copy.
Set CopyRng = sh.Range(sh.Cells(1, 2), sh.Cells(15, lastCol3))
' Test to see whether there enough rows in the summary
' worksheet to copy all the data.
If Last + CopyRng.Columns.Count > DestSh.Columns.Count Then
MsgBox "There are not enough columns in " & _
"the summary worksheet."
GoTo ExitTheSub
End If
' This statement copies values, formats, and the column width.
CopyRng.Copy
With DestSh.Cells(1, Last + 1)
.PasteSpecial 8 ' Column width
.PasteSpecial xlPasteValues
'.PasteSpecial xlPasteFormats
Application.CutCopyMode = False
End With
End If
Next
ExitTheSub:
Application.Goto DestSh.Cells(1)
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Data sheet 1 from comments:
Data sheet 2 from comments:
Expected output from comments:
This sort of copy can be done easily with Copy. In order to pick the output Range for the paste part, you can use an Application.InputBox with a Type:=8 parameter. This prompts Excel to open the Range selection dialog which works well.
Once you know those two pieces, the only difficulty is building the Ranges. This is not difficult, but is specific to the context, existing data on the sheets, and degree of robustness. For the example below, I am using CurrentRegion to get the block of data (same as hitting CTRL+A) and then Intersect to only get the desired columns. You can also make use of UsedRange and End to build ranges.
Picture of ranges shows the different sheets for input and the final sheet for output. The sheet to paste into c is empty for now.
Code does the work to get the two ranges to copy and then prompts for an output location. From there, it pastes the resulting Ranges into the desired location. There is an Offset to ensure that the 2nd range does not overlap the first.
Sub CopyFromTwoRanges()
Dim rng_set1 As Range
Dim rng_set2 As Range
Dim rng_output As Range
'build the ranges
Set rng_set1 = Intersect(Sheets("a").Range("C:F"), _
Sheets("a").Range("C1").CurrentRegion)
Set rng_set2 = Intersect(Sheets("b").Range("C:F"), _
Sheets("b").Range("C1").CurrentRegion)
'prompt for cell
Set rng_output = Application.InputBox("Pick the range", Type:=8)
'ensure a single cell only
Set rng_output = rng_output.Cells(1, 1)
'paste the ranges
rng_set1.Copy rng_output
rng_set2.Copy rng_output.Offset(, rng_set1.Columns.Count)
End Sub
Result shows the prompt with cell selected and then the output.
I have an audit that is done daily. I have been asked to save the audit points to a separate sheet for review by the mgmt. team. The code is below but when I run it I get an error: Script out of range.
Sub copy1()
Dim sheet2 As Worksheet
Dim sheet10 As Worksheet
Set sheet2 = Worksheets("sheet2")
Set sheet10 = Worksheets("sheet10")
sheet2.Range("a2:g10").Copy
sheet10.Cells(Rows.count, 1).End(xlUp).Offset(1, 0).pastspecial xlPasteValues
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub
It's difficult to say for sure, but it is likely that you are receiving the "Subscript out of range" error because your workbook does not have the worksheets named "Sheet2" and "Sheet10".
The following code copies data from Sheet2 and pastes the values of the data to the next available row on Sheet10.
Sub Copy2()
Dim DestinationStartingCell As Range
Dim SheetRowCount As Long
Worksheets("Sheet2").Range("A2:I29").Copy
SheetRowCount = Worksheets("Sheet10").Rows.Count '1048576 for Excel 2007 and later
Set DestinationStartingCell = Worksheets("Sheet10") _
.Range("A" & SheetRowCount).End(xlUp).Offset(1, 0)
DestinationStartingCell.PasteSpecial xlPasteValues
End Sub
You could use this code
emptyrow=WorksheetFunction.CountA(Workbooks(<workbookname>).Sheets(10).Range("A:A"))+1
Workbooks(<workbookname>).Sheets(10).Cells(emptyrow,1).pastespecial xlPasteValues
to dynamically find the first empty row in Sheet10 to paste to.