Skip Blank Values With PasteSpecial in Excel VBA - excel

I've tried various solutions that I've found online, but with no luck yet. Here is my VBA code to copy cells from about 30 sheets and paste them all onto one sheet. Each sheet has Formulas in 4 columns that show a value if there is a value in another sheet. Like this:
=IF(Sheet1!A2<>"", Sheet1!A2, "")
Then I run my macro on the page that I want it to output:
Sub SummurizeSheets()
Dim ws As Worksheet
Application.ScreenUpdating = False
Sheets("Summary").Activate
For Each ws In Worksheets
If ws.Name <> "Summary" And ws.Name <> "Sheet1" Then
ws.Range("A2:D5406").Copy
Worksheets("Summary").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial (xlPasteValues), SkipBlanks:=True
End If
Next ws
End Sub
The output results in a lot of blank cells after the ones with actual values in them.
I tried putting that "SkipBlanks" variant in there, but that wasn't the solution. Any help would be appreciated.

This was answered for me on excelforum.com, co I figured I'd post the solution here in case it helps anyone else.
Sub SummurizeSheets()
Dim ws As Worksheet
Application.ScreenUpdating = False
Sheets("Summary").Activate
For Each ws In Worksheets
If ws.Name <> "Summary" And ws.Name <> "Sheet1" Then
ws.Range("A2:D5406").Copy
Worksheets("Summary").Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).PasteSpecial Paste:=xlPasteValues, SkipBlanks:=False
End If
Next ws
'Try inserting this line
'***********************************************************************
Worksheets("Summary").Select
'************************************************************************
'Find the last used row in column 1
LR = Cells(Rows.Count, 1).End(xlUp).Row
'Insert a formula in column E to return the row number of any non blank row
Range("E1:E" & LR).FormulaR1C1 = "=IF(RC[-4]="""","""",ROW())"
'Copy Paste Values to remove the formula
Range("E1:E" & LR).Value = Range("E1:E" & LR).Value
'Sort your data
ActiveWorkbook.Worksheets("Summary").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Summary").Sort.SortFields.Add Key:=Range("E1:E" & LR) _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Summary").Sort
.SetRange Range("A1:E" & LR)
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'Clear Column E
Range("E1:E" & LR).ClearContents
Range("A1").Select
End Sub

Related

VBA: failed to copy the first 20 rows of filtered data

I was reading the following post and tried to copy the first 20 rows (exclude header) from the filtered table. However, the last line gave me an error. What did I do wrong here ?
Sub Macro1()
'
' Macro1 Macro
'
'
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ActiveWorkbook
Set ws = ThisWorkbook.Sheets("HelloWorld")
wb.Activate
ws.Activate
ws.AutoFilterMode = False
If ws.Range("A1:L11470").AutoFilter Then
ws.Range("A1:L11470").AutoFilter
End If
ws.Range("A1:L11470").AutoFilter
ws.AutoFilter.Sort.SortFields.Add2 Key:=Range("G1:G11470"), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
With ws.AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
ws.Range("$A$1:$L$11470").AutoFilter Field:=11, Criteria1:="<>-"
ws.Range("$A$1:$L$11470").AutoFilter Field:=1, Criteria1:="10", Operator:=xlTop10Items ' <-- Error here
End Sub
The error is as follow:
I think I would take a slightly different approach to achieve the end you seem to be looking for. The code suggested below does the following based on my interpretation of your question:
Sort the data range A:L on the sheet “HelloWorld” by column G
Set a filter such that column A = 10 and column K <> “-“
Counts the first 20 filtered (visible) rows on the HelloWorld sheet and copies them (in this demonstration to Sheet2)
If this isn’t exactly what you were looking for, please comment & I’ll adjust accordingly.
Option Explicit
Sub TestTop20()
Dim ws As Worksheet, c As Range, i As Integer, LastRow As Long, EndData As Long
Set ws = ThisWorkbook.Sheets("HelloWorld")
'Determine the last 'possible' row of data
LastRow = ws.Cells(Rows.Count, 1).End(xlUp).Row
'Sort your data on column G
ws.Columns("A:L").Sort _
Key1:=ws.Range("G2"), order1:=xlDescending, Header:=xlYes
'Set the filter on columns K & A
With ws.Range("A1")
.AutoFilter
.AutoFilter Field:=1, Criteria1:="=10"
.AutoFilter Field:=11, Criteria1:="<>-"
End With
'Determine what the last visible row is - up to 20
i = 0
For Each c In ws.Range("A2:A" & LastRow)
If c.EntireRow.Hidden = False Then
i = i + 1
If i = 20 Then
EndData = c.Row
Exit For
End If
End If
Next c
If EndData < 20 Then MsgBox "Less than 20 records were detected"
'Copy the first 20 filtered records
ws.Range("A2:A" & EndData).SpecialCells(xlCellTypeVisible) _
.EntireRow.Copy Sheet2.Range("A1")
ws.AutoFilterMode = False
Application.Goto ws.Range("A1")
End Sub

