VBA Includes empty cells in table formatting - vba

Very new to VBA.
What I am trying to do:
1) Copy sheet from (source) workbook to active (master) workbook
2) Delete unnecessary columns of the copied data in the master workbook
3) Select cells with data in the master workbook and format as table (this is where I am stuck)
Sub first_sub()
'Open user Raw Data workbook
Workbooks.Open Filename:= _
"C:\Users\" & Environ("UserName") & "\Downloads\File.xls"
'Copy user Raw Data sheet to Data Master sheet
Workbooks("File.xls").Sheets("Records").Copy _
Before:=Workbooks("Macro Main.xlsm").Sheets(1)
'Close user Raw Data
Workbooks("File.xls").Close
End Sub
Sub Format()
Sheets("Records").Range("D:G,I:K,M:Y,AA:AA,AF:AM").EntireColumn.Clear
Sheets("Records").Range("D:G,I:K,M:Y,AA:AA,AF:AM").EntireColumn.Delete
End Sub
Sub MakeTable()
Dim tbl As ListObject
Dim rng As Range
Set rng = Range(Range("A1"), Range("A1").SpecialCells(xlLastCell))
Set tbl = ActiveSheet.ListObjects.Add(xlSrcRange, rng, , xlYes)
tbl.TableStyle = "TableStyleMedium3"
End Sub
The problem is in point 3. For some reasons, VBA selects columns up to "AM", even though I deleted them in previous sub, and as a result - I have the table full of empty columns all the way up to AM. How to solve this? Thank you in advance.

Check how .SpecialCells(xlLastCell) works: Range.SpecialCells Method (Excel)
I think your range variable rng is referencing from range Range("A1") to the last used cell in the column range AM
Set rng = Range(Range("A1"), Range("A1").SpecialCells(xlLastCell))
Try adding this line after to check if the range is actually targeting your desired range:
rng.select
To solve this problem you can try:
Set rng = Range("A1").CurrentRegion
Or finding the last cell in column A...
Code:
Sub MakeTable()
Dim tbl As ListObject
Dim rng As Range
Set rng = Range("A1").CurrentRegion
Set tbl = ActiveSheet.ListObjects.Add(xlSrcRange, rng, , xlYes)
tbl.TableStyle = "TableStyleMedium3"
End Sub

Related

How to merge 3 cells with using an absolute cell reference in VBA

Trying to put together a VBA macro Im trying to reference Sheet1A8(CSWAH_) as an absolute cell reference and merge SeparateA7(Last Name) and SeperateB7(First Name) so they'll display in SeperateE7(ASA Naming) and be able to carry it all the way down from E7 to E100.
Is something like this even possible?
Try this.
Sub Demo()
Dim ws As Worksheet
Dim rng As Range
Dim lastRow As Long
Set ws = ThisWorkbook.Sheets("Sheet1") 'change Sheet1 to your data sheet
With ws
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row 'last row with data using Column A
Set rng = .Range("E7:E" & lastRow) 'set range in Column E
rng.Formula = "=$B$1&""_""&A7&"",""&B7" 'enter formula in range
rng.Value = rng.Value 'display values in range
End With
End Sub

VBA - Copy template sheets to multiple sheets of another workbook if criteria met

