Combine Print Ranges from Multiple Worksheets VBA EXCEL - vba

I am trying to figure out how to print the "ActiveSheet" or Sheet1 along with "Sheet5" (rows 1-6, A:M) being displayed at the bottom with a 2 row space in between the end of Sheet1 and the beginning of data from Sheet5. I've been trying to look up similar questions and read something about a "Union" but I wasn't sure how it would fit here.
Private Sub CommandButton1_Click()
Dim Sel_Manager As String
'Headers repeated at the top
Application.PrintCommunication = False
With ActiveSheet.PageSetup
.PrintTitleRows = "$2:$2"
.PrintTitleColumns = "$B:$M"
.Orientation = xlLandscape
.Zoom = False
.FitToPagesWide = 1
.FitToPagesTall = 1
End With
'Manager selection through ComboBox dropdown
Sel_Manager = ComboBox1
'Inserting autofilters for worksheet
Cells.Select
Selection.AutoFilter
'Manager defined in the dropdown ComboBox
ActiveSheet.Range("B2", Range("M2").End(xlDown)).AutoFilter Field:=1, Criteria1:=Sel_Manager
ActiveSheet.Range("B2", Range("M2").End(xlDown)).AutoFilter Field:=2, Criteria1:="A"
'Here I select range to be printed and specify manager in filename
ActiveSheet.Range("B2", Range("M2").End(xlDown)).Select
Selection.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _
Sel_Manager + ".pdf", Quality:=xlQualityStandard, _
IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:=True
ActiveSheet.ShowAllData
Application.PrintCommunication = True
End Sub

This may give you some ideas.
I created two worksheets. One, called "Main", contains data that has "names" in column B and some As in column C. The other, called "Extra" contains the six rows to appear at the bottom of the filtered data.
I do not use Excel's identifiers when referencing worksheets. The first sheet will have an identifier of Sheet1 and a name of "Sheet1". If you immediately create another sheet it will have an identifier of Sheet2 and a name of "Sheet2". However, if Sheet1 is renamed before the second sheet is created, it will have an identifier of Sheet2 and a name of "Sheet1". It can all get very confusing.
I have hardcoded the selected manager as "Aaaaa" rather than make it a user entered parameter. I have prepared worksheet "Main" for printing but have not output it.
Option Explicit
Sub Test()
Dim Manager As String
Dim RngFiltered As Range
Dim RowSht1Last As Long
Manager = "Aaaaa"
With Worksheets("Main")
.AutoFilterMode = False ' Switch off auto filtering if on
' Find last row containing a value
RowSht1Last = .Cells.Find("*", .Range("A1"), xlFormulas, , xlByRows, xlPrevious).Row
With .Range("B2:M2")
.AutoFilter Field:=1, Criteria1:=Manager
.AutoFilter Field:=2, Criteria1:="A"
End With
Set RngFiltered = .Cells.SpecialCells(xlCellTypeVisible)
' Just to show the filtered range. Note, I cannot find a documented limit
' on the number of sub-ranges within a range. If there is a limit, I have
' never managed to reach it. However Range.Address has a limit which is a
' little under 255.
Debug.Print Replace(RngFiltered.Address, "$", "")
Worksheets("Extra").Range("A1:M6").Copy Destination:=.Cells(RowSht1Last + 2, "A")
' ###### Output visible rows
' Delete rows copied from Sheet5
.Rows(RowSht1Last + 2 & ":" & RowSht1Last + 8).Delete
End With
End Sub

Related

using a wildcard to prevent subtotal line from being filtered and copied excel vba