Copy data based on loop and then paste data on multiple sheets created based on array

I am creating new data which is dependent upon variable x using loop, then trying to copy the data with each iteration in X and then pasting the data on multiple sheets (variable "FundSheetNames"). Here I dont know how to exit from loop FundSheetNames without next i and then again go on to X to copy new data.
Sub peer2()
ThisWorkbook.Sheets("Peer Code").Activate
Dim X As Range, Y As Range
Set X = Sheets("Peer Code").Range("J2:J11")
Dim Sht As Worksheet
Dim sheet_names As Variant
For Each sheet_Name In Sheets("Peer Code").Range("K2:K3")
For Each Y In X
Set WS = Worksheets(sheet_Name.Text)
ThisWorkbook.Sheets("Peer Fund").Activate
Range("F7:F166").Select
Selection.ClearContents
ThisWorkbook.Sheets("Peer Code").Activate
Y.Select
Selection.Copy
Range("L2").Select
Selection.PasteSpecial Paste:=xlPasteValues
Range("N2:N161").Select
Selection.Copy
ThisWorkbook.Sheets("Peer Fund").Activate
Range("F7").EntireColumn.Hidden = False
Range("$F7").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone,
SkipBlanks:= _
False, Transpose:=False
With Sheets("Peer Fund")
Set FOUNDRANGE = .Columns("F:F").Find("*", After:=.Range("F167"), searchdirection:=xlPrevious, LookIn:=xlValues)
If Not FOUNDRANGE Is Nothing Then LR1 = FOUNDRANGE.Row
End With
Range("F166:F" & LR1 + 1).EntireRow.Select
Application.Selection.EntireRow.Hidden = False
Range("A6:W" & LR1).Select
ActiveWorkbook.Worksheets("Peer Fund").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Peer Fund").Sort.SortFields.Add2 Key _
:=Range("A2:A" & LR1), SortOn:=xlSortOnValues, Order:=xlAscending, _
DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Peer Fund").Sort
.SetRange Range("A6:W" & LR1)
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Range("F7").EntireColumn.Hidden = False
Range("A5:W172").Select
Selection.SpecialCells(xlCellTypeVisible).Copy
WS.Activate
Range("A5").Select
Selection.PasteSpecial Paste:=xlPasteValues
Selection.PasteSpecial Paste:=xlPasteFormats
With WS
Set FOUNDRANGE = .Columns("F:F").Find("*",
After:=.Range("F167"),
searchdirection:=xlPrevious, LookIn:=xlValues)
If Not FOUNDRANGE Is Nothing Then LR2 = FOUNDRANGE.Row
End With
Range("F166:F" & LR1 + 1).EntireRow.Select
Application.Selection.EntireRow.Hidden = True
Range("F7").EntireColumn.Hidden = True
Next Y
Next sheet_Name
End Sub
Exit For
Open a new worksheet and put the code into a module. Then put in some values into column A. Put a few 5-s among the values.
The following is an example that looks for the value 5 in column A. When 5 is found it returns a message containing the address of the cell where it was found, in the Immediate window (CTRL+G).
Option Explicit
Sub FirstOccurrence()
Const Col As Variant = "A"
Const FirstRow As Long = 2
Const Criteria As Long = 5
Dim rng As Range
' Define the last non-empty cell.
Set rng = Columns(Col).Find("*", , xlValues, , , xlPrevious)
If rng Is Nothing Then Exit Sub
If rng.Row < FirstRow Then Exit Sub
' Define the column range from FirstRow to row of last non-empty cell.
Set rng = Range(Cells(FirstRow, Col), rng)
Dim cel As Range
For Each cel In rng
If cel.Value = Criteria Then
Debug.Print "Cell '" & cel.Address & "' contains the value '" _
& Criteria & "'."
Exit For
End If
Next cel
End Sub
You have just seen how the code finds just the first occurrence of 5.
Now remove the line Exit For and see the results in the Immediate window (CTRL+G).