I've been trying to get the code to work for the past week with no luck. I tried various modifications, which ends up giving different error codes.
The first Error I was getting was with Set rng = Intersect(.UsedRange, .Columns(2))
Object doesn’t support this property or method
So then I changed this to just going through the entire column just to see if it would work : Set rng = Range("B:B"), when I do that then it reads through and I get an error for Set HyperlinkedBook = Workbooks.Open(Filename:=cell.Offset(0, -1).Value) with the error code:
run time error 1004 Sorry we couldn’t find 24 James.xlsx
Is it possible it was moved, renamed or deleted?
I believe that this line of the code is assuming that the hyperlink should open a different workbook with that name, however this is not the case. The hyperlink on the summary sheet links through to other sheets on the same master workbook, only the templates are on a separate book.
So to overcome this I tried changing this line as well and ended up with the code below, which manages to open the template workbook, and copy just the tab name onto the first sheet and then gives an error for the following line TemplateBook.Sheets("Red").Copy ActiveSheet.Paste, saying
subscript out of range
Sub Summary()
Dim MasterBook As Workbook
Set MasterBook = ActiveWorkbook
With MasterBook
Dim rng As Range
Set rng = Range("B:B")
End With
Dim TemplateBook As Workbook
Set TemplateBook = Workbooks.Open(Filename:=" C:\Users\Desktop\Example template.xlsx")
Dim cell As Range
For Each cell In rng
If cell.Value = "Red" Then
cell.Offset(0, -1).Hyperlinks(1).Follow NewWindow:=False, AddHistory:=True
TemplateBook.Sheets("Red").Copy ActiveSheet.paste
ElseIf cell.Value = "Blue" Then
cell.Offset(0, -1).Hyperlinks(1).Follow NewWindow:=False, AddHistory:=True
TemplateBook.Sheets("Blue").Copy ActiveSheet.paste
End If
Next cell
End Sub
I tried several more variations but I just can’t get it to copy the correct template, switch back to the master workbook sheet, follow through the link to correct sheet in the same master workbook, and paste the template.
A few comments about the modifications I made to your code:
Instead of using the entire Column B, try to use only cells in Column B that have values inside them.
Try to avoid using ActiveWorkbook, if the code lies in the same workbook then use ThisWorkbook instead.
When you set a Range, fully qualify it by stating the Workbook and Worksheet, as in : Set Rng = Sht.Range("B1:B" & Sht.Cells(Sht.Rows.Count, "B").End(xlUp).Row).
I replaced your 2 Ifs with Select Case, as they the result in both is the same, and it will also allow you more flexibility in the future to add more cases.
When you copy an entire sheet with TemplateBook.Sheets("Red") and paste it to another Workbook, the syntax is TemplateBook.Sheets("Red").Copy after:=Sht.
Code
Option Explicit
Sub Summary()
Dim MasterBook As Workbook
Dim Sht As Worksheet
Dim Rng As Range
Set MasterBook = ThisWorkbook '<-- use ThisWorkbook not ActiveWorkbook
Set Sht = MasterBook.Worksheets("Sheet3") '<-- define the sheet you want to loop thorugh (modify to your sheet's name)
Set Rng = Sht.Range("B1:B" & Sht.Cells(Sht.Rows.Count, "B").End(xlUp).Row) '<-- set range to all cells in column B with values
Dim TemplateBook As Workbook
Set TemplateBook = Workbooks.Open(Filename:="C:\Users\Desktop\Example template.xlsx")
Dim cell As Range
For Each cell In Rng
Select Case cell.Value
Case "Red", "Blue"
cell.Offset(0, -1).Hyperlinks(1).Follow NewWindow:=False, AddHistory:=True '<-- not so sure what values you have here
TemplateBook.Sheets(cell.Value).Copy after:=Sht '<-- paste after the sheet defined
Case Else
' do something if you have other cases , not sure it's needed
End Select
Next cell
End Sub
Edit 1: to copy>>paste contents of the sheet, use the loop below:
For Each cell In Rng
Select Case cell.Value
Case "Red", "Blue"
cell.Offset(0, -1).Hyperlinks(1).Follow NewWindow:=False, AddHistory:=True '<-- not so sure what values you have here
Application.CutCopyMode = False
TemplateBook.Sheets(cell.Value).UsedRange.Copy
Sht.Range("A1").PasteSpecial '<-- paste into the sheet at Range("A1")
Case Else
' do something if you have other cases , not sure it's needed
End Select
Next cell
Edit 2: Create a new worksheet, and then rename it with the cell.Offset(0, -1).Value
TemplateBook.Sheets(cell.Value).Copy after:=Sht
Dim CopiedSheet As Worksheet
Set CopiedSheet = ActiveSheet
CopiedSheet.Name = cell.Offset(0, -1)

Excel VBA Array list

