I have a file that consists of 5 data related sheets and an additional master sheet. These master sheet has a functionality that retrieves the data from all sheets into master sheet based on the ID.
The flow of the code for now is:
Range().Select
Application.CutCopyMode = False
Selection.Copy
Sheets("mSheet").Select
ActiveSheet.Paste
It does what I want in a simple way that it only shows the necessary data. What I ideally want is to have link between this data and actual sheet, so that once I retrieve data in the master sheet and perform any edit - this edit is made in the actual corresponding sheet.
Any idea and suggestion is appreciated.
Original partial VBA code:
Sheets("dSheet1").Select
ActiveSheet.ListObjects("Table").Range.AutoFilter Field:=3, Criteria1:=id
Range(Selection, Selection.End(xlDown)).Select
Range(Selection, Selection.End(xlToRight)).Select
Application.CutCopyMode = False
Selection.Copy
Sheets("masterSheet").Select
ActiveSheet.Paste Destination:=Sheets("masterSheet").Range("A8")
The following will copy the contents of your selection, but instead of pasting the value will enter the reference to the cell, so when the cell gets updated, so would the master sheet:
Sub foo()
Range("A1").Select
Sheets("mSheet").Range("A2").Formula = "=" & Selection.Address
End Sub
EDIT
The following will do the opposite of the code above, so it will copy the data, paste it in your master Sheet and then go back to the original copied range and enter the cell reference there so when the master is updated, so is that range:
Sub foo()
Range("A1").Select 'select the range to be copied
Application.CutCopyMode = False
Selection.Copy 'copy it
Sheets("mSheet").Range("A2").PasteSpecial (xlPasteValues) 'paste the value into your master sheet
Range("A1").Formula = "=" & Sheets("mSheet").Range("A2").Address
'go back to your previous selection and enter the formula to reference the specific cell
End Sub
UPDATE
Replace your code with the following, as it does the same but with fewer lines of code an without any Select statement:
Sub foo2()
Sheets("dSheet1").ListObjects("Table").Range.AutoFilter Field:=3, Criteria1:=ID
Sheets("dSheet1").Range("A2:D2").Copy Destination:=Sheets("masterSheet").Range("A8")
'change the range above to copy as many columns as you need
End Sub
Then add the following code behind you Master Sheet to detect changes:
Private Sub Worksheet_Change(ByVal Target As Range)
'place this code behing the masterSheet
LastRow = Sheets("dSheet1").Cells(Sheets("dSheet1").Rows.Count, "A").End(xlUp).Row
'get the last row of dSheet1
If Target.Address = "$A$8" Then 'if A8 changes
For i = 1 To LastRow 'loop through dSheet1 to find the ID
If Sheets("dSheet1").Cells(i, 3) = Range("C8").Value Then 'when ID found
Sheets("dSheet1").Cells(i, 1) = Range("A8").Value 'change relevant cell with new data
End If
Next i
End If
'below do the same as above to change data for other columns, add more to adapt it to be able to make changes to however many columns you are copying over
If Target.Address = "$B$8" Then
For i = 1 To LastRow
If Sheets("dSheet1").Cells(i, 3) = Range("C8").Value Then
Sheets("dSheet1").Cells(i, 2) = Range("B8").Value
End If
Next i
End If
If Target.Address = "$D$8" Then
For i = 1 To LastRow
If Sheets("dSheet1").Cells(i, 3) = Range("C8").Value Then
Sheets("dSheet1").Cells(i, 4) = Range("D8").Value
End If
Next i
End If
End Sub
This assumes that your ID's are unique and you are getting a single row as a result of your autofilter.
How about adding buttons.
CopyID - Copy range from SheetID = B1
After Editing, EditID - will clear range in SheetID = B1, and rewrites everything from mSheet Range from A3 then paste in SheetID = B1
Edit ID code:
Public Sub EditID(ID As String)
Sheets(ID).Select
If Range("A1").Value <> "" Then
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Clear
End If
Sheets("mSheet").Select
If Range("A3").Value <> "" Then
Range("A3").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Sheets(ID).Select
Range("A1").Select
ActiveSheet.Paste
End If
Sheets("msheet").Select
End Sub
Related
New to VBA and simply wanted to create a macro which copies the tables within a specified range and pastes in the next available empty rows. What happens is that every time I run it it pastes into the same range i.e. B12 and don't know how to amend...
Sub CopyRange2()
Range("A1:I9").Select
Selection.Copy
Range("B12").Select
ActiveSheet.Paste
Application.CutCopyMode = False
End Sub
Would like to know why you have specified cell B12 ??
The below code will work if you just want to paste the data in the next available empty rows.
Sub CopyRange2()
Dim lastrow As Long
lastrow = Range("A" & Rows.Count).End(xlUp).Row
Range("A1:I9").Select
Selection.Copy
Range("A" & lastrow + 1).Select
ActiveSheet.Paste
Application.CutCopyMode = False
End Sub
I have some code that filters a large data set, then selects visible cells, and copy & pastes the range elsewhere.
Sub Filterstuff()
' Select & Filter data
Sheets("Main").Select
Lastrow = ActiveSheet.Range("A2").End(xlDown).Row
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.AutoFilter
' Filter for things
ActiveSheet.Range("A1:AU" & Lastrow).AutoFilter Field:=39, Criteria1:="words"
ActiveSheet.Range("A1:AU" & Lastrow).AutoFilter Field:=43, Criteria1:= _
"<>*wordswords*"
' Find the first unfiltered cell
Range("A1").Select
ActiveCell.Offset(1, 0).Select
Do Until ActiveCell.EntireRow.Hidden = False
ActiveCell.Offset(1, 0).Select
Loop
' If there are no unfiltered cells, exit
If ActiveCell.Row = Lastrow + 1 Then
Exit Sub
' Else paste results normally
Else
Range(Selection, Selection.Offset(0, 47)).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.SpecialCells(xlCellTypeVisible).Select
Selection.Copy
' Paste to bottom
Sheets("PasteSheet").Select
countrows = Cells(Cells.Rows.Count, "A").End(xlUp).Row
Range("A" & countrows + 1).Select
ActiveSheet.Paste
End If
' Return to Main and unfilter
Sheets("Main").Select
Cells.Select
ActiveSheet.ShowAllData
Selection.AutoFilter
End Sub
My issue is located in the code block meant to exit the sub if everything gets filtered out and there are no resulting rows with data after filtering. The relevant code begins at the commented section "Find the first unfiltered cell".
This code finds the first unhidden row, and checks if it is after the last row of data in the data set. My issue is that it is exceedingly slow. My data set can be 100,000+ rows and looping through it using ActiveCell.Offset(1, 0).Select takes forever.
How can I re-tool this code to exit the sub if everything gets filtered out?
Avoid using Select (this will improve the runtime performance):
http://stackoverflow.com/questions/10714251
Then, get a handle on the full range of "data". Finally, after applying autofilter, check the range's SpecialCells(xlCellTypeVisible).Count.
As long as that .Count is greater than the number of columns in your range, then you have at least one visible row of data (assuming your data has headers -- if there are no headers, you can just compare whether > 0).
Untested:
Sub Filterstuff()
' Select & Filter data
Dim ws as Worksheet
Dim rng as Range
Set ws = Worksheets("Main")
Set rng = ws.Range("A2:AU" & ws.Range("A2").End(xlDown).Row))
rng.AutoFilter
' Filter for things
rng.AutoFilter Field:=39, Criteria1:="words"
rng.AutoFilter Field:=43, Criteria1:="<>*wordswords*"
' Find the first unfiltered cell
If rng.SpecialCells(xlCellTypeVisible).Count > rng.Columns.Count Then
'Autofilter has returned at least one row of data
Else
MsgBox "No data results from Autofilter"
Exit Sub
End If
<more code...>
I have 2 sheets in my workbook, "Sheet1" and "Data". In Sheet1 I have used a Worksheet_Change macro so that when a change happens in column C:
A timestamp appears in column D
That range will get copied into the "Data" sheet.
Here is my code:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Location As Range
If Target.Column > 3 Or Target.Column < 3 Then Exit Sub
Application.EnableEvents = False
Cells(Target.Row, 4) = Now
Application.EnableEvents = True
Selection.End(xlToLeft).Select
Range(Selection, Selection.End(xlToRight)).Select
Selection.Copy
Sheets("data").Unprotect
Sheets("data").Range("a1").End(xlDown).Offset(1, 0).PasteSpecial _
Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
Sheets("data").Protect
Range("a1").Select
End Sub
My problem is that the PasteSpecial is not working more than one time.
The problem was that unprotecting the sheet was clearing the clipboard, meaning there was nothing to paste! Here is adapted code, which I've also changed in a couple of other ways to greatly improve it, see the comments for details.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Location As Range
' Use <> to mean "not equal to"
If Target.Column <> 3 Then Exit Sub
Application.EnableEvents = False
' Fully qualify the cells object
ThisWorkbook.Sheets("Sheet1").Cells(Target.Row, 4).Value = Now
Application.EnableEvents = True
' Avoid using .Select and Selection, the user could have clicked anywhere after the value change
' Use a With block to fully qualify your range objects
With ThisWorkbook.Sheets("data")
.Unprotect
' Copy immediately before paste
Target.EntireRow.Copy
.Range("A1").End(xlDown).Offset(1, 0).PasteSpecial Paste:=xlPasteValues
.Protect
End With
Application.CutCopyMode = False
End Sub
Currently, this just overwrites the same line on the "data" sheet, because the data you're pasting has nothing in column A, so the End(xlDown) in column A returns the same position. You may need to change this to column C, or use
.Cells(Rows.Count,"C").End(xlUp).Offset(1, 0).PasteSpecial
Which is still column dependant but goes up to get the last row. There is a dot . before Cells because that line would be within the With block.
Not sure what is being copied as you have used Selection and that depends upon how you input value in column C, whether by hitting Enter or Ctrl+Enter.
Say if you input a value in B2 and press Enter to submit it, cell B3 will get selected and as per your code a range from row3 will be copied to Data sheet. Whereas if you hit Ctrl+Enter, the selection will remain in B2 so a range from row2 will be copied to data sheet.
But that you can tweak yourself.
See if the tweaked code works for you.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Location As Range
If Target.Column <> 3 Then Exit Sub
Application.ScreenUpdating = False
Application.EnableEvents = False
Cells(Target.Row, 4) = Now
Application.EnableEvents = True
Selection.End(xlToLeft).Select
Range(Selection, Selection.End(xlToRight)).Select
Sheets("data").Unprotect
Selection.Copy
Sheets("Data").Range("A" & Rows.Count).End(3)(2).PasteSpecial xlPasteValues
Sheets("data").Protect
Range("a1").Select
Application.ScreenUpdating = True
End Sub
I would like to copy the data from 'Sheet1' ($A:$N ; may fluctuate), select the range of the data and paste it in 'Sheet3'.
I also need to copy the data from 'Sheet2' without the first row (same headers as 'Sheet1') and paste it underneath the data of 'Sheet1' that is now in 'Sheet3'.
Sub CopyPaste()
Sheets("PC_VIEWS").Select
Range("A1:Q231").Select
Selection.Copy
Sheets("PC_LTC_VIEWS").Select
Range("A1").Select
ActiveSheet.Paste
Range("A1").Select
Selection.End(xlDown).Select
Range("A232").Select
Sheets("LTC_VIEWS").Select
Range("A1").Select
Application.CutCopyMode = False
Range("A1:M1264").Select
Selection.Copy
Sheets("PC_LTC_VIEWS").Select
ActiveSheet.Paste
End Sub
I am open to other solutions!
This code is enough. Try it.
Public Sub CopyAndPaste()
Dim firstRowCount, secondRowCount As Integer
'Copy from "PC_VIEWS" sheet.
Sheets("PC_VIEWS").Select
'Getting the last row from "PC_VIEWS" sheet.
firstRowCount = Range("A:Q").SpecialCells(xlLastCell).row
Range("A1:Q" & firstRowCount).Select
Selection.Copy
'Paste to "PC_LTC_VIEWS" sheet.
Sheets("PC_LTC_VIEWS").Select
Range("A1").Select
ActiveSheet.Paste
'Reset clipboard
Application.CutCopyMode = False
'Copy from "LTC_VIEWS" sheet.
Sheets("LTC_VIEWS").Select
'Getting the last row from "LTC_VIEWS" sheet.
secondRowCount = Range("A:Q").SpecialCells(xlLastCell).row
Range("A2:Q" & secondRowCount).Select
Selection.Copy
'Paste to "PC_LTC_VIEWS" sheet.
Sheets("PC_LTC_VIEWS").Select
Range("A" & firstRowCount + 1).Select
ActiveSheet.Paste
'Reset clipboard
Application.CutCopyMode = False
End Sub
I would like to loop through column A in Worksheet1 and find the first cell which has a specified text "Oil Production". This cell is the first cell in the array I wish to copy to Worksheet2. This cell and the size of the array will change from time to time, hence the code I have used. I then paste it into cell B7 in Worksheet2 which will never change.
This is my formula. I get the error at line ActiveSheet.Paste
Sub Test()
Application.ScreenUpdating = False
For Each Cell In Sheets("Sheet1").Range("A:A")
If Cell.Value = "Oil Production" Then
ActiveSheet.Cells.Select
Range(ActiveCell, Cells(ActiveCell.End(xlDown).Row, ActiveCell.End(xlToRight).Column)).Select
Selection.Copy
Sheets("Sheet2").Select
Range("B7").Select
ActiveSheet.Paste
End If
Next
End Sub
resize the area:
Sub Test()
Dim MyRowCount As Long, MyColCount As Long
Application.ScreenUpdating = False
For Each Cell In Sheets("Sheet1").Range("A1:A" & Range("A" & Rows.count).end(xlup).row) 'This make it poll the used data rather than the whole column
If Cell.Value = "Oil Production" Then
ActiveSheet.Cells.Select
With Range(ActiveCell, Cells(ActiveCell.End(xlDown).Row, ActiveCell.End(xlToRight).column))
.Copy
MyRowCount = .Rows.Count
MyColCount = .Columns.Count
End With
Sheets("Sheet2").Select
Range("B7").Resize(MyRowCount, MyColCount).PasteSpecial xlPasteAll
'Do you need to flick back to Sheet1 after pasting?
End If
Next
End Sub
Also I took out a bunch of selects for you.
Range("A1").Select
Selection.Paste
can be written as
Range("A1").PasteSpecial XLPasteAll
You can chop out most selects this way, you can see I have also done it with the Range you are copying