I have a situation where I have a list of salespeople that gets filtered and moves all that filtered data to it's own spreadsheet. The problem that I am having is the macro is also filtering the subtotal line so its creating a sheet with no data and it's also creating a situation where the sheet is so large I cant save the file.
I wrote some code that i thought would prevent any worksheet starting with "Sheet" to not get filtered, but I don't know how to use a wildcard in a string. Need a wildcard since the "Sheet #" is different depending on the month.
Dim Sht As Worksheet
Dim Rng As Range
Dim List As Collection
Dim varValue As Variant
Dim E As Long
' // Set your Sheet name
Set Sht = Application.ActiveSheet
' // set your auto-filter, A6
With Sht.Range("A2")
.AutoFilter
End With
' // Set your agent Column range # (2) that you want to filter it
Set Rng = Range(Sht.AutoFilter.Range.Columns(22).Address)
ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort.SortFields.Add
Key:=Range _
("V:V"), SortOn:=xlSortOnValues, Order:=xlAscending,
DataOption:= _
xlSortTextAsNumbers
With ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
' // Create a new Collection Object
Set List = New Collection
' // Fill Collection with Unique Values
On Error Resume Next
For E = 2 To Rng.Rows.Count
List.Add Rng.Cells(E, 1), CStr(Rng.Cells(E, 1))
Next E
' // Start looping in through the collection Values
For Each varValue In List
' // Filter the Autofilter to macth the current Value
'Rng.AutoFilter Field:=22, Criteria1:=varValue, _
' Operator:=xlAnd, Criteria2:="<>"
Rng.AutoFilter Field:=22, Criteria1:="<>Sheet*", _
Operator:=xlAnd, Criteria2:=varValue
' // Copy the AutoFiltered Range to new Workbook
'If List = (Blanks) Then
Sht.AutoFilter.Range.Copy
The Criteria1:="<>Sheet*" code is what I tried to do and the code above is what is was before. So my question is what can be done to prevent to the subtotal row sheet from being created?
Don't add the sheet name to the autofilter criteria. Just check the sheet name before you autofilter at all.
If Not ActiveSheet.Name Like "Sheet*" Then
'Do whatever you need to do
End If
On the other hand, you can remove the Not keyword if you wanted to include sheet names starting with sheet:
If ActiveSheet.Name Like "Sheet*" Then
Append a timestamp to your sheetname string. The basic idea is to use the "time" function, i.e. time (now), where time can be extracted as yy,mm,dd,hh,ss. Separately define variables strings to store each of the desired time components. Then, create a name like sheetname= myname string+my dd+ my hh.... I think it can become problematic if you try to add the time results directly to your sheetname string, so save the time result first, then combine strings.
I like to start my project by setting up my workbook with sheets(1).name ="blank". Hide it, unhide it, and copy it perpetually.
Good luck.
So after playing with the code for awhile I realized that using a wildcard for "Sheet*" wouldn't work since all the filtered results started with "Sheet" in the first place. But by adding
If varValue <> "" Then (which states that if the filtered result isn't blank than continue code) after Rng.AutoFilter Field:=22, Criteria1:="<>Sheet*", Operator:=xlAnd, Criteria2:=varValue
it fixed the issue. Now the code skips the subtotal line successfully.

Avoiding Excel range difragmantation with Areas So append such form of filtered range at one PDF result

I want create report from a filtered Table of Worksheet in One pdf file.
This have two approach:
(1)
1- Using Print Area, that works correctly in this episode of exporting pdf.
2- Using given Range to .ExportAsFixedFormat with SpecialCells(xlCellTypeVisible) Range which that generating wrong result with fragmented Areas section in pdf.
In this episode of this question, sub question is why above range had fragmented and how can correct this?
How can I do that with avoid of Range fragmentation by Areas?
(2) appending result to previous pdf
This report needs several filtered result type of change programmatically one specific column criteria in above Table.
Of course, the Table has some filtered rows or columns.
Thus, How can I append such filtered form of Table in new section page at the end of the pdf report file? (without save and merge several pdf s; so appending quietly in memory (or in one file) and publish resulted pdf.)
I tried code below but...
Sub PDFExport()
Dim Rng As Range
ActiveSheet.Unprotect
Set Rng = Range("tblInsRep[#All]").SpecialCells(xlCellTypeVisible)
ActiveSheet.PageSetup.PrintArea = Sheets("Sheet1").Range("A4:H" & _
ActiveSheet.ListObjects("tblInsRep").ListRows.Count + 4).Address
Rng.ExportAsFixedFormat _
Type:=xlTypePDF, _
fileName:=ThisWorkbook.path & "rep.pdf", _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=True
ActiveSheet.Protect AllowFiltering:=True
End Sub
Produced Non-coherent pdf file as Fragmented with filtered rows and columns by Areas, each Area sectioned in new page! (Episode ONE of sub question)
How ever I followed CreateObject("AcroExch.PDDoc") solutions for appending an Excel range at end of source pdf but cant reach summed up result, contains two above issues solution integrated.Episode TWO of sub question)
Thanks.
I think the best will be to copy the data you are wanting to get onto the PDF to "Helper" sheet and then save that sheet as PDF.
What will help to get each section of copied info to another sheet is to insert page breaks after each set of data is copied.
See code below:
Option Explicit
Sub PDFExport()
Dim CopyRng As Range
Dim HelpSheetLastRow As Long
Dim DataSheet As Worksheet
Dim HelperSheet As Worksheet
Set DataSheet = ThisWorkbook.Sheets("SheetNameHere")
Set HelperSheet = ThisWorkbook.Sheets.Add
DataSheet.Unprotect
'Set some range to the cells you want to copy
'
'
'If there is a named range tblInsRep in your sheet
Dim tblInsRepRowNum As Long
'Provided that there is a named range in the sheet with name tblInsRep
tblInsRepRowNum = DataSheet.Range("tblInsRep").Rows.Count
Set CopyRng = DataSheet.Range(DataSheet.Cells(4, "A"), _
DataSheet.Cells(4 + tblInsRepRowNum, "H"))
With HelperSheet
' +2 to have a line betwen the data entries
HelpSheetLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row + 2
.Range(.Cells(HelpSheetLastRow, 1), _
.Cells(1 + CopyRng.Rows.Count, 1 + CopyRng.Columns.Count)) = CopyRng.Value
End With
'Set some range to the cells you want to copy
Set CopyRng = DataSheet.Range(DataSheet.Cells(4, "A"), _
DataSheet.Cells(4 + tblInsRepRowNum, "H"))
'
'
'
With HelperSheet
' +2 to have a line betwen the data entries
HelpSheetLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row + 2
'Inserting a page break will ensure the next copied range is start on the next page
.HPageBreaks.Add .Cells(HelpSheetLastRow, 1)
.Range(.Cells(HelpSheetLastRow, 1), _
.Cells(HelpSheetLastRow + CopyRng.Rows.Count, 1 + CopyRng.Columns.Count)) = CopyRng.Value
End With
'Set some range to the cells you want to copy
Set CopyRng = DataSheet.Range(DataSheet.Cells(4, "A"), _
DataSheet.Cells(4 + tblInsRepRowNum, "H"))
'
'
'
With HelperSheet
' +2 to have a line betwen the data entries
HelpSheetLastRow = .Cells(.Rows.Count, "A").End(xlUp).Row + 2
'Inserting a page break will ensure the next copied range is start on the next page
.HPageBreaks.Add .Cells(HelpSheetLastRow, 1)
.Range(.Cells(HelpSheetLastRow, 1), _
.Cells(HelpSheetLastRow + CopyRng.Rows.Count, 1 + CopyRng.Columns.Count)) = CopyRng.Value
End With
'ActiveSheet saves the PDF without splitting the ranges.
HelperSheet.ExportAsFixedFormat Type:=xlTypePDF, _
Filename:=ThisWorkbook.Path & "\rep.pdf", Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=True
'remove helper sheet
'remove alerts to stop the delete confirmation popping up
Application.DisplayAlerts = False
HelperSheet.Delete
Application.DisplayAlerts = True
ActiveSheet.Protect AllowFiltering:=True
End Sub