I am a toddler in VBA
I have a large range this could be more than 1000 text values (This could be going down A1), I am trying to concatenate all values with quote and comma into one cell (C1), i know of the transpose formula, but I am not sure my vba array will recognise this as a list.
I am keen for my array formula to recognize c1 as list, in order to carry out my action.
I am really keen to keep this clean and not use the concatenation and drag various formulas down.
I came across this, but this does not paste all the values into one cell.
Sub transpose()
Dim rng As Range
Dim ws As Worksheet
Dim last As Range
Set ws = ActiveSheet
Set last = ws.Cells(Rows.Count, "A").End(xlUp)
Set rng = ws.Range("A1", last)
For Each cell In rng
Dim hold As String
hold = """"
hold = hold + cell.Value
hold = hold + """" + ", "
cell.Value = hold
Next cell
rng.Copy
ActiveWorkbook.Sheets(2).Range("A1").PasteSpecial transpose:=True
End Sub
Code done by ryan E
If anyone can suggest any cheats on gathering list for Arrays that would be great. Other than using the Macro tool in excel
Example.
A1 = company1
A2 = company2
etc
Solution
C1 would show in one cell "company1", "company2", .... "company10000"
You can use Join() and Transpose().
For example:
Sub transpose()
Dim rng As Range
Dim ws As Worksheet
Dim last As Range
Set ws = ActiveSheet
Set last = ws.Cells(Rows.Count, "A").End(xlUp)
Set rng = ws.Range(ws.Range("A1"), last)
ws.Range("B1").Value = """" & Join(Application.Transpose(rng.Value), """,""") & """"
End Sub
EDIT: now I see what you really want to do (create an array of sheet names to pass to Sheets.Copy()) here's one approach...
Add a sheet named (eg) "Groups" to hold your various lists of sheets to be copied:
Group names are in Row 1, with a list of sheets below each name.
Then use this code:
'to demo the "CopySheets()" sub...
Sub Tester()
CopySheets "Group2" 'copy all sheets in Group2
End Sub
'Create of copy for all sheets under "GroupName" header...
Sub CopySheets(GroupName As String)
Dim rng As Range, arr
Dim ws As Worksheet
Dim f As Range
Set ws = ThisWorkbook.Sheets("Groups") '<< has lists of sheet names
'find the header for the group to be copied
Set f = ws.Rows(1).Find(GroupName, lookat:=xlWhole)
If Not f Is Nothing Then
'found the header, so create an array of the sheet names
Set rng = ws.Range(f.Offset(1, 0), ws.Cells(ws.Rows.Count, f.Column).End(xlUp))
arr = Application.transpose(rng.Value)
'use the array in the sheets Copy method
ThisWorkbook.Sheets(arr).Copy
Else
'alert if you tried to copy a non-existent group
MsgBox "Sheet group '" & GroupName & "' was not found!"
End If
End Sub

AdvancedFilter CopyToRange:= First empty row

I am trying to use AdvancedFilter in VBA, but instead of setting copy to range to a fixed value I want to copy it to the first empty row.
I am trying to append two tables from two separate AdvancedFilter steps, is there an easier way? E.g. first copy the two tables to separate location and then merge them? Both table have the same columns.
My code as of now is:
Set rngCriteria_v = Sheets("1").Range("filter")
Set rngExtract_v = Sheets("2").Range("**Here first empty row**")
Set rngData_v = Sheets("3").Range("Input")
rngData_v.AdvancedFilter Action:=xlFilterCopy, _
CriteriaRange:=rngCriteria_v, _
CopyToRange:=Sheets("Stocks_5_control").Columns("AG").Find(vbNullString, Cells(Rows.Count, "AG")), _
Unique:=False
Change your advanced filter line to this:
rngData_v.AdvancedFilter xlFilterCopy, rngCriteria_v, Sheets("Stocks_5_control").Cells(Sheets("Stocks_5_control").Rows.Count, "AG").End(xlUp)(2)
The following merges the all the worksheets in to a new sheet called Master. Hope that helps :)
Dim wrk As Workbook 'Workbook object - Always good to work with object variables
Dim sht As Worksheet 'Object for handling worksheets in loop
Dim trg As Worksheet 'Master Worksheet
Dim rng As Range 'Range object
Dim colCount As Integer 'Column count in tables in the worksheets
Dim wd As Object 'used for word document
Dim WDoc As Object
Dim strWorkbookName As String
Set wrk = ActiveWorkbook 'Working in active workbook
For Each sht In wrk.Worksheets
If sht.Name = "Master" Then
MsgBox "There is a worksheet called as 'Master'." & vbCrLf & _
"Please remove or rename this worksheet since 'Master' would be" & _
"the name of the result worksheet of this process.", vbOKOnly + vbExclamation, "Error"
Exit Sub
End If
Next sht
'Add new worksheet as the last worksheet
Set trg = wrk.Worksheets.Add(After:=wrk.Worksheets(wrk.Worksheets.Count))
'Rename the new worksheet
trg.Name = "Master"
'Get column headers from the first worksheet
'Column count first
Set sht = wrk.Worksheets(1)
colCount = sht.Cells(1, 255).End(xlToLeft).Column
'Now retrieve headers, no copy&paste needed
With trg.Cells(1, 1).Resize(1, colCount)
.Value = sht.Cells(1, 1).Resize(1, colCount).Value
'Set font as bold
.Font.Bold = True
End With
'We can start loop
For Each sht In wrk.Worksheets
'If worksheet in loop is the last one, stop execution (it is Master worksheet)
If sht.Index = wrk.Worksheets.Count Then
Exit For
End If
'Data range in worksheet - starts from second row as first rows are the header rows in all worksheets
Set rng = sht.Range(sht.Cells(2, 1), sht.Cells(65536, 1).End(xlUp).Resize(, colCount))
'Put data into the Master worksheet
trg.Cells(65536, 1).End(xlUp).Offset(1).Resize(rng.Rows.Count, rng.Columns.Count).Value = rng.Value
Next sht
'Fit the columns in Master worksheet
trg.Columns.AutoFit

