How to Paste a Range onto another worksheet with filters on - excel

This seems like a simple task but I keep running into various errors. I need to filter worksheet B and then copy a column of data. I then need to filter worksheet A and then paste the copied data into a column.
Worksheets("SheetB").Select
lastRowOne = Range("B" & Rows.Count).End(xlUp).Row
Range("DL2:DL" & lastRowOne).AutoFilter Field:=116, Criteria1:="<>Apples"
lastRowTwo = Range("B" & Rows.Count).End(xlUp).Row
Range("DG2:DG" & lastRowTwo).AutoFilter Field:=111, Criteria1:=Target
'Target is already defined earlier in the Macro and functions fine
lastRowThree = Range("B" & Rows.Count).End(xlUp).Row
Range("DX2:DX" & lastRowThree).Copy
Worksheets("SheetA").Activate
lastRowFour = Range("B" & Rows.Count).End(xlUp).Row
Range("A2:A" & lastRowFour).AutoFilter Field:=1, Criteria1:=Target
lastRowFive = Range("B" & Rows.Count).End(xlUp).Row
Range("Z2:Z" & lastRowFive).SpecialCells(xlCellTypeVisible).Select
Selection.PasteSpecial Paste:=xlPasteRange, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
In place of the last line I have also tried:
ActiveSheet.Paste
The first returns a "Run-time error '1004':
PasteSpecial method of range class failed
the ActiveSheet.Paste returns a "Run-time error '1004':
Paste method of Worksheet class failed
Although this code is not the cleanest, it all functions with the exception of the "pasting" onto 'sheetA' in Column Z. I also need the data pasted into AA if that can be included in a fix.
Thanks !

Here's (I hope) the same macro, but without .Select/.Activate, and a little tweaking. For instance, you don't need more than one "lastRow" variable. Since you really just reset it, you can use one.
Sub tester()
' First create, then SET, worksheet variables to hold the sheets. We use these when
' referring to ranges, cells, etc.
Dim aWS As Worksheet, bWS As Worksheet
Set aWS = Worksheets("SheetA")
Set bWS = Worksheets("SheetB")
Dim lastRow As Long 'AFAICT, you only need this one Last Row variable. Just update it each time.
Dim copyRng As Range
With wsB ' working with SheetA
lastRow = .Cells(.Rows.Count, 2).End(xlUp).Row
.Range("DL2:DL" & lrOne).AutoFilter Field:=116, Criteria1:="<>Apples"
lastRow = .Cells(.Rows.Count, 2).End(xlUp).Row
.Range("DG2:DG" & lastRow).AutoFilter Field:=111, Criteria1:=Target
lastRow = .Cells(.Rows.Count, 2).End(xlUp).Row
' We now SET the range we want to copy. We can avoid copy/paste by setting two ranges equal
' to eachother. For now, let's store the COPY RANGE in a Range variable
Set copyRng = .Range("DX2:DX" & lastRow).SpecialCells(xlCellTypeVisible)
End With 'bWS
Dim pasteRng As Range
With aWS
lastRow = .Cells(.Rows.Count, 2).End(xlUp).Row
.Range("A2:A" & lastRow).AutoFilter Field:=1, Criteria1:=Target
lastRow = .Cells(.Rows.Count, 2).End(xlUp).Row
Set pasteRng = .Range("Z2:Z" & lastRow).SpecialCells(xlCellTypeVisible)
End With 'aWS
pasteRng.Value = copyRng.Value
End Sub
The only hesitation I have is the pasting to SpecialCells. AFAIK, if the paste range is different than the copy range, you might get some errors. In any case, try the above and let me know what happens.
An important thing to pay attention to, especially when using multiple worksheets, is that you should be explicit with which sheet you want to get a Range(),Cells(),Rows(),Columns(),etc. Otherwise, it's going to get that info. from the ActiveSheet, whatever that may be.

Related

How can I turn a Range ("A1:A11") into (A"1: until empty cell")