Transposing a worksheet and sorting to generate two views (original and transposed)

New workbook opens fine with transposed data copied from original, but executable sorting code does not sort.
Tried various code strings from others based on extensive searches - no examples found that are similar to this effort
Private Sub CommandButton1_Click()
'clear any thing on clipboard to maximize available memory
Application.CutCopyMode = False
Application.ScreenUpdating = False
'unfreeze all panes
ActiveWindow.FreezePanes = False
'copy the data, create new workbook, and paste transposed data into worksheet
Dim newWB As Workbook, currentWB As Workbook
Dim newS As Worksheet, currentS As Worksheet
Dim LastRow As Long, LastColumn As Long
Dim SortRange As Range
'Copy the data you need
Set currentWB = ThisWorkbook
Set currentS = currentWB.Sheets("Sheet1")
LastRow = currentS.Cells(currentS.Rows.Count, "A").End(xlUp).Row
LastColumn = currentS.Cells(2, currentS.Columns.Count).End(xlToLeft).Column
Range(Cells(2, 1), Cells(LastRow, LastColumn)).Copy
'Create a new file that will receive the data and paste it
Set newWB = Workbooks.Add
With newWB
Set newS = newWB.Sheets("Sheet1")
newS.Activate
newS.Range("A1").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:=False, Transpose:=True
'reselect the range to sort and sort
LastRow = newS.Cells(newS.Rows.Count, "A").End(xlUp).Row
LastColumn = newS.Cells(1, newS.Columns.Count).End(xlToLeft).Column
ActiveSheet.Range(Cells(2, 1), Cells(LastRow, LastColumn)).Select
'newS.Range("A1").Select
'Apply sort
With ActiveSheet.Sort
.SortFields.Clear
.SortFields.Add Key:=Range("A1"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange Range(Cells(2, 1), Cells(LastRow, LastColumn))
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
'CODE RUNS TO HERE BUT DOES NOT SORT
'move back to cell C2 and freeze row and column headings
Cells(2, 3).Select
ActiveWindow.FreezePanes = True
'select all columns and adjust width and height
ActiveCell.Columns("A:DV").EntireColumn.Select
Selection.ColumnWidth = 13
Selection.Rows.AutoFit
Application.ScreenUpdating = True
End Sub
runs fine through the sort then get a
Error 1004 "Application-defined or Object-defined error"
on the freezepane code. However, the new transposed data window DOES NOT SORT.
I have made some changes to your code and this should work:
Private Sub CommandButton1_Click()
'clear any thing on clipboard to maximize available memory
Application.CutCopyMode = False
Application.ScreenUpdating = False
'unfreeze all panes
ActiveWindow.FreezePanes = False
'copy the data, create new workbook, and paste transposed data into worksheet
Dim newWB As Workbook, currentWB As Workbook
Dim newS As Worksheet, currentS As Worksheet
Dim LastRow As Long, LastColumn As Long
Dim SortRange As Range
Set currentWB = ThisWorkbook
Set currentS = currentWB.Sheets("Sheet1")
'Create a new file that will receive the data
Set newWB = Workbooks.Add
Set newS = newWB.Sheets("Sheet1")
'Copy the data you need
With currentS
LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
LastColumn = .Cells(2, .Columns.Count).End(xlToLeft).Column
.Range(.Cells(2, 1), .Cells(LastRow, LastColumn)).Copy
End With
'Paste it asap
With newS
.Range("A1").PasteSpecial Paste:=xlPasteAll, SkipBlanks:=False, Transpose:=True
Application.CutCopyMode = False
'We know we copied LastRow-1 rows, and LastColumn columns
'So our pasted data is just the other way round. So we just use that info.
'Apply sort
With .Sort
.SortFields.Clear
.SortFields.Add Key:=newS.Range("A1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
.SetRange newS.Range(newS.Cells(1, 1), newS.Cells(LastColumn, LastRow-1))
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End With
'move back to cell C2 (of newS, I assume) and freeze row and column headings
' Let us do it without Select :)
newS.Activate
With ActiveWindow
If .FreezePanes Then .FreezePanes = False
.SplitColumn = 2
.SplitRow = 1
.FreezePanes = True
End With
'adjust width and height of all columns, the right way (with our range)
With newS.Range(newS.Cells(1, 1), newS.Cells(LastColumn, LastRow-1))
.ColumnWidth = 13
.Rows.AutoFit
End With
Application.ScreenUpdating = True
End Sub

Column Sort not sorting referenced column, only on active column

I am trying to adapt some code that copies and pastes two separate ranges into another on a different sheet and then sorts it alphabetically. Problem is when i hide the sheet - even though I unhide and re-hide it to run the Macro - it seems to sort only on the Active Column.
I have singled out in bold the sorting code in the second macro below. The GetNamesList macro calls the ConsolidateList towards the end of its code.
The GetNamesList is set to run on workbook open:
Private Sub Workbook_Open()
GetNamesList
End Sub
The original code for GetNamesList is from: http://bit.ly/1y3dU6n by #Siddharth-rout
Sub GetNamesList()
Dim rng As Range, aCell As Range
Dim MyAr() As Variant
Dim n As Long, i As Long
Application.ScreenUpdating = False
Sheet28.Visible = True
'~~> Change this to the relevant sheet
With Sheet3
'~~> Non Contiguous range
Set rng = .Range("Table2[Contact 1],Table2[Contact 2]")
'~~> Get the count of cells in that range
n = rng.Cells.Count
'~~> Resize the array to hold the data
ReDim MyAr(1 To n)
n = 1
'~~> Store the values from that range into
'~~> the array
For Each aCell In rng.Cells
MyAr(n) = aCell.Value
n = n + 1
Next aCell
End With
'~~> Output the data in Sheet
'~~> Vertically Output to sheet 28
Sheet28.Cells(1, 1).Resize(UBound(MyAr), 1).Value = _
Application.WorksheetFunction.Transpose(MyAr)
ConsolidateList
Sheet28.Visible = False
Application.ScreenUpdating = True
End Sub
ConsolidateList is:
Sub ConsolidateList()
'
' ConsolidateList Macro
' Remove duplicates and blanks
'
With Sheet28.Range("A1:A1000")
.Value = .Value
.RemoveDuplicates Columns:=1, Header:=xlNo
On Error Resume Next
.SpecialCells(xlCellTypeBlanks).Delete xlShiftUp
On Error GoTo 0
End With
Columns("A:A").Sort Key1:=Range("A1"), Order1:=xlAscending
End Sub
Thanks for your help...
**Update - recording of macro to do the same thing...
Sub TestSort()
'
' TestSort Macro
'
Sheets("Jan").Select
Sheets("Sheet1").Visible = True
ActiveWindow.SmallScroll Down:=-405
Range("A1:A134").Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("A1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("A1:A134")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
ActiveWindow.SmallScroll Down:=-245
Sheets("Sheet1").Select
ActiveWindow.SelectedSheets.Visible = False
End Sub
Thanks #S-O. By taking your suggestion and puzzling over the recorded code I was able to cobble together the following:
Sub ConsolidateList()
'
' ConsolidateList Macro
' Remove duplicates and blanks
'
With Sheet28.Range("A1:A1000")
.Value = .Value
.RemoveDuplicates Columns:=1, Header:=xlNo
On Error Resume Next
.SpecialCells(xlCellTypeBlanks).Delete xlShiftUp
On Error GoTo 0
End With
Sheet28.Sort.SortFields.Clear
Sheet28.Sort.SortFields.Add Key:=Range("A1"), _
SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("A1:A134")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End Sub
Though an ActiveWorkbook seems to have snuck in there...!
**UPDATE
Replaced
With ActiveWorkbook.Worksheets("Sheet1").Sort
.SetRange Range("A1:A134")
With:
At top
Dim Lastrow As Integer
Then
Lastrow = Sheet28.Cells.Find("*", searchorder:=xlByRows,searchdirection:=xlPrevious).Row
With Sheet28.Sort
.SetRange Range("A1:A" & Lastrow)
That fixed it...

Update macro in vba

I created this macro to search through two spreadsheets and update one from the other based on unique keys that each row has. It will copy the first sheet to a temp sheet then unfilter and unhide everything. Next it will sort them by key so that they are all in order. after that it will move two columns to be excluded from the update to the front and update the rest. To update it will search through using the match function and if it comes up as an error (which means the row isn't there) it will add it to the end of the update sheet. Otherwise, it will copy and paste each row from the source to the update sheet. It all works but for some reason it won't update past line 24 and I have no idea why. I've stepped through it and it doesn't break, it just doesn't update. I am new to vba so any help would be greatly appreciated.
Sub crossUpdate()
Dim rng1 As Range, rng2 As Range, rng1Row As Range, rng2Row As Range, Key As Range, match As Variant
Dim wb1 As Workbook
Dim wb2 As Workbook
Dim endRng2 As Long
Set wb2 = Workbooks("011 High Level Task List v2.xlsm")
Set wb1 = Workbooks("011 High Level Task List v2 ESI.xlsm")
'Unfilter and Unhide both sheets
With wb1.Sheets("Development Priority List")
.Cells.EntireColumn.Hidden = False
.Cells.EntireRow.Hidden = False
.AutoFilterMode = False
End With
With wb2.Sheets("Development Priority List")
.Cells.EntireColumn.Hidden = False
.Cells.EntireRow.Hidden = False
.AutoFilterMode = False
End With
'Copy and paste original sheet to new temp sheet
wb1.Sheets("Development Priority List").Activate
wb1.Sheets("Development Priority List").Cells.Select
Selection.Copy
Sheets.Add.Name = "SourceData"
wb1.Sheets("SourceData").Paste
N = Cells(Rows.Count, "A").End(xlUp).Row
Set rng1 = wb1.Sheets("SourceData").Cells.Range("A2:A" & N)
Set rng1Row = rng1.EntireRow
'Sort temp sheet by key
wb1.Worksheets("SourceData").Sort.SortFields.Clear
wb1.Worksheets("SourceData").Sort.SortFields.Add Key:=wb1.Sheets("SourceData").Cells.Range("A2:A" & N), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With wb1.Worksheets("SourceData").Sort
.SetRange Range("A1:Z1000")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'Sort update sheet by key
wb2.Activate
wb2.Worksheets("Development Priority List").Sort.SortFields.Clear
wb2.Worksheets("Development Priority List").Sort.SortFields.Add Key:=wb2.Sheets("Development Priority List").Cells.Range("A2:A" & N), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With wb2.Worksheets("Development Priority List").Sort
.SetRange Range("A1:Z1000")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'Dev columns moved on SourceData sheet
wb1.Sheets("SourceData").Activate
Columns("F:G").Select
Selection.Cut
Columns("A:A").Select
Selection.Insert Shift:=xlToRight
'Dev columns moved on update sheet
wb2.Sheets("Development Priority List").Activate
Columns("F:G").Select
Selection.Cut
Columns("A:A").Select
Selection.Insert Shift:=xlToRight
'Update sheet searched and updated from SourceData
Set rng2 = wb2.Sheets("Development Priority List").Cells.Range("C2:C" & N)
endRng2 = rng2.Rows.Count
For i = 2 To rng1.Rows.Count + 1
Set Key = wb1.Sheets("SourceData").Range("C" & i)
match = Application.match(Key, rng2, 0)
'Rows that don't exsist in update sheet are added
If IsError(match) Then
wb1.Sheets("SourceData").Range("C" & i, "Z" & i).Copy
wb2.Sheets("Development Priority List").Range("C" & endRng2, "Z" & endRng2).Select
wb2.Sheets("Development Priority List").Paste
endRng2 = endRng2 + 1
'All other rows are scanned for changes
Else
For j = 3 To wb1.Sheets("SourceData").Range("C" & i, "Z" & i).Columns.Count
wb2.Sheets("Development Priority List").Cells(j, i).Value = wb1.Sheets("SourceData").Cells(j, i)
Next j
End If
Next i
'SourceData sheet deleted
Application.DisplayAlerts = False
wb1.Sheets("SourceData").Delete
Application.DisplayAlerts = True
'Dev columns moved back on update sheet
wb2.Sheets("Development Priority List").Activate
Columns("A:B").Select
Selection.Cut
Columns("H:H").Select
Selection.Insert Shift:=xlToRight
wb1.Activate
It took me a few times coming back to this to figure out what was wrong. Here is what I believe is happening:
This code:
For j = 3 To wb1.Sheets("SourceData").Range("C" & i, "Z" & i).Columns.Count
wb2.Sheets("Development Priority List").Cells(j, i).Value = wb1.Sheets("SourceData").Cells(j, i)
Next j
Is looping from 3 to the number of columns between "C" and "Z" (ALWAYS 24). The bit inside the FOR loop is using Cells(<row>, <column>) syntax to copy from one cell to another. Because J is always looping from 3 to 24 then ROWS 3 through 24 are the only ones that will be updated. Perhaps you meant Cells(i,j)?

Resources