Cannot remove duplicates from range

I have an excel table with several columns two of which I am interested in. What I am trying to do is filter the first column with a specific criterion and then copy the visible values from the other column into a range object. After that I need to remove duplicates. The problem is I get an error. Here's the code. There are a lot of duplicates. Please tell me what's wrong or suggest a better way to achieve the task I'm trying to do.
Sub Begin()
Dim tbl As ListObject
Set tbl = Worksheets("Sheet1").ListObjects("Table1")
WorkSheet.AutoFilterMode = False
tbl.Range.AutoFilter Field:=8, Criteria1:="DUKESTREET_II-2"
Dim rng1 As Range
Set rng1 = tbl.ListColumns("TGT CELL NAME").DataBodyRange.SpecialCells(xlCellTypeVisible)
MsgBox rng1.Count
rng1.RemoveDuplicates Columns:=1, Header:=xlNo
MsgBox rng1.Count
End Sub
You're off to a great start, but unfortunately as #siddharth-rout pointed out .RemoveDuplicates will not work on a non-contiguous range.
In this case, to collect the all the unique cell values from the "TGT CELL NAME" column, you could use a collection (MSDN link):
Sub Begin()
Dim tbl As ListObject
Dim rng1 As Range, RngIdx As Range
Dim MySheet As Worksheet
Dim UniqueTGTCells As Collection
Set MySheet = ThisWorkbook.Worksheets("Sheet1")
Set tbl = MySheet.ListObjects("Table1")
'only turn off auto filter mode if it's already set to true
If MySheet.AutoFilterMode = True Then
MySheet.AutoFilterMode = False
End If
tbl.Range.AutoFilter Field:=8, Criteria1:="DUKESTREET_II-2"
Set rng1 = tbl.ListColumns("TGT CELL NAME").DataBodyRange.SpecialCells(xlCellTypeVisible)
MsgBox rng1.Count
'populate the collection object
Set UniqueTGTCells = New Collection
For Each RngIdx In rng1
On Error Resume Next
UniqueTGTCells.Add LCase(CStr(RngIdx.Value)), LCase(CStr(RngIdx.Value))
On Error GoTo 0
Next RngIdx
'message the size of the collection
MsgBox UniqueTGTCells.Count
End Sub
Here are our message boxes:
My own solution to this old post below, in case anybody struggle again with that.
Note that I translated my working code into the posted one without testing, but I guess the idea is simple enough to be applied anyway.
Sub Begin()
Dim tbl As ListObject
Set tbl = Worksheets("Sheet1").ListObjects("Table1")
WorkSheet.AutoFilterMode = False
tbl.Range.AutoFilter Field:=8, Criteria1:="DUKESTREET_II-2"
' Sort to make sure filtered view will be contiguous
tbl.range.sort Key1:=tbl.range.cells(1,8), Order1:=xlAscending, Header:=xlYes
Dim rng1 As Range
Set rng1 = tbl.ListColumns("TGT CELL NAME").DataBodyRange.SpecialCells(xlCellTypeVisible)
MsgBox rng1.Count
' Using Areas(1) does the trick (there is only 1 area - no gaps - thanks to sorting)
rng1.Areas(1).RemoveDuplicates Columns:=1, Header:=xlNo
MsgBox rng1.Count
End Sub