I have tried to just set the range to ("A:A") but that makes the table too large and my computer freezes up, I have also tried to input a line like Range("A" & Rows.Count).End(xlUp).Offset(1) but that is not recognized by VBA.
Any help would be appreciated!
You need to first define your last row by referencing the last cell in the column then use .End(xlUp).row to find the last row number. You can then use that row number to build cell references, or even save the range as a range variable like I did:
Sub Last_Row_Example()
Dim LastRow As Long 'Last Row as a long integer
Dim RG As Range 'A range we can reference again and again very easily
'Consider renaming it to something more descriptive.
'for your particular situation
LastRow = Range("A" & Rows.Count).End(xlUp).Row ' Here we store the "LastRow" Number
Set RG = Range("A1:A" & LastRow) ' Here we build a range using the LastRow variable.
RG.Select
Application.CutCopyMode = False
ActiveSheet.ListObjects.Add(xlSrcRange, RG, , xlYes).Name = _
"Table3"
Range("Table3[[#All],[Ticker Name]]").Select
Selection.ConvertToLinkedDataType ServiceID:=268435456, LanguageCulture:= _
"en-US"
End Sub

How can I add cell values based on column header?

I am having trouble grasping how the operation I'm about to describe can be conceptualized, since I am new to coding.
A big spreadsheet includes 100 columns, and those need to be condensed down to 10 by adding together the columns. There is a key, so that all the columns tagged with "1" go to 1st new column, and so on.
Here is an example:
There are n original columns. Each one of those columns has a key (bottom left), and according to that key it must be added to column 1, 2, 3, or 4 of the new table (bottom right). This is all nice and clean but the real spreadsheet has perhaps 270+ columns and they must be condensed into 10 columns or so for 3000+ ID's where not all ID's have all columns filled.
I am not sure how to create that sort of loop, I thought of looping through the key first, then finding in the original columns each "A", adding them to first column of new table, then doing that through all of them, but I'm not sure how to avoid overwriting old sums with the new ones.
Cheers!
You can do it with SUMPRODUCT. Actually, you can code it on VBA using this same formula of SUMPRODUCT and pasting values or with Evaluate:
=SUMPRODUCT(--($A$2:$A$6=$F14)*$B$2:$M$6*TRANSPOSE(--($B$14:$B$25=G$13)))
Depending on your Excel version maybe you need to input the formula as array formula, so instead of normally, type the formula and press CTRL+ENTER+SHIFT
UPDATE: You can also do it with VBA but you need to make some changes to your source file to make it work with any dataset of any size:
Your data must be alone in a worksheet called DATA
Your keys must be alone in a worksheet called KEYS
The code will generate a new worksheet with the grouped data according to keys. It uses same formula than before, but does it everything alone.
Sub TEST()
Dim wk As Worksheet
Dim rngData As Range
Dim rngKeys As Range
Dim LR As Long 'last non blank row
Dim LC As Long 'last non blank column
Dim ThisKeys As Variant
Set wk = ThisWorkbook.Sheets.Add(, ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count)) 'add new worksheet for output at end of workbook
With ThisWorkbook.Worksheets("DATA")
LR = .Range("A" & .Rows.Count).End(xlUp).Row
LC = .Cells(1, .Columns.Count).End(xlToLeft).Column
Set rngData = .Range(.Cells(2, 2), .Cells(LR, LC))
.Range("A2:A" & LR).Copy wk.Range("A2:A" & LR) 'copy names to output
End With
With ThisWorkbook.Worksheets("KEYS")
LR = .Range("A" & .Rows.Count).End(xlUp).Row
Set rngKeys = .Range("B2:B" & LR)
.Range("B2:B" & LR).Copy
wk.Range("B2").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
End With
With wk
.Range("B2:B" & LR).RemoveDuplicates Columns:=1, Header:=xlNo
LR = .Range("B" & .Rows.Count).End(xlUp).Row
ThisKeys = .Range("B2:B" & LR).Value
.Range("B2:B" & LR).Clear
.Range("B1").Resize(1, UBound(ThisKeys)) = Application.WorksheetFunction.Transpose(ThisKeys) 'transpose keys to horizontal
.Range("A1").Value = "Names / Keys"
LR = .Range("A" & .Rows.Count).End(xlUp).Row
LC = .Cells(1, .Columns.Count).End(xlToLeft).Column
.Range("B2").FormulaArray = _
"=SUMPRODUCT(--(DATA!R2C1:R" & rngData.Rows.Count + 1 & "C1=RC1)*DATA!" & rngData.Address(True, True, xlR1C1) & "*TRANSPOSE(--(KEYS!R2C2:R" & rngKeys.Rows.Count + 1 & "C2=R1C)))"
.Range("B2").AutoFill Destination:=Range(.Range(.Cells(2, 2), .Cells(2, LC)).Address), Type:=xlFillDefault 'drag to right
.Range(.Cells(2, 2), .Cells(2, LC)).AutoFill Destination:=Range(.Range(.Cells(2, 2), .Cells(LR, LC)).Address), Type:=xlFillDefault 'drag to right
.Range(.Cells(2, 2), .Cells(LR, LC)).Value = .Range(.Cells(2, 2), .Cells(LR, LC)).Value 'paste as values, not formulas
End With
Erase ThisKeys
Set rngKeys = Nothing
Set rngData = Nothing
Set wk = Nothing
End Sub
I uploaded the file with the code so you can check it out: https://drive.google.com/file/d/1rc8oOPcqP4HBFEyamku24H9hHRFpncq_/view?usp=sharing