In VBA (Excel) how can Column A insert an ID header followed by 1-X UNTIL it reaches the empty cell representing the highest row with data?

I am trying to create a macro that will insert a column, which is to be the first column in the spreadsheet (A) while shifting all original columns over 1 column to the right.
I then need this first column to create the header "ID" with each one numerically counting the rows:
[A]
ID
1
2
3
I only want the numbering to stop once it has reached the last relevant row in the spreadsheet. I was able to generate the following VBA by doing what I would normally do to accomplish this task while recording the macro and ended up with this:
Sub InsertID()
'
' InsertID Macro
' Add first column to be 1-##
'
' Keyboard Shortcut: Ctrl+Shift+N
'
Columns("A:A").Select
Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
Range("A1").Select
ActiveCell.FormulaR1C1 = "ID"
Range("A2").Select
ActiveCell.FormulaR1C1 = "1"
Range("A3").Select
ActiveCell.FormulaR1C1 = "2"
Range("A2:A3").Select
Selection.AutoFill Destination:=Range("A2:A522")
Range("A2:A522").Select
Range("A1").Select
End Sub
Obvoiusly, this doesn't work for my situation. The template I was using only had 521 rows. This number is going to be a variable which can usually be determined by the number of rows in the original column A (Which is now column be after running this macro).
I have extensively looked into how to create a variable for number of rows in a specific column but have been unable to find a question that has similar enough parameters even though it seems so simple.
Thanks in advance
Try this...
Sub CreateIDColumn()
lr = ActiveSheet.UsedRange.Rows.Count
Columns(1).Insert
Range("A1").Value = "ID"
Range("A2:A" & lr).Formula = "=ROW()-1"
Range("A2:A" & lr).Value = Range("A2:A" & lr).Value
End Sub
I believe the following code will do what you want to do. It declares variables (in case Option Explicit is declared - which it should be), inserts the column, finds the last row (if there is one), and inserts relevant data.
Private Sub InsertID()
Dim lastrow, i As Integer 'declaring variables
'adding column
Range("A1").EntireColumn.Insert
'getting last row #
If Application.WorksheetFunction.CountA(Cells) <> 0 Then
lastrow = Cells.Find(What:="*", _
After:=Range("A1"), _
Lookat:=xlPart, _
LookIn:=xlFormulas, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False).Row
Else
lastrow = 1
End If
'setting value of cell A1
Cells(1, 1) = "ID"
'setting value for the rest of the cells in column A
For i = 2 To lastrow
Cells(i, 1) = i - 1
Next
End Sub

VBA Macro to AutoFilter by criteria, copy visible results from one column into an Array, and then AutoFilter a different sheet by that Array

I'm trying to create a custom report for a technically illiterate client, and I need some help.
So here's what I need to do:
I have two different Workbooks as input files: a Case List (cases.csv) and a Revenue Report (revenue.csv), which are output from a web service.
The Case List contains Case Filenames (Column K), and Usernames (Column W). All cases and users are listed.
The Revenue Report contains Case Filenames (Column C), and the Revenue Data (Columns G through T), but does not contain associated Usernames (which I need to filter by).
The amount of entries in these lists change all the time, so I need something dynamic.
I basically need to AutoFilter the Revenue Report to only show Cases that are assigned to a specific User.
This is what I have so far for the first part:
Set MyRange = Range("A1").CurrentRegion
Selection.AutoFilter Field:=23, Criteria1:="User1"
Range("K2").Select
Range(Selection, Selection.End(xlDown)).Select
Dim arr As Variant
arr = Selection
This will AutoFilter the Case List to only show Cases associated with "User1", and then copy the visible results of Column K (Case Filenames associated with User1) to an array.
I then wanted to use that Array as the criteria for the second AutoFilter on the second sheet (revenue.csv), so that the Revenue Information for only Case Filenames associated with User1 will be visible.
I'm getting stuck on the second part. Preferably, I want the Client to download both reports as CSV files to a specified directory (let's say C:\test\ as an example).
Then I want them to open this Macro-enabled workbook (let's call it macro.xlsm), which will load the Worksheets of both reports into itself, and then run the code to AutoFilter>Results to Array>AutoFilter again.
Here's my sorry attempt at the loading script.
Sub Button1_Click()
Dim directory As String, fileName As String, sheet As Worksheet, total As Integer
Application.ScreenUpdating = False
Application.DisplayAlerts = False
directory = "C:\test\"
fileName = Dir(directory & "*.xl??")
Do While fileName <> ""
Workbooks.Open (directory & fileName)
For Each sheet In Workbooks(fileName).Worksheets
total = Workbooks("macrotest.xlsm").Worksheets.Count
Workbooks(fileName).Worksheets(sheet.Name).Copy _
after:=Workbooks("import-sheets.xlsm").Worksheets(total)
Next sheet
Workbooks(fileName).Close
fileName = Dir()
Loop
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
Basically, I would provide them this macro.xlsm with all the code in it, and all they would have to do is download the two reports into a specific directory, open macro.xlsm, then click a button, and the reports will load in, auto-filter themselves, and the Revenue sheet is filtered by only Cases associated with User1.
HELP!
i have tried to recreate your problem, so the data might be in different cells,
File 1, cases.csv
Col A - Case names
Col B - Usernames
File 2, revenues.csv
Col A - Case names
Col B - Revenue data
File 3, Report.xlsm
Range("A1") = "username"
Col C:D - output (Row 1 is headers)
Run below macro from File 3
Sub getRevenue()
'
' Macro2 Macro
'
'
Range("C2:D" & Range("C" & Rows.Count).End(xlUp).Row).ClearContents
Dim username As String
username = Range("A1")
Dim wbCases As Workbook
Dim numCases As Integer
Set wbCases = Workbooks.Open("C:\xxx\xxx\xxx\cases.csv")
ActiveSheet.Range("$A$1:$B$" & Range("A" & Rows.Count).End(xlUp).Row).AutoFilter _
Field:=2, Criteria1:=username
Range("A2:A" & Range("A" & Rows.Count).End(xlUp).Row).Select
Selection.Copy
ThisWorkbook.Activate
Range("C2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
numCases = Selection.Rows.Count
wbCases.Close
Dim cases() As String
ReDim cases(1 To numCases) As String
For i = 1 To numCases
cases(i) = Selection(i, 1)
Next i
Dim wbRev As Workbook
Set wbRev = Workbooks.Open("C:\xxx\xxx\xxx\Revenue.csv")
ActiveSheet.Range("$A$1:$B$" & Range("A" & Rows.Count).End(xlUp).Row).AutoFilter _
Field:=1, Criteria1:=cases, Operator:=xlFilterValues
Range("$A$2:$B$" & Range("A" & Rows.Count).End(xlUp).Row).Select
Selection.Copy
ThisWorkbook.Activate
Range("C2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
wbRev.Close
End Sub
This will generate a list of Cases names and Revenue data for the specified username in Range("A1")
Cheers

How to combine reverse-chronological sheets while rearranging cells, preventing stacking?

OK, I will try to explain this well. An odd problem to solve, and it's WAY beyond my skill level (novice).
Excel 2011 for Mac.
The workbook has 11 sheets.
Sheet names are all 'Month Year'. (Eg: sheet 1 is titled "June 2013")
Sheet names are reverse chronological. (June 2013, May 2013, April 2013 etc)
Each sheet has data in the same layout:
A1 is the sheet's name. B1 through to a varying endpoint on B hold dates. (approx two weeks but varies greatly between sheets)
A2 and downward in A is all names, as "last,first".
The remaining columns below B1 and outward are either blank, 0's, or 1's (attendance for date at row 1).
What I need to do:
Get ALL of the data in one sheet, with dates in chronological order along row 1 and names in alphabetical order down column A. Without messing up the associations between the names and the 0/1/blank values that existed on the original sheet.
What I have done:
I did this manually using the Excel GUI on a very similar sheet. It took forever!
I also have been writing or sourcing Subs to do some of the other work needed to these sheets to get them ready for this big rearranging. But I am already at my limits writing super simple "find rows with the word 'total' in them" sorts of stuff.
I know WHAT to do here, but have no clue HOW.
Start with the oldest sheet, copy into a new sheet(YearSheet).
Take names from 2ndOldest, paste into A under names already there.
Take dates and the cells beneath them into YearSheet, but staggered out on the columns so they begin where the first sheet left off.
Repeat again with nextYoungest, same deal. Names under names, dates and data shoved out along the letter axis to prevent overlap with prior dates.
Eventually it's a long list of names in A, and a descending step-pattern of data blocks in the remainder.
Sort it all by A, alphabetically.
Find and compress identical names into one row, without losing the data along the way (Why does Excel only keep top left? Aaargh!)
So, I know that's a lot to ask here.
Have no idea if this is too much or over the top for a question, but I am just stumped so am posting it in hopes somebody can make sense of the VBA to do it.
I created a workbook based on your description to use as sample data.
I wrote this macro
Sub Main()
Dim CombinedData As Variant
Dim TotalCols As Integer
Dim TotalRows As Long
Dim PasteCol As Integer
Dim PasteRow As Long
Dim i As Integer
Dim PivSheet As Worksheet
ThisWorkbook.Sheets.Add Sheet1
On Error GoTo SheetExists
ActiveSheet.Name = "Combined"
On Error GoTo 0
Range("A1").Value = "Name"
For i = ThisWorkbook.Sheets.Count To 1 Step -1
If Sheets(i).Name <> "Combined" Then
Sheets(i).Select
TotalCols = Sheets(i).Columns(Columns.Count).End(xlToLeft).Column
TotalRows = Sheets(i).Rows(Rows.Count).End(xlUp).Row
PasteCol = PasteCol + TotalCols - 1
If PasteRow = 0 Then
PasteRow = 2
Else
PasteRow = PasteRow + TotalRows - 1
End If
'Copy Date Headers
Range(Cells(1, 2), Cells(1, TotalCols)).Copy Destination:=Sheets("Combined").Cells(1, PasteCol)
'Copy Names
Range(Cells(2, 1), Cells(TotalRows, 1)).Copy Destination:=Sheets("Combined").Cells(PasteRow, 1)
'Copy Data
Range(Cells(2, 2), Cells(TotalRows, TotalCols)).Copy Destination:=Sheets("Combined").Cells(PasteRow, PasteCol)
End If
Next
Sheets("Combined").Select
ActiveSheet.Columns.AutoFit
With ActiveSheet.Sort
.SortFields.Clear
.SortFields.Add Key:=Range("A1"), _
SortOn:=xlSortOnValues, _
Order:=xlAscending, _
DataOption:=xlSortNormal
.SetRange ActiveSheet.UsedRange
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Set PivSheet = Sheets.Add
ThisWorkbook.PivotCaches.Create(SourceType:=xlDatabase, _
SourceData:=Sheets("Combined").UsedRange, _
Version:=xlPivotTableVersion14).CreatePivotTable _
TableDestination:=PivSheet.Range("A1"), _
TableName:="PivotTable1", _
DefaultVersion:=xlPivotTableVersion14
For i = 1 To PivSheet.PivotTables("PivotTable1").PivotFields.Count
With ActiveSheet.PivotTables("PivotTable1")
If i = 1 Then
.PivotFields(i).Orientation = xlRowField
.PivotFields(i).Position = 1
Else
ActiveSheet.PivotTables("PivotTable1").AddDataField .PivotFields(i), _
"Sum of " & .PivotFields(i).Name, _
xlSum
End If
End With
Next
Application.DisplayAlerts = False
Sheets("Combined").Delete
Application.DisplayAlerts = True
PivSheet.Name = "Combined"
CombinedData = ActiveSheet.UsedRange
Cells.Delete
Range(Cells(1, 1), Cells(UBound(CombinedData), UBound(CombinedData, 2))).Value = CombinedData
Range("A1").Value = "Name"
Range(Cells(1, 1), Cells(1, UBound(CombinedData, 2))).Replace "Sum of ", ""
Columns.AutoFit
Exit Sub
SheetExists:
Application.DisplayAlerts = False
Sheets("Combined").Delete
Application.DisplayAlerts = True
Resume
End Sub
Which produces this result:
This was written in Excel 2010 in windows. I don't know what the differences are between the pc and mac versions but this may work for you.