How to enter a variable value decided by the user on vba?

I have to do a calculation on using several excel sheets and I need the user to enter the number of lines except that this number varies each year so I want this variable to be variable and entered by the user who will use the macro. Unfortunately I can't find a way to do it.
Range("B2").Select
ActiveCell.FormulaR1C1 = "=CONCATENATE(RC[7],RIGHT(RC[-1]))"
Range("B2").Select
Selection.AutoFill Destination:=Range("B2:B95145"), Type:=xlFillDefault
Range("B2:B95145").Select
Range("J1").Select
for example, when I want to perform a calculation I want the B2:B95145 to be variable, the numbers that must be entered before the macro is launched.
You can automatically find the last used row in column A for example using
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
So this code should fill as many rows in column B as there is data in column A
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1") 'define your sheet name
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
ws.Range("B2").FormulaR1C1 = "=CONCATENATE(RC[7],RIGHT(RC[-1]))"
ws.Range("B2").AutoFill Destination:=ws.Range("B2:B" & LastRow), Type:=xlFillDefault
or even just write the formula without using Autofill into all cells directly:
ws.Range("B2:B" & LastRow).FormulaR1C1 = "=CONCATENATE(RC[7],RIGHT(RC[-1]))"
If you have another formula eg in column C then just add it like
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1") 'define your sheet name
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
ws.Range("B2:B" & LastRow).FormulaR1C1 = "=CONCATENATE(RC[7],RIGHT(RC[-1]))"
ws.Range("C2:C" & LastRow).FormulaR1C1 = 'your formula here

The search block throws 'Run-time error 91'

Good day,
When I search within a column for a particular string, I get the 91 run error.
I have tried to modify the logic - copied the result to the new sheet and then, did the deletion - see the second piece of code.
Then, I found that it happens because the vba cannot find the text, so I asked a person who runs this report in the requested language to change "??????? ATLAS ????-???" to the way it is written in the data source language. But it didn't help.
Columns("A:A").Select
Selection.Find("??????? ATLAS ????-???", LookIn:=xlValues).Select
Range(ActiveCell.Address & ":" & Cells(Cells(Rows.Count, "A").End(xlUp).Row, ActiveCell.Column + 4).Address).Select
Selection.Copy
'Pasting the Ylan-Yde data to the new sheet
Sheets("interim").Select
Range("A1").Select
ActiveSheet.Paste
'Copying the Ylan-Yde data to a new sheet
Cells.Select
Selection.Copy
Sheets("interim").Select
Cells.Select
ActiveSheet.Paste
Columns("A:A").Select
Selection.Find("??????? ATLAS ????-???", LookIn:=xlValues).Select
Range("A1:A" & ActiveCell.Row - 1).EntireRow.Delete```
If I stick to the 2nd version, the code is supposed to find the a certain string in a column (it is present only once) and delete all rows before the row with the found string.
You should avoid using .Selectbecause everything can go wrong if the user interacts with excel. Instead you need to Declare variables for your workbooks and worksheets.
This approach is assuming your word only appears once and its Length is always 22, so the other ATLAS that shows on the column don't have the same length. With that in mind this should work:
Option Explicit
Sub Test()
Dim arr As Variant, LastRow As Long, ws As Worksheet, wsInterim As Worksheet, i As Long, StartRow As Long, NowDelete As Boolean
With ThisWorkbook
Set ws = .Sheets("NameWhereAtlasIs")
Set wsInterim = .Sheets("Interim")
End With
With ws
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
arr = .Range("A1:A" & LastRow).Value 'store the column A inside an array
End With
NowDelete = False
For i = 1 To UBound(arr) 'find the ATLAS with the exact length match.
If arr(i, 1) Like "*ATLAS*" And Len(arr(i, 1)) = 22 Then
StartRow = i
NowDelete = True
arr(i, 1) = vbNullString 'if you intend to delete this row too, the one with the ATLAS
End If
If NowDelete Then arr(i, 1) = vbNullString 'from the moment you find your match all the rows will be emptied on column A
Next i
ws.Range("A" & StartRow & ":A" & LastRow).Copy wsInterim.Range("A1")
ws.Range("A1:A" & LastRow).Value = arr 'this would paste the array back with the empty cells you cleared before
End Sub

Delete Row of only visible cells

I have a macro that compiles data from another worksheet and then manipulates said data. My first step is filtering by blanks and deleting all of the rows that appear. I thought I wrote the code correctly but I'm not apparently not, because each time I get a Run-time error '1004': Application-define or object-defined error
I don't see anything wrong with my variables, the column I'm filtering by is column D.
If you can see anything in my code that would help I'd love to know. Thank you!
Sub X50()
Dim wb As Workbook
Dim ws As Worksheet, macro As Worksheet, Pscrub As Worksheet
Dim lastRow As Long
Dim mlastRow As Long
Set wb = ThisWorkbook
Set ws = wb.Sheets("X50 - All")
lastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
Sheets.Add After:=Sheets(Sheets.Count), Count:=2
Sheets(3).Select
Sheets(3).Name = "Pre Scrub"
Sheets(4).Select
Sheets(4).Name = "Macro"
Set Pscrub = wb.Sheets("Pre Scrub")
Set macro = wb.Sheets("Macro")
mlastRow = macro.Range("A" & Rows.Count).End(xlUp).Row
ws.Range("AM6:AM" & lastRow).Copy Destination:=macro.Range("A1")
ws.Range("AL6:AL" & lastRow).Copy Destination:=macro.Range("B1")
ws.Range("F6:F" & lastRow).Copy Destination:=macro.Range("C1")
ws.Range("E6:E" & lastRow).Copy Destination:=macro.Range("D1")
ws.Range("G6:G" & lastRow).Copy Destination:=macro.Range("E1")
ws.Range("K6:K" & lastRow).Copy Destination:=macro.Range("F1")
macro.Range("A1").AutoFilter Field:=4, Criteria1:=(""), _
Operator:=xlFilterValues
macro.Range("D2:D" & mlastRow).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
macro.AutoFilterMode = False
wsPrescrub.Range("$A$1:$F$" & mlastRow).RemoveDuplicates Columns:=Array(1, 2, 3, 4, 5, 6) _
, Header:=xlYes
End Sub

Resources