Most Valuable Professional


View Jan Karel Pieterse's profile on LinkedIn subscribe to rss feed
Subscribe in a reader

Subscribe to our mailing list

* indicates required

Audit !!!

Check out our RefTreeAnalyser
the ultimate Excel formula auditing tool.

Trainings

Excel VBA Masterclass (English)
Excel VBA for Financials (Dutch)

Third party tools

Speed up your file

FastExcel
The best tool to optimise your Excel model!

Repair your file

Stellar Phoenix Excel Repair
Best tool to repair corrupt Excel sheets and objects
Home > English site > Articles > Excel Tables (VBA)
Deze pagina in het Nederlands

Working with Tables in Excel 2013, 2010 and 2007 (VBA)

This article has also been published on Microsoft Office Online:

Working with Excel tables in Visual Basic for Applications (VBA)

Introduction

In Working with Tables in Excel 2013, 2010 and 2007 I promised to add a page about working with those tables in VBA too. Well, here you go.

It's a ListObject!

On the VBA side there seems to be nothing new about Tables. They are addressed as ListObjects, a collection that was introduced with Excel 2003. But there are significant changes to this part of the object model and I am only going to touch on the basic parts here.

Creating a table

Converting a range to a table starts with the same code as in Excel 2003:

 Sub CreateTable()
    ActiveSheet.ListObjects.Add(xlSrcRange, Range("$B$1:$D$16"), , xlYes).Name = _
        "Table1"
        'No go in 2003
    ActiveSheet.ListObjects("Table1").TableStyle = "TableStyleLight2"
End Sub

But the new stuff is right there already: TableStyles. A collection of objects which are a member of the Workbook object. This gives rise to some oddities. You can change the formatting of a tableStyle, e.g. like this:

Sub ChangeTableStyles()
    'No Go in Excel 2003
    ActiveWorkbook.TableStyles(2).TableStyleElements(xlWholeTable) _
        .Borders(xlEdgeBottom).LineStyle = xlDash
End Sub

This changes the linestyle of the bottom of your table. But hold your horses! If you have any other workbook open, all tables with the same tablestyle appear in your changed style! But if you save your file, close Excel and open Excel again with the file, the changes are gone. This is because you've just changed a built-in tablestyle. If you ask me, I find it strange that the Workbook is a tablestyles' parent, whereas built-in table styles behave as if being bound to the Application object.

If you want full control over your table style, you'd better duplicate a built-in style and modify and apply that style to your table.

Listing the tables

Let's start with finding all tables on the active worksheet:

Sub FindAllTablesOnSheet()
    Dim oSh As Worksheet
    Dim oLo As ListObject
    Set oSh = ActiveSheet
    For Each oLo In oSh.ListObjects
        Application.Goto oLo.Range
        MsgBox "Table found: " & oLo.Name & ", " & oLo.Range.Address
    Next
End Sub

This snippet of code works exactly the same in Excel 2003, so nothing new there (well, that is, in 2003 those tables ARE called Lists).

Selecting parts of tables

You might need to work with specific parts of a table. Here is a couple of examples on how to achieve that. The code comments show you where Excel 2003 differs from 2013, 2010 and 2007.

Sub SelectingPartOfTable()
    Dim oSh As Worksheet
    Set oSh = ActiveSheet
    '1: with the listobject
    With oSh.ListObjects("Table1")
        MsgBox .Name
        'Select entire table
        .Range.Select
        'Select just the data of the entire table
        .DataBodyRange.Select
        'Select third column
        .ListColumns(3).Range.Select
        'Select only data of first column
        'No go in 2003
        .ListColumns(1).DataBodyRange.Select
        'Select just row 4 (header row doesn't count!)
        .ListRows(4).Range.Select
    End With
   
    'No go in 2003
    '2: with the range object
    'select an entire column (data only)
    oSh.Range("Table1[Column2]").Select
    'select an entire column (data plus header)
    oSh.Range("Table1[[#All],[Column1]]").Select
    'select entire data section of table
    oSh.Range("Table1").Select
    'select entire table
    oSh.Range("Table1[#All]").Select
    'Select one row in table
    oSh.Range("A5:F5").Select
End Sub

As you may have spotted, Excel 2013, 2010 and 2007 handle tables like they are range names. Well, that is exactly what is going on. After inserting a table, a range name is defined automatically. These range names are special though. Excel controls them entirely. You cannot delete them and they get renamed automatically when you change a table's name. Remove a table (convert back to range) and the defined name is removed as well.

Inserting rows and columns

Another part in which lists already had most of the functionality. Just a few new things have been added, like the "AlwaysInsert" argument to the ListRows.Add method:

Sub TableInsertingExamples()
'insert at specific position
    Selection.ListObject.ListColumns.Add Position:=4
'insert right
    Selection.ListObject.ListColumns.Add
'insert above
    Selection.ListObject.ListRows.Add (11)
'NoGo in 2003
'insert below
    Selection.ListObject.ListRows.Add AlwaysInsert:=True
End Sub

If you need to do something with a newly inserted row, you can set an object variable to the new row:

     Dim oNewRow As ListRow
    Set oNewRow = Selection.ListObject.ListRows.Add(AlwaysInsert:=True)

If you then want to write something in the first cell of the new row you can use:

oNewRow.Range.Cells(1,1).Value="Value For New cell"

Adding a comment to a table

This is something Excel 2003 cannot do and is related to the fact that a table is a range name. Adding a comment to a table through the UI is a challenge, because you have to go to the Name Manager to do that. In VBA the syntax is:

Sub AddComment2Table()
    Dim oSh As Worksheet
    Set oSh = ActiveSheet
    'NoGo in 2003
    'add a comment to the table (shows as a comment to
    'the rangename that a table is associated with automatically)
    'Note that such a range name cannot be deleted!!
    'The range name is removed as soon as the table is converted to a range
    oSh.ListObjects("Table1").Comment = "This is a table's comment"
End Sub

Convert a table back to a normal range

That is simple and uses the identical syntax as 2003:

Sub RemoveTableStyle()
    Dim oSh As Worksheet
    Set oSh = ActiveSheet
    'remove table or list style
    oSh.ListObjects("Table1").Unlist
End Sub

Special stuff: Sorting and filtering

With Excel 2013, 2010 and 2007 we get a whole new set of filtering and sorting options. I'm only showing a tiny bit here, a Sort on cell color (orangish) and a filter on the font color. The code below doesn't work in Excel 2003. A List in 2003 only has the default sort and autofilter possibilities we have known since Excel 5 and which had hardly been expanded at all in the past 12 years or so.

Sub SortingAndFiltering()
'NoGo in 2003
    With ActiveWorkbook.Worksheets("Sheet1").ListObjects("Table1")

        .Sort.SortFields.Clear
        .Sort.SortFields.Add( _
                Range("Table1[[#All],[Column2]]"), xlSortOnCellColor, xlAscending, , _
                xlSortNormal).SortOnValue.Color = RGB(255, 235, 156)
        With .Sort
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
    End With
    'Only old autofilter stuff works in 2003
    ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=2, _
        Criteria1:=RGB(156, 0, 6), Operator:=xlFilterFontColor
End Sub

Accessing the formatting of a cell inside a table

You may wonder why this subject is there, why not simply ask for the cell.Interior.ThemeColor if you need the ThemeColor of a cell in a table? Well, because the cell formatting is completely prescribed by the settings of your table and the table style that  has been selected. So in order to get at a formatting element of a cell in your table you need to:

The function shown here returns the TableStyleElement belonging to a cell oCell inside a table object called oLo:

Function GetStyleElementFromTableCell(oCell As Range, oLo As ListObject) As TableStyleElement
'-------------------------------------------------------------------------
' Procedure : GetStyleElementFromTableCell
' Company   : JKP Application Development Services (c)
' Author    : Jan Karel Pieterse
' Created   : 2-6-2009
' Purpose   : Function to return the proper style element from a cell inside a table
'-------------------------------------------------------------------------
    Dim lRow As Long
    Dim lCol As Long
    'Determine on what row we are inside the table
    lRow = oCell.Row - oLo.DataBodyRange.Cells(1, 1).Row
    lCol = oCell.Column - oLo.DataBodyRange.Cells(1, 1).Column

    With oLo
        If lRow < 0 And .ShowHeaders Then
            'on first row and has header
            Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlHeaderRow)
        ElseIf .ShowTableStyleFirstColumn And lCol = 0 Then
            'On first column and has first column style
            Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlFirstColumn)
        ElseIf .ShowTableStyleLastColumn And lCol = oLo.Range.Columns.Count - 1 Then
            'On last column and has last col style
            Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlLastColumn)
        ElseIf lRow = .DataBodyRange.Rows.Count And .ShowTotals Then
            'On last row and has total row
            Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlTotalRow)
        Else
            If .ShowTableStyleColumnStripes And Not .ShowTableStyleRowStripes Then
                'in table, has column stripes
                If lCol Mod 2 = 0 Then
                    Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlColumnStripe1)
                Else
                    Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlWholeTable)
                End If
            ElseIf .ShowTableStyleRowStripes And Not .ShowTableStyleColumnStripes Then
                'in table, has column stripes
                If lRow Mod 2 = 0 Then
                    Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlRowStripe1)
                Else
                    Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlWholeTable)
                End If
            ElseIf .ShowTableStyleColumnStripes And .ShowTableStyleRowStripes Then
                If lRow Mod 2 = 0 And lCol Mod 2 = 0 Then
                    Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlRowStripe1)
                ElseIf lRow Mod 2 <> 0 And lCol Mod 2 = 0 Then
                    Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlColumnStripe1)
                ElseIf lRow Mod 2 = 0 And lCol Mod 2 <> 0 Then
                    Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlRowStripe1)
                Else
                    Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlWholeTable)
                End If
            End If
        End If
    End With

End Function

You could use this function like this:

Sub test()
    Dim oLo As ListObject
    Dim oTSt As TableStyleElement
    Set oLo = ActiveSheet.ListObjects(1)
    Set oTSt = GetStyleElementFromTableCell(ActiveCell, oLo)
    With ActiveCell.Offset(, 8)
        .Interior.ThemeColor = oTSt.Interior.ThemeColor
        .Interior.TintAndShade = oTSt.Interior.TintAndShade
    End With
End Sub

Removing formating from an Excel Table

Suppose you have just converted a range to a table, but the range had some formatting set up such as background fills and borders. Tables allow you to format things like that automatically, but now your preexisting formatting messes up the table formatting. One way to overcome this is by changing the style of the cells (see this article) in the table back to the Normal style. This however removes your number formats too. The little macro below fixes that by first making a copy of the normal style, setting its Number checkbox to false and then applying the new style without number format to the table. Finally it applies the tablestyle and deletes the temporary style:

Sub RemoveFormattingOfTable()
    Dim oStNormalNoNum As Style
    On Error Resume Next
    Set oStNormalNoNum = ActiveWorkbook.Styles("NormalNoNum")
    On Error GoTo 0
    If oStNormalNoNum Is Nothing Then
        ActiveWorkbook.Styles.Add "NormalNoNum"
        Set oStNormalNoNum = ActiveWorkbook.Styles("NormalNoNum")
        oStNormalNoNum.IncludeNumber = False
    End If
    With ActiveSheet.ListObjects(1)
        .Range.Style = "NormalNoNum"
        'Now apply tablestyle:
        .TableStyle = "TableStyleLight1"
    End With
    ActiveWorkbook.Styles("NormalNoNum").Delete
End Sub

Note that the function shown above does not take into account that you can set the width of the stripes, both vertically and horizontally.

Wrap Up

Of course there is more to learn and know about tables and lists. A good way to come acquainted with the VBA behind them is by recording macro's while fooling around with them. Luckily Microsoft did include the table object if it comes to recording your actions, unlike the omission on the charting side...


Comments

All comments about this page:


Comment by: Gilles Frechet (11/7/2007 2:57:31 PM)

Hello:

I am currently trying to use a workbook which was developped using a prior version of Excel. This workbook contains multiple sheets and several large Macros. All of the Macros appear to work, however I have found that if I attempt to select a large range of cells in any of the sheets (by using the mouse or with the use of a Macro) the program slows down considerably and the larger the range selected, the longer the time it takes for the system to respond. I would appreciate any help and comments.

 


Comment by: Jan Karel Pieterse (11/7/2007 9:59:31 PM)

Hi Gilles,

Without seeing the code this is hard to analyse. It may help to turn off screenupdating at the beginning of your code though:
Application.ScreenUpdating=false
Then at the end, turn it back on:
Application.ScreenUpdating=True

 


Comment by: Manuel (11/9/2007 7:40:44 AM)

Necesito saber si como se aplica el
AutofilterMode?
Pasa activar o desactivar filtros

 


Comment by: Jan Karel Pieterse (11/10/2007 8:16:22 AM)

Selection.AutoFilter

Will turn on autofilter

ActiveSheet.AutoFilterMode = False

will turn it off.

 


Comment by: akj (11/15/2007 11:31:19 PM)

Excellent

 


Comment by: Johan Nordberg (12/8/2007 2:20:19 PM)

An important difference between Excel 2003 lists and Excel 2007 tables is that the InsertRowRange property of the ListObject only works when the table is empty. When the table has data InsertRowRange returns nothing.

In that case you have to get the last row of the table and move down one row from that.

If anyone has a better solution, please let me know...

// Johan Nordberg

 


Comment by: Jan Karel Pieterse (12/9/2007 3:47:59 AM)

Hi Johan,

Thanks for the comment. I think you have found the only solution to this problem indeed.

 


Comment by: Andrei Sheshka (1/9/2008 8:07:33 AM)

Hi Johan!

At first you must activate ListObject to get InsertRowRange in Excel 2003.

Function GetInsertRow(objList As ListObject) As Range
objList.Parent.Activate
objList.Range.Activate
Set GetInsertRow = objList.InsertRowRange
End Function

Sub Test_GetInsertRow()
Dim lo As ListObject
Dim objListRng As Range

    Set lo = Worksheets("Sheet3").ListObjects(1)
    Set objListRng = GetInsertRow(lo)
    objListRng.Select

End Sub


 


Comment by: Jose Manuel (1/31/2008 12:57:16 PM)

Hi to all!

After 'insert below
Selection.ListObject.ListRows.Add AlwaysInsert:=True
How can I select the cell in the first column of the new row?

Thanks in advance

 


Comment by: Jan Karel Pieterse (2/3/2008 10:20:12 PM)

Hi Jose,

Like this:
    Selection.ListObject.Range.End(xlDown).Select

 


Comment by: Aindril De (5/29/2008 12:46:09 AM)

This is real excellent stuff.

Can anyone advice any book that is available, that helps differentiate Excel 2003
VBA vs Excel 2007 VBA?

Thanks in advance

 


Comment by: Jan Karel Pieterse (5/29/2008 2:06:33 AM)

Hi Aindril,

I'd recommend "Excel 2007 VBA programming Reference" (Stephen Bullen et al)
and
"Excel 2007 Power Programming with VBA" (John Walkenbach)

 


Comment by: Adele Summers (6/9/2008 8:19:09 AM)

This may seem like a simple question, but can you set the data source of a table to
come from a sheet other than the current sheet that you are on?

 


Comment by: Jan Karel Pieterse (6/9/2008 10:18:44 AM)

Hi Adele,

I'm not sure what you're looking for. What do you mean by "the data source"? Which
option are you referring to?

 


Comment by: Martin (6/19/2008 8:26:16 AM)

i need call the dialog "Modify table Quick style"

 


Comment by: Jan Karel Pieterse (6/19/2008 10:51:14 AM)

Hi Martin,

I had a look at Application.Dialogs(xlDialog......), but I could not find it.

 


Comment by: Ann Marie (7/1/2008 6:03:09 AM)

How and where do you turn off screenupdating in Office Excel 2007?

Thank you.

 


Comment by: Jan Karel Pieterse (7/1/2008 10:21:56 AM)

Hi,

Application.ScreenUpdating=False

at the start of your code

and

Application.ScreenUpdating=True

at the end.

 


Comment by: Matt (7/29/2008 3:38:08 PM)

Fantastic Article! This has been extremely helpful in my projects.

One thing I'm struggling with is deleting multiple table rows. Recording a macro
of selecting the desired rows, right-clicking and selecting Delete > Table Rows
results in the following code repeated for each row selected:
Selection.ListObject.ListRows(1).Delete.
Running the macro is very, very slow relative to the action from the UI. I reduced
the code to loop through this, but it is still slow. I'm regularly deleting 1000+
rows. Any ideas as to how to streamline this?

 


Comment by: Mazhar Basa (10/3/2008 2:28:27 AM)

I used the code for creating "table comment" however I cannot see anything on excel
sheet. When I msgbox the comment I can see it but on screen no?

 


Comment by: Jan Karel Pieterse (10/3/2008 5:17:10 AM)

Hi Mazhar,

You see the comment if you type the table's name within a formula and you have
formula autocomplete turned on.

 


Comment by: Luc (10/6/2008 7:23:56 AM)

Great job.

 


Comment by: Scott (10/17/2008 1:16:41 PM)

How would you delete a table row based on selection.
"Selection.ListObject.ListRows.Delete"

 


Comment by: Jan Karel Pieterse (10/19/2008 9:22:17 PM)

Hi Scott,

Not sure what you mean; is this a question or a suggestion?

 


Comment by: Michiel Kotting (1/16/2009 11:34:46 AM)

How do you select the last row in a ListObject? In a normal range I use myRange.Rows(myRange.Rows.Count).Select, but in a ListObject I can't get it to work...

Similarly, how do I get the count of the number of rows in a ListObject?

thanks!

 


Comment by: Jan Karel Pieterse (1/18/2009 11:29:31 PM)

Hi Michiel,

This selects the last row:

    Dim oL As ListObject
    Set oL = ActiveSheet.ListObjects(1)
    oL.DataBodyRange.Rows(oL.DataBodyRange.Rows.Count).Select

 


Comment by: Michiel Kotting (1/19/2009 1:28:25 AM)

Thanks, it works! I also picked up Excel 2007 VBA by Bullen e.a. at your recomendation.

 


Comment by: Mohan Kumar Karunakaran (2/19/2009 3:35:27 PM)

Hi,

I have created a table using VBA, but I really want to stop the default text entered in the first row of the table. I will be working mostly on financial tables, which doesn't have any value on the first cell. If I apply table style using VBA, it adds "Column1" for the first cell, which is not necessary. Do you have any idea on how to restrict this.

Thanks,
Mohan

 


Comment by: Jan Karel Pieterse (2/20/2009 5:11:21 AM)

Hi Mohan,

You cannot prevent the title row from appearing, as Excel needs that for referencing columns in the table. But you can tell Excel to hide the title row by unchecking the box "Header row" on the table tools tab of the ribbon.

 


Comment by: Rangarajan Vijayaraghavan (3/3/2009 8:52:46 AM)

Excellent work! Thanks a ton!

 


Comment by: Dian Leger (3/16/2009 9:35:37 AM)

I am using Excel 2007.
When I click in a cell to enter data, a range of cells is automatically selected.
Is there a way to stop this so that when I select a cell only one cell is selected?

 


Comment by: Jan Karel Pieterse (3/16/2009 11:37:29 AM)

Hi Dian,

Odd, that is abnormal behaviour. Please check out my page on Excel start up problems, especially the part about addins:

www.jkp-ads.com/articles/startupproblems.asp

 


Comment by: Radek Kukuczka (3/17/2009 10:10:05 AM)

Hello,
First of all - thanks for this useful guide!
I have a problem, which you may be able to help solve... I've created spreadsheet which automaticaly calculates data, based on used values. I am storing data in Excel 2007 tables and use INDEX function in excel to select required data from specific row in the table. It's all working perfectly.
What I need to do now is add a userf form wizzard. Some fields are combo boxes, and I need to load data from a column into these combos. How do I inicialize form to include proper items from a specific table into this combo box? I hope this makes sense, I'd appreciate your help.
thanks, Radek

 


Comment by: Jan Karel Pieterse (3/17/2009 11:10:54 AM)

Hi Radek,

You can add the contents of a column in a table to a listbox quite easily, for example:

Dim vValues As Variant
vValues = ActiveSheet.ListObjects(1).DataBodyRange.Columns(1).Value
ListBox1.List = vValues

 


Comment by: S Srinivas (3/23/2009 4:22:11 AM)

Created a macro for sorting the excel worksheet according to colour . Created one command button and pasted the macro . Afterwardd when I run the command button , I am getting the following error.
Run-time error - 2147319765
Automation error
Element not found.
Pl help.
Thanks
Regards
S Srinivas

 


Comment by: Jan Karel Pieterse (3/23/2009 6:10:32 AM)

Hi Srinivas,

I suggest you to go to this site to ask your question:

http://www.wopr.com/cgi-bin/w3t/login.pl?Cat=

 


Comment by: Radek Kukuczka (3/26/2009 9:54:14 AM)

Hi Jan,
Thanks for the hint! It was very usefull.
Unfortunately I've hit another obstacle... Now, when I load the contens of column 1 to my user form, I need to relate the Cell Y in Row X with Cell Z in the same Row X.
I don't think this makes much sense... Let me explain.

I have a table with some data. In column 1 I have names which I load to the ComboBox in my user form. Column 2 contains a numeric ID(which isn't loaded anywhere), which I need to put in a specific cell when clicking OK in the form(this must be depending on what was choosen in the ComboBox).
I did some googling and this is what I've come up with. Please note the below doesn't work...

Dim i As Integer
For i = 1 To 29 // I have 29 rows in my table
    If comboBox1.Value = Worksheets("Data").ListObjects("Table5").DataBodyRange.Columns(1).Rows(i).Value Then
        ActiveWorkbook.Sheets("Parameter").Activate
        Range("C18").Select
        ActiveCell.Value = i
    End If
Next i

As you can see, I'm nowhere with this script, I'd appreciate help
thanks, Radek

 


Comment by: Jan Karel Pieterse (3/27/2009 5:50:14 AM)

Hi Radek,

You can simply load both columns into the listbox (which you set to have two columns and set the column width of the second column to zero) and set the boundcolumn property to the second column.
Now the listbox will show the first column, but return the value of the second column.

 


Comment by: Radek Kukuczka (3/30/2009 4:37:07 AM)

Hello Jan,
thank you very much for this precious hint!
Once I set up the ComboBox properties as you advised, it does return the value I wanted. Apparently I noticed, that I could use the displayed value as well... can I somehow access it?

Is there any reference where I could familarize myself with object properties etc?

thanks, Radek

 


Comment by: Jan Karel Pieterse (3/30/2009 5:39:33 AM)

Hi Radek,

I'd start with using F1 (Help), it is quite extensive.

You can access the other values using the list property:

Texbox1.List(TextBox1.ListIndex,0)
'returns the value of the selected item in column 1

Texbox1.List(TextBox1.ListIndex,1)
'returns the value of the selected item in column 2

 


Comment by: Bharani (3/31/2009 2:13:33 AM)

Thanks a lot....

 


Comment by: Tom Pirotte (4/17/2009 1:48:44 PM)

Hello,
I have a question regarding tables in use with VBA.
I want to use a sheet as "database" for information.
Let me explain

When I open a new xls I have 3 sheets. Sheet1 ,2 and3.
I fill sheet1 with a table (5 x 2.)
When I save the XLS to XLA the sheet with info isn't visible anymore and I can't use my formula, which was written in VBA, to reach the data on the inputted sheet.
Altho in the VB editor I still see the 3 sheets in the structure. How can I reach the sheets in the xla by a self written function or procedure?
Or what is the best way to handle diffrent tables or sheets in a XLA.

Best regards,


 


Comment by: Jan Karel Pieterse (4/19/2009 7:18:52 AM)

Hi Tom,

You should be able to read information from a worksheet contained in an Excel addin without trouble. Post your code here and I'll have a look at the code.

 


Comment by: Ray Bernard (6/1/2009 7:12:19 PM)

For a cell within an Excel 2007 Table (the table is named "Table1"), with banded coloring of cells within the table, the .Interior.ColorIndex property of the cell returns "No fill" regardless of the cell color.

The code in the following post (due to post size limitations) is intended to change the color of a Wingding dot character in a cell based upon the contents of the adjacent cell. However, .Interior.ColorIndex always returns -4142 for both Green and White cells colored by Table banding.

Is the ColorIndex value only available through ListObjects("Table1")? If so, how would I do that? I am new to Excel Macro coding and can't seem to find a reference for the Table object model on the Web or in the Help.

I will submit the code next.

 


Comment by: Ray Bernard (6/1/2009 7:12:59 PM)

Below is the code (provided to me by Ken Johnson) that goes with the previous post I submitted:

' Written by Ken Johnson
'Check for changes to any of the dropdown cells 4 columns to the right of the Tasks column
If Not Intersect(Target, Range("Tasks").Offset(0, 9)) Is Nothing Then
'Format the font color in the cells to the left of the dropdown cells according to the value in the dropdown cell
Dim rgCell As Range
    For Each rgCell In Intersect(Target, Range("Tasks").Offset(0, 9)).Cells
        Select Case rgCell.Value
            Case "Not Started"
            'Make the wingding character the same color as the cell interior so that it is not visible
                With rgCell.Offset(0, -1)
                    If .Interior.ColorIndex <> -4142 Then
                    '-4142 corresponds to No Fill.
                    'Font.ColorIndex = -4142 causes error
                        .Font.ColorIndex = .Interior.ColorIndex
                    Else: .Font.ColorIndex = 2 'White
                    End If
                End With
            Case "Started"
                With rgCell.Offset(0, -1)
                    .Font.ColorIndex = 5 'Blue
                End With
            Case "Behind Schedule"
                With rgCell.Offset(0, -1)
                    .Font.ColorIndex = 44 'Gold
                End With
            Case "Late"
                With rgCell.Offset(0, -1)
                    .Font.ColorIndex = 3 'Red
                End With
            Case "Completed"
                With rgCell.Offset(0, -1)
                    .Font.ColorIndex = 10 'Green
                End With
        End Select
    Next
End If

 


Comment by: Jan Karel Pieterse (6/1/2009 10:15:31 PM)

Hi Ray,

You need to find out the proper TableStyleElement that belongs to the cell inside the table. Which tablestyleElement is needed depends on the settings of your table style. Assuming your cell is within the dataBodyRange of the table and you have no column striping you'd get something like this:

Function GetStyleElementFromTableCell(oCell As Range, oLo As ListObject) As TableStyleElement
'-------------------------------------------------------------------------
' Procedure : GetStyleElementFromTableCell
' Company : JKP Application Development Services (c)
' Author    : Jan Karel Pieterse
' Created : 2-6-2009
' Purpose : Function to return the proper style element from a cell inside a table
'-------------------------------------------------------------------------
    Dim lRow As Long
    'Determine on what row we are inside the table
    lRow = oCell.Row - oLo.DataBodyRange.Cells(1, 1).Row

    If oLo.ShowTableStyleRowStripes Then
        'We are in the table's body
        If lRow Mod 2 = 0 Then
            Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlRowStripe1)
        Else
            Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlWholeTable)
        End If
    Else
        Set GetStyleElementFromTableCell = oLo.TableStyle.TableStyleElements(xlWholeTable)
    End If
End Function

Sub test()
    Dim oLo As ListObject
    Dim oTSt As TableStyleElement
    Set oLo = ActiveSheet.ListObjects(1)
    Set oTSt = GetStyleElementFromTableCell(ActiveCell, oLo)
    ActiveCell.Offset(, 3).Interior.ThemeColor = oTSt.Interior.ThemeColor
    ActiveCell.Offset(, 3).Interior.TintAndShade = oTSt.Interior.TintAndShade
End Sub

 


Comment by: Tim (6/8/2009 6:41:54 AM)

Excel 2007 tables are named ranges ... but I can't treat them as a database name for SQL queries (example, in the MS Query builder). Named rnages appear as a database table, but not Excel 2007 tables. I have to convert the table to a normal range before the name is recognised by the Excel ODBC driver. This is annoying. Am I doing something wrong?

 


Comment by: Jan Karel Pieterse (6/8/2009 7:36:00 AM)

Hi,

I guess you'll have to define your own "normal" named range for each table to have msQuery pick them up.

 


Comment by: Brian (7/2/2009 7:59:42 AM)

Good morning - maybe this is a stupid question, but how do I use vba to obtain the table name that the activecell is in? eg, I can use CurrentRegion to select the whole table, but how do I obtain the table name so that I can start working with its fields?

Thanks,
Brian

 


Comment by: Jan Karel Pieterse (7/2/2009 12:19:45 PM)

Hi Brian,

You could use something like this:

    If ActiveCell.ListObject Is Nothing Then
        MsgBox "Not in a table"
    Else
        MsgBox ActiveCell.ListObject.Name
    End If

 


Comment by: HDR (7/13/2009 12:00:28 PM)

Hello,
How would you use VBA to loop through each row of the Excel 2007 table/list and get values from specific columns and work with them? I tried the code below but it's not working (it doesn't like the Structured Reference syntax)

Also, if the Tables are Workbook in scope in Excel 2007, how do I set a reference to them without using the worksheet on which it resides? (see code below)?

Dim myTable As ListObject
Set myTable = ThisWorkbook.Worksheets("Sheet1").ListObjects("myTable")

For CurRow = myTable.DataBodyRange.Row To myTable.ListRows.Count

myVar = myTable[[#This Row], [Header1]]").Value
'do other stuff..

'The #This Row should obviously move to the next row for each iteration of CurRow
next

 


Comment by: Jan Karel Pieterse (7/15/2009 12:39:53 AM)

Hi HDR,

This example runs through the cells in the first column of the list:
Sub RunThroughFirstColumnOfList()
    Dim oList As ListObject
    Dim oCell As Range
    Set oList = Worksheets(1).ListObjects(1)
    For Each oCell In oList.DataBodyRange.Columns(1).Cells
        MsgBox oCell.Address & ":" & CStr(oCell.Value)
    Next
End Sub

 


Comment by: John (8/3/2009 5:15:44 PM)

Is it possible to offset by using header names, for instance when using find to locate a cell value and then modifying a value in the located cell's row? Kind of like doing such (with Status and Filing ID being table headers):


For Each acell In Selection

With ext_book.Worksheets("Assignments").Range("AssignmentsTbl[Filing ID]")
    Set c = .Find(acell.Value, LookIn:=xlValues)
    If Not c Is Nothing Then
        c.Offset(0, "[Status]").Value = acell.Offset(0, "[Status]").Value
    End If
    
End With

Next acell


I've been racking my brain on how to do this, any help would be GREATLY appreciated. Many thanks!

 


Comment by: Robert (8/10/2009 5:41:19 PM)

Formulas work well within the same row using [#This Row]

ex. =Table_SDCBIBE01_SDCBFDDS_BF_RetailSummary[[#This Row],[RetailSales]]/Table_SDCBIBE01_SDCBFDDS_BF_RetailSummary[[#This Row],[InvPct]]

Is there any way to reference a different row using the table[] syntax? something like [[#This Row](-1),[RetailSales]]?

 


Comment by: Brent (9/2/2009 9:33:51 AM)

Great article. Thanks!!

What VBA code can I use to resize the current table by one row?

 


Comment by: Jan Karel Pieterse (9/7/2009 8:58:09 AM)

Hi John,

Anything is possible. I'd do two finds: one on the header row of the table to find the fieldname you need.
Then the other you already do.
Say the object variable is called oHeader and you have found row c, then the code to update the proper cell is:

Intersect(c.entirerow,oHeader.Entirecolumn).Value="New Value"

 


Comment by: Jan Karel Pieterse (9/7/2009 9:31:27 AM)

Hi Robert,

I don't really know, I don't think so. Look in Help and search fro "Structured references". That should give you all information on how to refer to tables.

 


Comment by: Jan Karel Pieterse (9/7/2009 10:13:38 AM)

Hi Brent,

Like this:

With ActiveCell.ListObject
    .Resize ActiveSheet.Range(.Range.Resize(.Range.Rows.Count + 1, .Range.Columns.Count).Address)
End With

 


Comment by: Andreas (9/22/2009 2:39:42 PM)

Hi Jan,

I have a bunch of Excel 2003-xlas making heavy use of InsertRowRange.
I want to let them run in 2007 compatibility-mode without any change but that's impossible because InsertRowRange Is Nothing after the 1st row insertion.
In Excel 2003 InsertRowRange was never Nothing when the ListObject was active (ActiveCell within the ListObject).
In Excel 2007 it equals to Nothing after the 1st row insertion despite the ActiveCell is ALWAYS within the ListObject.
The following code of an 2003-xla works fine in 2003 but errors with 2007.

Sub InsertRowRangeTest()
    With ThisWorkbook.Worksheets.Add
        .Range("A1").Value = "head"
        .ListObjects.Add xlSrcRange, Range("$A$1"), , xlYes
        .ListObjects(1).InsertRowRange.Value = "1st insert"
        ' next statement works fine in Excel 2003 but errors in 2007
        ' Since the ActiveCell is within the ListObject the
        ' InsertRow should be visible (despite it is not shown in Excel 2007)
        ' Run time error 91: Object of With variable not set
        .ListObjects(1).InsertRowRange.Value = "2nd insert"
    End With
End Sub

What is the reason of the error?
Did I miss to set something?
Can I make the InsertRow visible in another way to prevent Excel 2007 to throw errors?

Kind regards,
Andreas

 


Comment by: Debug (9/23/2009 2:38:34 AM)

Hi

I'm look for code to change a standard command buttons color after I have refreshed the data from the server and the text to data has been refreshed. I'm using Excel 2007. If you can't use a standard button it is not a problem to change it to something else. Thanks before hand.

 


Comment by: Jan Karel Pieterse (9/23/2009 10:07:45 AM)

Hi Andreas,

Thanks for letting me know the problem and the fix:

http://technet.microsoft.com/en-us/library/cc179167.aspx#whatschanged16

 


Comment by: Ignatius Verbeek (11/2/2009 6:33:25 PM)



If I try to change the formula of a cell in a table (aka listobject) in 2007 using vba I get an error. Here is the psuedo code.

set rng = ' a reference to a cell in a table
rng.formula = "= my formula"

gives error code 1004.

I get around this by unlisting the table adding the formula then relisting it.

Is there a better way? What is throwing the error?

 


Comment by: Jan Karel Pieterse (11/3/2009 12:40:47 AM)

Hi Ignatius,

Seems to me the relevant part of your code is missing, could you please post the real code (or just enough in a sub so it shows the error)?

I just tested and setting a formula to a cell inside a table works without a hitch.

 


Comment by: Ignatius Verbeek (11/3/2009 4:50:39 AM)

Jan,

I just did a test and yes I can get vba to add a simple formula in a simple table. I am sorry to bother you with something I should be able to test myself and thankyou for you comments.

However, I remain curious. In the actual table and vba code I did strike the error that I could not add a formula to a table with vba. After much testing I found that in some instances the formula was not correctly defined and that was the source of the error. After eliminating that problem I still found the formula could not be added. With a deadline looming and hours wasting I found that unlisting the table worked, the formula could be added and appears to be correct. I can only guess that excel is doing and auto correct or something which is masking an error in my formula.

Thanks again for you help.

 


Comment by: Ignatius Verbeek (11/3/2009 5:01:22 AM)

Jan,

When you map a table to xml data you get an "insert row" ie a row at the bottom of the table where if you enter data it automaticall adds a new just like data tables in Access. If you don't map the table to xml you don't get the insert row.

I have worked out a way of emulating the insert row behaviour using the workbook sheet change event. In this way one set of subs and functions works on all tables in a workbook that have been flagged to behave in this way. It was/is a bit tricky to get it working neatly but now that it is, it is a very useful feature.

Do you know of a way that you can get the native "insert row" feature of a table to work for a table the is not mapped to xml.

 


Comment by: Jan Karel Pieterse (11/3/2009 5:29:07 AM)

Hi Ignatius,

You don't really need that insert row, Excel will expand your table automatically when you enter anything below or to the right of the table.

 


Comment by: Noah Fehrenbacher (11/3/2009 6:23:30 PM)

How do we know if sorting (or an autofilter) has been applied to a table since before we used autofiltermode and filtermode to determine it before, and now they don't work. What is the alternative for 2007 tables?

 


Comment by: amirtha (11/3/2009 10:02:26 PM)

hai
i want to create table in the form using vb.i want to know how to implement this.

 


Comment by: Jan Karel Pieterse (11/4/2009 6:55:51 AM)

Hi Noah,

It is not straightforward, this function seems to give what you need:

Public Function HasFilter(oLo As ListObject) As Boolean
    Dim oFltr As Filter
    For Each oFltr In oLo.Range.Parent.AutoFilter.Filters
        If oFltr.On Then
            HasFilter = True
            Exit Function
        End If
    Next
End Function

Sub Test()
    MsgBox HasFilter(ActiveCell.ListObject)
End Sub

 


Comment by: Jan Karel Pieterse (11/4/2009 6:57:43 AM)

Hi Amirtha,

See:

http://www.jkp-ads.com/Articles/AutoSizeListBox.asp

 


Comment by: Mark (11/6/2009 10:12:02 AM)

I'm trying to create a macro to delete all the rows in a table. I'm very close, but am very confused by the behavior of my macro.


Sub Delete_Lotsa_Rows()
    Dim oList As ListObject
    Dim oRow As ListRow
    Set oList = Worksheets(1).ListObjects(1)
    Set oRow = oList.ListRows(1)
    For Each oRow In oList.ListRows
        oRow.Delete
    Next
End Sub


The problem is that the macro only deletes half the rows in the table, then gives me

"RUN-TIME ERROR '1004':
Application-defined or object-defined error"

I even numbered the rows sequentially, and the macro deleted the odd-numbered rows only. When I started with 256 rows, it deleted 128, then 64, then 32, 16, 8, 4, 2, and 1.

It appears that for some reason the code is deleting every other row.

 


Comment by: Jan Karel Pieterse (11/6/2009 10:37:55 AM)

Hi Mark,

The trick is to use a counter instead of a for-each construct and keep deleting the first row:

Sub Delete_Lotsa_Rows()
Dim oList As ListObject
Dim lCt as Long
Set oList = Worksheets(1).ListObjects(1)
Set oRow = oList.ListRows(1)
For lCt=1 To oList.ListRows.Count
oList.ListRows(1).Delete
Next
End Sub

 


Comment by: Charlie (11/8/2009 11:59:01 AM)

Jan,
This is an excellent place for information on the Excel 2007 table Object. However, I am a bit uncertain how to accomplish an action based on a table. I want to set the value of a variable strUserMembership to a value in a table based on another value in the table.

Imagine the table ("tblAdministration") has several FIELDS and one of the fields is [Username]. When the User opens the Workbook, I want to set some Workbook and Worksheet properties based on the User's access level. In the table is another field called [AccessLevel].

So when the User opens the Workbook, I want to find their [Username] in "tblAdministration", and set strUserMembership (variable) to the associated value in the field [AccessLevel].

Thank you so much for your help.

 


Comment by: Jan Karel Pieterse (11/8/2009 10:51:24 PM)

Hi Charlie,

Something like this should do the trick:

Function GetAccessRightsFromTable(sTableName As String, sUsername As String) As String
    Dim oCol As Range
    Dim oRow As Range
    On Error Resume Next
    Set oCol = ActiveSheet.ListObjects(sTableName).Range.Rows(1).Cells.Find("UserName")
    Set oRow = Intersect(ActiveSheet.ListObjects(sTableName).Range, oCol.EntireColumn.Cells).Find(sUsername)
    Set oCol = Nothing
    Set oCol = ActiveSheet.ListObjects(sTableName).Range.Rows(1).Cells.Find("AccessLevel")
    GetAccessRightsFromTable = Intersect(oCol.EntireColumn, oRow.EntireRow).Value
End Function

Sub Foo()
    MsgBox GetAccessRightsFromTable("tblAdministration", "Smith")
End Sub

 


Comment by: Ian (11/19/2009 6:38:50 AM)

In answer to Robert's question (quoted below)

Table_Name[[#This Row],[ColumnName]] is treated like a cell reference.

I've not tried it myself but wouldn't:
=OFFSET(Table_Name[[#This Row],[ColumnName]],-1,0)

provide you with the result you're seeking?

The only issue I can see with this is when you're approaching the edge of the table (the row above the top row is the header...)
====
Comment by: Robert (8/10/2009 5:41:19 PM)

Formulas work well within the same row using [#This Row]

ex. =Table_SDCBIBE01_SDCBFDDS_BF_RetailSummary[[#This Row],[RetailSales]]/Table_SDCBIBE01_SDCBFDDS_BF_RetailSummary[[#This Row],[InvPct]]

Is there any way to reference a different row using the table[] syntax? something like [[#This Row](-1),[RetailSales]]?

 


Comment by: Charlie (11/25/2009 11:10:41 PM)

Jan,

First, thank you for your help on the previous question I posted (11/8/2009 11:59:01 AM) - worked like a champ.

I have tried to use the information from your answer to Radek (3/17/2009 11:10:54 AM) to populate a data validation drop-down. I am here because I cannot get it to work. the code is:

Sub subDropDownActivate(strInCell As String)
Dim varValues As Variant

varValues = shtListSource.ListObjects("tblDocumentType").DataBodyRange.Columns(2).value

Range("" & strInCell & "").Select
With Selection.Validation
.Delete
.Add Type:=xlValidateList, _
AlertStyle:=xlValidAlertStop, _
Operator:=xlBetween, _
Formula1:=varValues
.IgnoreBlank = False
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = "Select a value from the drop-down list"
.ErrorMessage = "Only values in the list can be entered"
.ShowInput = True
.ShowError = True
End With
Selection.ClearContents
End Sub


I have tried everything for "Formula1:=" and cannot get it to work. Am I even close?

 


Comment by: Hi Charlie (11/25/2009 11:17:28 PM)

You're close. For a list, the Formula1 property expects the items as a string, separated by a comma, so you could do it like this:

Sub subDropDownActivate(strInCell As String)
    Dim varValues As Variant
    Dim sFormula As String
    Dim sValues() As Variant
    Dim lCt As Long
    varValues = shtListSource.ListObjects("tblDocumentType").DataBodyRange.Columns(2).Value
    ReDim sValues(1 To UBound(varValues, 1))
    For lCt = 1 To UBound(varValues, 1)
        sValues(lCt) = varValues(lCt, 1)
    Next
    sFormula = Join(sValues, ",")
    Range("" & strInCell & "").Select
    With Selection.Validation
        .Delete
        .Add Type:=xlValidateList, _
             AlertStyle:=xlValidAlertStop, _
             Operator:=xlBetween, _
             Formula1:=sFormula
        .IgnoreBlank = False
        .InCellDropdown = True
        .InputTitle = ""
        .ErrorTitle = ""
        .InputMessage = "Select a value from the drop-down list"
        .ErrorMessage = "Only values in the list can be entered"
        .ShowInput = True
        .ShowError = True
    End With
    Selection.ClearContents
End Sub

 


Comment by: Charlie (12/1/2009 3:14:18 PM)

Jan,

Once again your answer to my previous post was very helpful. I have work on the next (and hopefully last) issue all day and am stumped.

How would you apply SEVERAL filters to the table values BEFORE loading the string into the Validation Object? Based on conditions (that will increase in complexity), I would like to reduce the number of records in the table before they end up in the Data Validation Object.

I have tried a two step Autofilter (based on the "Special Stuff" section of your article) approach that I cannot get to work. How would I get Case "tblDSRDocument" filters to work before assigning the varValues variable?

Sub subDropDownActivate(strRange, strTab As Object, strTable As String)
Dim varValues As Variant
Dim varValuesString() As Variant
Dim strFormula1 As String
Dim lngCount As Long

Select Case strTable
     Case "tblDSRDocument"
         shtListSource.ListObjects("tblDSR").Range.AutoFilter Field:=4, _
            Criteria1:="1", Operator:=xlFilterValues
         shtListSource.ListObjects("tblDSR").Range.AutoFilter Field:=9, _
            Criteria1:="All", Operator:=xlOr, Criteria2:="BW"
         varValues = shtListSource.ListObjects("tblDSR").DataBodyRange.Columns(2).value
     Case "tblDSRUnassigned"
         varValues = shtListSource.ListObjects("tblDocumentType").DataBodyRange.Columns(2).value
End Select
ReDim varValuesString(1 To UBound(varValues, 1))
For lngCount = 1 To UBound(varValues, 1)
     varValuesString(lngCount) = varValues(lngCount, 1)
Next
strFormula1 = Join(varValuesString, ",")
....
End Sub

 


Comment by: Jan Karel Pieterse (12/2/2009 2:10:45 AM)

Hi Charlie,

You can't add the visible cells of a filtered list to a variant array unfortunatly, use something like this instead:

Sub subDropDownActivate(strRange, strTab As Object, strTable As String)
    Dim varValues As Variant
    Dim varValuesString() As Variant
    Dim strFormula1 As String
    Dim lngCount As Long
    Dim oCell As Range
    Dim oFilteredRange As Range
    Select Case strTable
    Case "tblDSRDocument"
        shtListSOurce.ListObjects("tblDSR").Range.AutoFilter Field:=4, _
                                                             Criteria1:="1", Operator:=xlFilterValues
        shtListSOurce.ListObjects("tblDSR").Range.AutoFilter Field:=9, _
                                                             Criteria1:="All", Operator:=xlOr, Criteria2:="BW"
        Set oFilteredRange = shtListSOurce.ListObjects("tblDSR").DataBodyRange.Columns(2).Value
    Case "tblDSRUnassigned"
        Set oFilteredRange = shtListSOurce.ListObjects("tblDocumentType").DataBodyRange.Columns(2).Value
    End Select
    For Each oCell In oFilteredRange.SpecialCells(xlCellTypeVisible).Cells
        strFormula1 = strFormula1 & oCell.Value & ","
    Next
    strFormula1 = Left(strFormula1, Len(strFormula1) - 1)
End Sub

 


Comment by: Joakim Westin (12/2/2009 4:57:17 AM)

Thank you for an excellent post!

Can you add an example of the recommended way to loop through all the data in a ListObject? I am not a seasoned VBA programmer so this may be that I don't understand the difference between a range and the ListObject. But what I want to do is to programatically (VBA) access the ListObject data in order to do things with it.

Any examples and recommendations of how to best do this are most welcome!

/Joakim

 


Comment by: Jan Karel Pieterse (12/2/2009 11:39:06 AM)

Hi Joakim,

This loops through all cells in a listobject:

    Dim oCell As Range
    For Each oCell In ActiveSheet.ListObjects(1).Range
        MsgBox oCell.Address & "," & oCell.Value
    Next

 


Comment by: dimson (12/11/2009 2:46:42 AM)

Hi

I am using excel sheet1 as table and in the same workbook i have created a module in which i am trying to pull data from the SQL statements using ADODB connection.
i am not able to write correct syntex for 'WHERE' Clause. Actually i am not able to write the field name
EX:
"WHERE" & [Sheet1$].[Acc Ref#] & "= '665544' "

please tell me what is the right way to use the 'Where' Clause of SQL statement in Excel macro

Thanks
dimson

 


Comment by: Jan Karel Pieterse (12/11/2009 3:36:37 AM)

HI dimson,

Looks like the syntax is something like this:

"WHERE [Sheet1$].[Acc Ref] = '665544'"

 


Comment by: Nasser (12/20/2009 12:30:14 AM)

Hi,

In excel 2003 changing the color of a line does not make a problem. The code is as follow:

ActiveSheet.Shapes("line 1").Line.ForeColor.SchemeColor = 2

But in excel 2007 the things are a bit different. The line is called" straight connector" and i could not find the right code to change its color. Any help to find the correct code.

Many Thanks
Nasser.

 


Comment by: Jan Karel Pieterse (12/21/2009 11:55:52 AM)

Hi Nasser,

This seems to do the trick (turns line black):

ActiveSheet.Shapes("Name Of Shape").Line.ForeColor.RGB = RGB(0, 0, 0)

 


Comment by: Nasser (12/21/2009 11:04:09 PM)


Hi karel,

It works, thank you so much. Using rectangle shape it works with numbers but RGBs it does not, strange!

Cheers,
Nasser.

 


Comment by: Nasser (12/22/2009 1:47:32 AM)

Hi,

I know that there 4 methods to trigger a combobox. The only one working me is to populate the combobox through a command button. The code i am using is as follow:

private sub cmdsetcombo_click()
combobox1.clear
combobbox.additem "1"
combobox1.additem "2"
combobox1.additem "3"

When open the program, i just click on the command button and my combobox gets populated. Without adding this button my combobox remains empty.

I checked the other 3 methods also but after opening the program i find the combobox almost empty. Is there another method which does not need a button to trigger the combobox?

Cheers,
Nasser.

 


Comment by: Jan Karel Pieterse (12/22/2009 6:45:32 AM)

Hi Nasser,

You could use the Workbook_Open event in the Thisworkbook module to run the code that fills the combobox.

 


Comment by: Nasser (12/23/2009 12:25:44 AM)

Hi Karel,

I put the whole code below in "thisworkbook" but it does not seem to work.

Option Explicit

Private Sub ComboBox1_Change()
ComboBox1.Clear
ComboBox1.AddItem ("1")
ComboBox1.AddItem ("2")
ComboBox1.AddItem ("3")

[/End Sub

Private Sub Workbook_Open()
If ComboBox1.Value = "1" Then
ActiveSheet.Shapes("line 2").Line.ForeColor.RGB = RGB(0, 0, 0)
ElseIf ComboBox1.Value = "2" Then
ActiveSheet.Shapes("line 2").Line.ForeColor.RGB = RGB(225, 0, 0)
Else
ActiveSheet.Shapes("line 2").Line.ForeColor.RGB = RGB(0, 225, 0)
End If
End Sub]

Thanks your feedback
Nasser.

 


Comment by: Jan Karel Pieterse (12/23/2009 4:19:14 AM)

Hi Nasser,

The change event of the combobox needs to go in the module belonging to the worksheet the combobox is on.

So this goes in ThisWorkbook:
(note that you may need to change Sheet1 in this code to the name as shown in the project explorer in the VBA Editor)


Private Sub Workbook_Open()
Sheet1.ComboBox1.Clear
Sheet1.ComboBox1.AddItem ("1")
Sheet1.ComboBox1.AddItem ("2")
Sheet1.ComboBox1.AddItem ("3")
End Sub


And this goes in the sheet's module:

Private Sub ComboBox1_Change()
    If ComboBox1.Value = "1" Then
        ActiveSheet.Shapes("line 2").Line.ForeColor.RGB = RGB(0, 0, 0)
    ElseIf ComboBox1.Value = "2" Then
        ActiveSheet.Shapes("line 2").Line.ForeColor.RGB = RGB(225, 0, 0)
    Else
        ActiveSheet.Shapes("line 2").Line.ForeColor.RGB = RGB(0, 225, 0)
End If
End Sub

 


Comment by: dimson (12/23/2009 6:16:19 AM)

I am trying to pull some data from an external read only file(from defined Table) by using SQL Query.

I am getting all the required result but i am not getting few fields data(I have noticed its Number type data)

the exception is that i am getting few data for the same fields. even when i import data, i am getting the same result

due to this, manual copy pasting only works

what could be the error(is the cariage return in the field causing this)

 


Comment by: Marek (12/23/2009 8:42:03 AM)

Hi Jan,

and thanks for the article. Helped quite a bit where the VBA documentation is lacking ...

One question I have is, how do I use the below line,

oNewRow .Range.Cells(1,1).Value="Value For New cell"


but instead of using Cells(1,1) type of referencing I'd rather call it by their field (or column name) name ... like

oNewRow.Range("tblLog[DateTime]").Value = "Test"


I've tried many different syntax versions, but it doesn't seem to accept anything of this kind .

Thanks,

Marek

ps. Happy holidays

 


Comment by: Nasser (12/23/2009 10:04:35 AM)

Hi Karel,

Great, it works nicely. Thanks.

As a new learner i want to try to use the form control and see what is the difference between them and the activeXcontrol. Using the ActiveXcontrol i did not have any problem using combobox with the label but with the form control, my label is not responding.

After selecting a drop down from form control,i entered in 3 cells the names "red, black and green".
After highlighting the cells and selecting the cell d7 as the number to be tested. I wrote my program and it works nicely with the straight connector" without the label.
Adding the label to display the color names, it gives errors, " variable label5 not defined and also "can't execute code in
'break mode". All the code is kept in folder "module1".

[Sub DropDown4_Change()
If Range("d7").Value = 1 Then
ActiveSheet.Shapes("straight connector1").Line.ForeColor.RGB = RGB(225, 0, 0)
Label5.Caption = "red"
    ElseIf Range("d7").Value = "2" Then
ActiveSheet.Shapes("straight connector 1").Line.ForeColor.RGB = RGB(0, 0, 0)
Label5.Caption = "black"
    Else
ActiveSheet.Shapes("straight connector 1").Line.ForeColor.RGB = RGB(0, 225, 0)
Label5.Caption = "green"
    End If
End Sub]

Cheers

 


Comment by: Jan Karel Pieterse (12/23/2009 11:12:34 AM)

Marek: I don't think that syntax will work, because it probably points to an entire column (the one with that heading).

Nasser: The proper syntax is:

ActiveSheet.Labels("Label 1").Caption = "Red"

 


Comment by: Nasser (12/24/2009 12:40:26 AM)


Great! Thanks

Merry Chrismas

 


Comment by: Nasser (12/24/2009 1:08:24 AM)

Hi Karel,

I am using a timer in my application. Here is the code which works fine so far.

Application.Wait Now + TimeValue("00:00:02")
MSGBox ("Clearing time 1.75 seconds")

I want to show exactely 1.75 sec. Since i can not adjust this particular time so i put 2 secs. Is there a way to program my VBA for less than 1 second since i have different timing 0.01, 0.15, 0.75 sec. and so one.

Cheers,
Nasser.

 


Comment by: Jan Karel Pieterse (12/24/2009 5:49:47 AM)

Hi Nasser,

Use the Timer function in combination with a Do loop:

Sub Test()
    Dim dTime As Double
    dTime = Timer
    Do
    Loop Until Timer - dTime >= 1.75
    MsgBox Timer - dTime
End Sub

 


Comment by: Nasser (12/24/2009 8:49:08 AM)

Hi Karel,

Thanks, that work fine but only thing it displays sometimes more than 1.75, 0.17 or 0.01. What i did is changing the MsgBox contain " Timer - Dtime" by the timing above like MsgBox( 1.75 secs"). That will also satisfy my need. Any better idea will be welcomed.

Many many thanks
Nasser.

 


Comment by: Nasser (12/24/2009 8:57:55 AM)

Hi Karel,

I am making one Multi-choice Question. It works fine but when i click on "cancel or close mark" to exit from the window, it says " Invalid Entry" which normally should not.
With wrong entry other than 1,2,3 it displays "Invalid Entry" which is fine. Something needs to be added to my program, isn't it?

Private Sub question1_click()
Dim answer As Variant
answer = (InputBox( _
"Fuses have an inverse type of current-time operating characteristic. What does it mean?" & vbCrLf & _
"1) The higher the current, the slower the operating time." & vbCrLf & _
"2) The smaller the current, the faster the operating time." & vbCrLf & _
"3) The higher the current, the faster the operating time." & vbCrLf & _
" Your answer to question 1 is "))
Select Case answer
Case 1
MsgBox ("WRONG: When the current is high, the fuse must strip quickly.")
Case 2
MsgBox ("WRONG: For a small current close to the fuse rating, the fuse should not trip.")
Case 3
MsgBox ("CORRECT: In case of a higher current, the fuse should trip very quickly.")
Case Else
MsgBox (" Invalid Entry ")
End Select
End Sub

Thanks and Regards
Nasser.

 


Comment by: Jan Karel Pieterse (12/25/2009 3:28:28 AM)

Hi Nasser,

You need one extra test:

'Existing code
Case ""
Msgbox "Cancelled"
Case Else
'Existing code

 


Comment by: Geoff Hasforth (1/3/2010 4:38:33 PM)

I have created an Excel Table from an external database using the ListObjects.Add method then added additional calulated fields to the right of the data range.

The formulas fill down automatically when first entered, but if the data range expands downward when updated I only get one formula in the very bottom row. This leaves a gap which I then have to manually fill. Nor are the formats copied down with each refresh

I can't seem to get the FillAdjacentFormulas working nor can I find a box to turn it on like I use to get with MSQuery querytable. According to what I have read the option should be available in Data Properties menu.

I am trying to get all this working in VBA and would greatly appreciate some help.

Yours Sincerely

Geoff Hasforth

 


Comment by: Jan Karel Pieterse (1/3/2010 11:28:29 PM)

Hi Geoff,

This should work "out of the box". Make sure the formula column is included in the table range. On the table tools tab of the ribbon (only visible when you're within a table), click the design tab and locate the "Properties" group on the far left. It has a button called "Resize table".

 


Comment by: Dennis Ceralde (1/31/2010 7:36:54 PM)

Hi Jan,
On a 1/3/2010 11:28:29 PM posting of yours you stated:
This should work "out of the box". Make sure the formula column is included in the table range. On the table tools tab of the ribbon (only visible when you're within a table), click the design tab and locate the "Properties" group on the far left. It has a button called "Resize table".
Is there a way to programmatically resize a Excel table via VBA?
Thank you,

Dennis

 


Comment by: Jan Karel Pieterse (1/31/2010 10:20:06 PM)

Hi Dennis,

The example code is already on this page, sub called "TableInsertingExamples". This adds a column:

Selection.ListObject.ListColumns.Add

 


Comment by: Ramu (2/3/2010 7:04:56 AM)

Hi Karel,
I've created a user form using Excel 2007 to enter data in a worksheet and everything works fine as long as I write my data into the defined range of the worksheet. But when I convert the data range into a table, the data entered using the form are put outside the table. What's wrong. Many thanks in advance for your help.

Ramu

 


Comment by: Jan Karel Pieterse (2/3/2010 7:08:44 AM)

Hi Ramu,

Without any code examples this is very hard to solve.
I advise you to post your question -with sample file- here:

http://eileenslounge.com

 


Comment by: Ramu (2/3/2010 10:24:19 PM)

Hi Karel,
Sorry, and here is the code:

Private Sub cmdAdd_Click()
Dim iRow As Long
Dim ws As Worksheet
Set ws = Worksheets("Offres")

'find first empty row in database
iRow = ws.Cells(Rows.Count, 1) _
.End(xlUp).Offset(1, 0).Row

'check for a part number
If Trim(Me.txtCmpny.Value) = "" Then
Me.txtCmpny.SetFocus
MsgBox "Veuillez introduire une offre !"
Exit Sub
End If

'copy the data to the database
ws.Cells(iRow, 1).Value = Me.txtCmpny.Value
ws.Cells(iRow, 2).Value = Me.txtFName.Value
ws.Cells(iRow, 3).Value = Me.txtName.Value
ws.Cells(iRow, 4).Value = Me.txtProduct.Value
ws.Cells(iRow, 5).Value = Me.txtSubBy.Value
ws.Cells(iRow, 6).Value = Me.txtDate.Value
ws.Cells(iRow, 7).Value = Me.txtOValue.Value
ws.Cells(iRow, 8).Value = Me.txtDelai.Value
ws.Cells(iRow, 9).Value = Me.txtConclusion.Value
ws.Cells(iRow, 10).Value = Me.txtIndex.Value
ws.Cells(iRow, 11).Value = Me.txtStatus.Value

'clear the data
Me.txtCmpny.Value = ""
Me.txtFName.Value = ""
Me.txtName.Value = ""
Me.txtProduct.Value = ""
Me.txtSubBy.Value = ""
Me.txtDate.Value = ""
Me.txtOValue.Value = ""
Me.txtDelai.Value = ""
Me.txtConclusion.Value = ""
Me.txtIndex.Value = ""
Me.txtStatus.Value = ""
Me.txtCmpny.SetFocus

End Sub

 


Comment by: Jan Karel Pieterse (2/3/2010 11:00:02 PM)

Hi Ramu,

This adds a new row at the bottom of your list and enters a number in each of its cells:
Sub AddRow2List()
    Dim oNewRow As ListRow
    Dim oCell As Range
    With ActiveCell.ListObject
        Set oNewRow = .ListRows.Add
        For Each oCell In oNewRow.Range
            oCell.Value = "1"
        Next
    End With
End Sub

 


Comment by: Ramu (2/4/2010 8:16:40 AM)

Hi Karel,
Thanks for the time you've spent on my problem. I put your piece of code first on top and then after my "Privat Sub cmdAdd_Click()" but nothing changed. The data are still outside the table. So, what did I wrong. (I'm a newbie to VBA). Can you help me out?

Ramu

 


Comment by: Jan Karel Pieterse (2/4/2010 8:27:51 AM)

Hi Ramu,

I expect this is what you need:

Private Sub cmdAdd_Click()
Dim ws As Worksheet
Dim oNewRow As ListRow
Set ws = Worksheets("Offres")
With ws.ListObjects(1)
Set oNewRow = .ListRows.Add
End With

'check for a part number
If Trim(Me.txtCmpny.Value) = "" Then
Me.txtCmpny.SetFocus
MsgBox "Veuillez introduire une offre !"
Exit Sub
End If

'copy the data to the database
oNewRow.Range.Cells(1, 1).Value = Me.txtCmpny.Value
oNewRow.Range.Cells(1, 2).Value = Me.txtFName.Value
oNewRow.Range.Cells(1, 3).Value = Me.txtName.Value
oNewRow.Range.Cells(1, 4).Value = Me.txtProduct.Value
oNewRow.Range.Cells(1, 5).Value = Me.txtSubBy.Value
oNewRow.Range.Cells(1, 6).Value = Me.txtDate.Value
oNewRow.Range.Cells(1, 7).Value = Me.txtOValue.Value
oNewRow.Range.Cells(1, 8).Value = Me.txtDelai.Value
oNewRow.Range.Cells(1, 9).Value = Me.txtConclusion.Value
oNewRow.Range.Cells(1, 10).Value = Me.txtIndex.Value
oNewRow.Range.Cells(1, 11).Value = Me.txtStatus.Value

'clear the data
Me.txtCmpny.Value = ""
Me.txtFName.Value = ""
Me.txtName.Value = ""
Me.txtProduct.Value = ""
Me.txtSubBy.Value = ""
Me.txtDate.Value = ""
Me.txtOValue.Value = ""
Me.txtDelai.Value = ""
Me.txtConclusion.Value = ""
Me.txtIndex.Value = ""
Me.txtStatus.Value = ""
Me.txtCmpny.SetFocus

End Sub

 


Comment by: Ramu (2/4/2010 10:48:20 AM)

Hi Karel,
Great, it works. Many thanks for your precious help.
Ramu

 


Comment by: Andrew Morgan (3/9/2010 10:19:19 PM)

How or can I select 2 non adjacent columns in range by referencing their column headings? The data comes from an external query and the column order may change, but not the names. I can do 1 column at a time, but not more. The following did not work:
Range("Table_Query_from_LegrandDB[[#All],[who],[when]]").Select

 


Comment by: Jan Karel Pieterse (3/9/2010 10:27:01 PM)

Hi Andrew,

You have to use a slightly different syntax:

Range("Table_Query_from_LegrandDB[[#All],[who]],Table_Query_from_LegrandDB[[#All],[when]]").Select

 


Comment by: damian (3/17/2010 5:27:58 PM)

Hi
I was testing vba code below, and need to trap if there are no rows in the table (ie the header record exists and but there are NO other rows)
Dim oL As ListObject
    Set oL = ActiveSheet.ListObjects(1)
    oL.DataBodyRange.Rows(oL.DataBodyRange.Rows.Count).Select

 


Comment by: Jan Karel Pieterse (3/17/2010 10:54:32 PM)

Hi Damian,

The DataBodyRange is not behaving very nicely, if there are no rows, it returns a runtim error when you try to access it. One way of doing it is by turning off error handling temporarily:

Sub TestForData()
    Dim oLo As ListObject
    Dim oRows As Range
    Set oLo = ActiveSheet.ListObjects(1)
    On Error Resume Next
    Set oRows = oLo.DataBodyRange
    On Error GoTo 0
    If oRows Is Nothing Then
        MsgBox "List has no rows"
    Else
        MsgBox "List contains " & oRows.Rows.Count & " rows"
    End If
End Sub

 


Comment by: Sasya (3/18/2010 2:50:38 AM)

Im working on 2007 Excel. Im trying to run a macro on an excel sheet from a different excel sheet. The macro is to open an excel and perform some operations on it. With the macro below I am able to open the excel( 2003 only but not 2007 ) but I am not able to perform any operation on it.
Code goes here

Sub Open()
Dim objXL
Set objXL = CreateObject("Excel.Application")
With objXL
    .Workbooks.Open ("E:\CAT\wordlist.xls")
    .Visible = True 'Might not want this
End With
Set objXL = Nothing
End Sub

 


Comment by: Jan Karel Pieterse (3/18/2010 3:43:07 AM)

Hi Sasya,

You normally do not have to open a new Excel session to do something with an Excel sheet. What is it you are trying to do?

 


Comment by: Damian (3/18/2010 5:24:53 AM)

Hi Jan,
Thank you for the error trapping on dataBodyRange. Next I Have another question is there a way to do subtotals in table based on a code in a column. I don't really want to use a pivot table as it will sort columns and row etc

ie
Code    Amt
1        10.00
1        15.00
total 1 25.00
2         5.00
total 2 5.00
total    30.00

Thanks
Damian

 


Comment by: William White (3/25/2010 1:51:30 PM)

Hint: Trapping ListObjects with an empty DataBodyRange

With Range("tbTable").ListObject
     If .ListRows.Count > 0 Then
            .DataBodyRange.etc...
     End If
End With

 


Comment by: William White (3/25/2010 1:55:32 PM)

Is it possible to delete all ListRows where values meet an error criteria: Example..

     Range("tbData[Criteria]").SpecialCells(xlHasFormula, xlErrors).EnitreRow.Delete

which does not work.

However, filtering [Criteria] = #N/A and "selecting" the visible cells (.Select) followed by Selection.EntireRow.Delete does appear to work.

Would like a direct solution without filtering or using Select.

 


Comment by: Jan Karel Pieterse (3/26/2010 3:18:52 AM)

Hi William,

You have to step through the column cell-by-cell, starting from the bottom so Excel does not loose track of which row it is processing:

Sub DeleteErrorCells()
    Dim lCt As Long
    With Range("Table1[UserName]")
        For lCt = .Rows.Count To 1 Step -1
            If IsError(.Cells(lCt, 1)) Then
                .Cells(lCt, 1).EntireRow.Delete
            End If
        Next
    End With
End Sub

 


Comment by: William White (3/26/2010 7:21:18 AM)

This is the fastest I have, however, the table has many columns and even with xlCalcManual and screenupdating off, the deletes are taking quite a long time. In the spreadsheet itself, manually I an filter on the errors, select all the errors and select delete. It asks me "Delete Entire Rows", to which I say "yes", and the deletion is done it appears in a single swipe. Perhaps the internal code is able to control calculation better than I can. Anyway, this code identifies contiguous groups of cells meeting the criteria and can remove them as a block:


Sub remNaItems(rng)

' ----- Remove all rows where "rng" has an error value
'
' "rng" = table column reference, eg = "table[Column]"

    Range(rng).Worksheet.Calculate
    
    savedCalc = Application.Calculation
    savedUpdating = Application.ScreenUpdating
    Application.Calculation = xlCalculationManual
    Application.ScreenUpdating = False
    
    On Error GoTo exitSub
    Set items = _
     Range(rng).SpecialCells(xlCellTypeFormulas, xlErrors)
    
    On Error GoTo 0
    Range(rng).Worksheet.Unprotect
    n = items.Areas.Count
    For i = n To 1 Step -1
        items.Areas(i).EntireRow.Delete
    Next i
    Range(rng).Worksheet.Protect
    
exitSub:
    Application.Calculation = savedCalc
    Application.ScreenUpdating = savedUpdating

    Exit Sub
    
End Sub

 


Comment by: Rick Tipton (3/29/2010 6:09:02 AM)

Below allows me to select a cell in the data area of a 2007 pivot based on the cell value and formats the row. I have tried using "For Each C In .ListColumns(5).Cells
" in place of the .DataBodyRange but I have errors.

What needs to be changed to select the cell based on the Row Labels?

Sub FormatPage01Pvt1()
    Dim C As Range
    With ActiveSheet.PivotTables("Page01Pvt1")
    
    'Reset default formatting
    With .TableRange1
        .Font.Bold = False
        .Interior.ColorIndex = 0
        .Font.ColorIndex = 0
    
        End With
    
    'Apply formatting to each row if condition is met
    For Each C In .DataBodyRange.Cells

        If C.Value = 1 Then

            With .TableRange1.Rows(C.Row - .TableRange1.Row + 1)
                .Font.Bold = True
                .Interior.ColorIndex = 46
                .Font.ColorIndex = 2
                .Borders.ColorIndex = 0
            End With
        End If
    Next
    
    End With
        
End Sub

 


Comment by: Jan Karel Pieterse (3/29/2010 6:24:50 AM)

Hi Rick,

The proper syntax is:

For Each C In .ListColumns(5).Range.Cells

Note that the index is zero-based, so this is the sixth column of the table we're addressing here...

 


Comment by: William White (4/14/2010 1:20:41 PM)

We're moving files from Windows servers to SharePoint and I need to convert over some of my file manipulation code.

Old code:

FileCopy saCostsFolder & costModel, fnCostModel

This works when saCostsFolder is a Windows address, eg. "\\Cffp\costs\" but seems to fail when I need a file located at "http://domain.com/SharePointSite/costs".

The error is #52 - "Bad file name or number".

Another method tried is fso.CopyFile, where fso is a File System Object.

The file is not an Excel file.

A more general question is whether there is an equivalent for the "Directories and Files Keywords" (that operate only on Windows style file systems as I understand it) for sharepoint files, or web-based files in general.

 


Comment by: Jan Karel Pieterse (4/14/2010 9:19:31 PM)

Hi William,

See if this page gets you there:
http://www.tek-tips.com/viewthread.cfm?qid=1497864&page=2

 


Comment by: hermine viaene (4/15/2010 3:30:24 PM)

dear Mr.Pieterse

hope you are well.First of all many thanks for all your very interesting info and tips , really very very usefull ..

I am trying in VBA to handle a table where I have to do several steps , I succeed to do a part of it ,but not completely.
in short : i have a table per mth starting 2010 with textnumbers(exc 22105,3506 eur)
I want to have this table per mth(alocated at the same place) starting 2009 and with values divided by 1000
(so resulting in 22,1053 )Do you think this can be done in 1 macro ?
Superthks on beforehand for your help - really appreciated
kindest regards
hermine

 


Comment by: Jan Karel Pieterse (4/16/2010 3:02:14 AM)

Hi Hermine,

I certainly do.
I advise you to go to this site to ask your question:
www.eileenslounge.com

 


Comment by: Patrick Matthews (4/18/2010 5:39:17 PM)

Jan Karel,

Excellent article! Interesting that the ListColumns collection is zero based. This is consistent with how table fields are handled in ADO and DAO, but of course inconsistent with just about all of the established Excel collections!

Oh well :)

Patrick

 


Comment by: Jan Karel Pieterse (4/19/2010 12:46:26 AM)

Hi Patrick,

Thanks! Yes, I love these inconsistencies in Excel (NOT) :-(

It does keep me in business though :-)

 


Comment by: Carim (4/22/2010 4:23:11 AM)

Jan Karel,

Thanks for your very interesting article ...

Is there a VBA code to easily delete all filtered rows from table... since my current loop takes way too long ...

Thanks in advance for your advice

Carim

 


Comment by: Asher Rodriguez (4/22/2010 6:52:01 AM)

I have a table linked to an ODBC data connection. I need to keep a history of the data before I update it. I have created a history table in another sheet in the workbook and manual copy the existing data to the end of the history table before updating the ODBC link.I recorded a macro to do this but it always pastes the data to a specific line of the history table (the line that was the end of table when I recorded it). I cannot find anywhere the code to alter my macro to set it to paste the data to the END of the history table. Any help?

 


Comment by: Jan Karel Pieterse (4/22/2010 7:58:33 AM)

Hi Carim,

Something like this :

With ActiveSheet.ListObject1.DataBodyRange
    .SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With

 


Comment by: Jan Karel Pieterse (4/22/2010 8:04:00 AM)

Hi Asher,

You could use a line of code like this to select the last used cell in column A:

With Worksheets("Sheet1")
    .Range("A" & .Rows.Count).End(xlUp).Offset(1).Select
End With

 


Comment by: Carim (4/22/2010 8:31:47 AM)

Hi Jan Karel,

Many thanks for your suggestion ...
Will try it right away ... It will be a relief for over 60'000 rows to be filtered ...

Cheers
Carim

 


Comment by: Carim (4/22/2010 10:25:24 AM)

Hi Jan Karel,

Sorry to bother you again ... but following code just filters and does not delete ...
I am using Excel 2010 beta... does it matter ?


With ActiveSheet.ListObjects("Table1")
.Range.AutoFilter Field:=56, Criteria1:="0"
.DataBodyRange.SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With


If need be, I can try on another machine with Excel 2007

Thanks again for your kind assistance
Best Regards
Carim

 


Comment by: Jan Karel Pieterse (4/23/2010 1:12:27 AM)

Hi Carim,

I'm sorry, the code I gave appears to be wrong.This should do the trick:

Sub Test()
    Dim lCt As Long
    Dim oArea As Range
    With ActiveSheet.ListObjects(1)
        .Range.AutoFilter Field:=1, Criteria1:="0"
        For Each oArea In .DataBodyRange.SpecialCells(xlCellTypeVisible).Areas
            For lCt = oArea.Rows.Count To 1 Step -1
                oArea.EntireRow.Rows(lCt).Delete
            Next
        Next
    End With
End Sub

 


Comment by: Carim (4/23/2010 9:27:09 AM)

Hi Jan Karel,

Thanks a lot for your help ...

Your first solution works fine, provided sorting is applied beforehand ...
And your second solution does the trick as expected, but without the need to sort !!! Excellent !!!

Again, my sincere thanks for all your advice

Best Regards

 


Comment by: Asher Rodriguez (4/28/2010 8:02:55 AM)

Hi Jan Karel,

Thanks for your suggestion, I used a different form of it but it sure did point me in the right direction.

I have another question. I am pasting my code in so you can see what I am doing this time :-)

This code worked just fine yesterday, but today it give me a run-time error and stops at Line 9: Sheets("Test Request Table CURRENT").Select

Can you help?


Sub TR_Tracking_Refresh()


    Sheets("Test Request Table CURRENT").Select
    Range("Table_SysTest").Select
    Selection.Copy
    Sheets("TR_Table_Recent_Past").Select
    Range("Table_Recent_Past").Select
    Selection.End(xlDown).Select
    ActiveCell.Offset(1, 0).Select
    ActiveSheet.Paste
    Sheets("Test Request Table CURRENT").Select
    ActiveWorkbook.RefreshAll
    Range("Table_SysTest[Download Date]").FormulaR1C1 = "=TODAY()"
    Range("Table_SysTest[Download Date]").Select
    Selection.Copy
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False
    Range("A2").Select
    Application.CutCopyMode = False
    Range("A2").Select
    
End Sub

 


Comment by: Jan Karel Pieterse (4/28/2010 10:12:13 AM)

Hi Asher,

My guess is that there is no sheet called
"Test Request Table CURRENT"
in the workbook that is active when trying to execute that line.

 


Comment by: Asher Rodriguez (5/6/2010 6:04:32 AM)

Hello again Jan Karel :-)

I have another issue I was hoping you could assist me with.

My range is cells U4:AF302.

The columns represent one month in the fiscal year. The rows are the tasks for a project. People input percent complete values into the cells.

What I am trying to do is make it so that if the is a value of 100 in the column to the left (starting with column V) then it will automatically fill the rest with 100 through the last column.

I can't do it in cell with an IF statement (ex. for cell V4: IF(U4=100,100,"")) like I planned to at first because the users don't like typing over formulas.

Can you help me figure out how do it in the page code?

 


Comment by: Martin Bustios (5/6/2010 7:48:06 PM)

Jan,

Thanks very much for posting this information on tables. I was wondering if you new what is the VBA code to turn off the auto-expansion property of tables.

Thanks ! in advance

Martin

 


Comment by: Jan Karel Pieterse (5/7/2010 5:17:30 AM)

Hi Martin,

I recorded a macro whilst turning it off and got this:

Application.AutoCorrect.AutoExpandListRange = False

 


Comment by: Jan Karel Pieterse (5/7/2010 5:53:51 AM)

Hi Asher,

If you rightclick the sheet tab and select View code and paste in this code I think it will do what you need:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Intersect(Target, Range("U4:AF302")) Is Nothing Then Exit Sub
    If Target.Cells(1, 1).Value = 100 And Target.Cells(1, 1).Offset(, 1).Column <= Range("AF1").Column Then
        Target.Cells(1, 1).Offset(, 1).Value = 100
    End If
End Sub

 


Comment by: Asher Rodriguez (5/7/2010 12:17:23 PM)

Jan Karel YOU ROCK! That code worked perferctly! :-)

If I could ask one last thing on this sheet I would be much grateful.

I have been searching many forums and books and still can't find a code that works for this task:

I need to allow ONLY paste values in ONLY in that same Range of cells. Range("U4:AF302")

I have tried many suggested bits of code from forums I found and so far nothing has worked right and now, somehow I can no longer Paste Special in ANY worksheet.

Please help. I really miss being able to paste special, and I would really love to be able to make just that onerenage within that one sheet be resticted to paste values only.

 


Comment by: Jan Karel Pieterse (5/8/2010 3:01:40 AM)

Hi Asher,

You would use code like the one I propose in this article:
www.jkp-ads.com/articles/catchpaste.asp

But you need to use worksheet events to turn that code on or off where needed.

I would suggest to turn it on or off for the entire worksheet, using the worksheet_activate and worksheet_deactivate events.

 


Comment by: Asher Rodriguez (5/10/2010 7:43:20 AM)

Before I can try this I still need to figure out how to re-enable the paste-special function on my right-click mouse menu.

I have tried lots of code and it seems as though somewhere in there it got disabled.

Any suggestions?

 


Comment by: Jan Karel Pieterse (5/10/2010 11:20:39 PM)

Hi Asher,

This little macro resets all right-click menu's of Excel:
Sub ResetAll()
    Dim cbar As CommandBar
    For Each cbar In Application.CommandBars
        If cbar.Type = msoBarTypePopup Then
            cbar.Reset
        End If
    Next cbar
End Sub

 


Comment by: kunal (5/24/2010 1:44:43 AM)

I have a dump of data in excel which is arranged in the format of a table. I want to write an excel code that processes the required information from the data dump and creates another table with my required rows and columns.
Could you please provide me with sample codes relevant to my problem ?

 


Comment by: Asher Rodriguez (5/24/2010 6:24:43 AM)

Jan Karel,

Thanks so much for the macro to re-enable my right click menu's. I learned a very valuable lesson about thoroughly checking out code before trying it.

I'm going to try and get that book on ribbons soon, thank so myuch for the reference, and I'm still studying how to work your catchpaste macro.

Thanks for making your expertise available for us beginners :-)

 


Comment by: Jan Karel Pieterse (5/24/2010 9:49:59 AM)

Hi Kunal,

Without knowing what processing is needed, this is hard to answer.

 


Comment by: Asher Rodriguez (5/24/2010 10:10:22 AM)

Hi again Jan Karel,

I am trying to create a macro that will:

1. create a table from exported data
2. hide all columns so i can then:
3. show only columns necessary (there are crazy amt of columns in this export)

I started with this code:

    ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$2:$CI$66"), , xlYes).Name = _
        "Table1"
    
    Range("Table1").EntireColumn.Hidden = True
    Range("Table1[Report]").EntireColumn.Hidden = False
    Range("Table1[Project]").EntireColumn.Hidden = False

End Sub

-And it works, but I need a lot of columns, so in order to avoid retyping this:

Range("Table1[Project]").EntireColumn.Hidden = False

for each column I tried to make this Sub-Procedure:

    

Sub showColumn(cName)
    Range("Table1[cName]").EntireColumn.Hidden = False
End Sub

-And I tried to call it using:

showColumn "Status"

-But I keep getting this error:

Method 'Range' of object '_Global' failed

-Any suggestions?

 


Comment by: Jan Karel Pieterse (5/25/2010 12:04:12 AM)

Hi Kunal,

This code should do it:

Sub HideColumn(sTableName As String, sColumnName As String)
    With ActiveSheet.ListObjects(sTableName)
        .ListColumns(sColumnName).DataBodyRange.EntireColumn.Hidden = True
    End With
End Sub

 


Comment by: Asher Rodriguez (5/25/2010 6:45:53 AM)

Good Morning Jan Karel :-)

Thanks for that code snippet. I modified it for my need and this is what I have now (deleted some columns in the interest of length):
ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$2:$A$66"), , xlYes).Name = _
        "Table1"
    
    Range("Table1").EntireColumn.Hidden = True
    
    showColumn "Table1", "Report"
    showColumn "Table1", "Project"
    showColumn "Table1", "Status"
    showColumn "Table1", "Date Created"


    'Formatting table view
    Range("Table1").WrapText = True
    Columns("A:A").ColumnWidth = 8
    Columns("B:B").ColumnWidth = 30
    Columns("U:U").ColumnWidth = 30
    
End Sub

Sub showColumn(tName As String, cName As String)
    With ActiveSheet.ListObjects(tName)
        .ListColumns(cName).DataBodyRange.EntireColumn.Hidden = False
    End With
End Sub


It works great!

I have a question though...

Is there a way I can create the table if the range of data is unknown? I never know how many lines there will be on the export.

Also, is there any way I can get this to work even if the table has a different name? What if there is already a table 1 when they run the code.
I keep searching the internet and my VBA books but nothing seems to fit quite right. I think I need to make a variable for the table name but not sure where to put it. I'm a bit frustrated since I took a VB Course last semester but it was all about making programs with GUI Forms and did not mention Excel at all. I thought it would help but it hasn't so far.

Thanks again so much for all your help, much more valuable than the course I took.

-Asher

 


Comment by: Joe Salmi (6/14/2010 3:38:30 PM)

Hi, I'm wondering if someone could PLEASE help me with this. I have a formatted table in Excel 2007 that I am pulling data from a home tab and pasting it into my table. My problem is I need the script to find the last row of data then move to the last column of the table so it can tab down and create a new row then paste in the information. With that being my main issue I come to another problem that I don't always have all the information I need at the time of pasting it.

My table headers are on Row 3 and my data goes from B4:L4. My last row of data is B37:L37 with 2 cells with out information in them. A constant would be my D column because it will always have data in it but the rest may not.
I'm looking to find the last row in column D then move over to the L column then tab to the new row (which would out me at B38 and then paste the information...

Can anyone help me with this?

 


Comment by: Jan Karel Pieterse (6/15/2010 12:47:48 AM)

Hi Joe,

If you already have something in your clipboard to paste, then this pastes that immediately below the table and makes it become a part of that table:

Sub PasteBelowTable()
    Dim oLo As ListObject
    Set oLo = ActiveSheet.ListObjects("Table1")
    ActiveSheet.Paste oLo.DataBodyRange.Offset(oLo.DataBodyRange.Rows.Count).Resize(1, 1)
End Sub

 


Comment by: Jo Salmi (6/15/2010 2:01:18 PM)

Jan Kare,

Thanks for the help, I am going to change it to your way but I did end up getting it working with this little bit:


Range("AA17:AK17").Select
    Selection.Copy
    ActiveWindow.ScrollColumn = 1
    Sheets("No List").Select
    Range("D4").End(xlDown).Offset(0, 8).Select
    Selection.ListObject.ListRows.Add AlwaysInsert:=False
    Range("D4").End(xlDown).Offset(1, -2).Select
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False
    Sheets("Home").Select


Everything else after that is the macro clearing the cells on my home sheet.

Joe

 


Comment by: Olivier (6/15/2010 5:46:05 PM)

I am trying to use a ListObject in a function, e.g.,

Function Test(Table As ListObject)
    MsgBox TypeName(Table)
End Function

but when I call that function in a formula, with a table name as argument where the ListObject is expected, e.g.

=Test(MYTABLE)

I get a value error saying that the data type is wrong. Is "MYTABLE" construed as a range rather than a ListObject and if so how should I pass the table?

 


Comment by: Jan Karel Pieterse (6/16/2010 12:24:21 AM)

Hi Jo,

Thanks for letting me know!

 


Comment by: Jan Karel Pieterse (6/16/2010 12:26:01 AM)

Hi Olivier,

Excel cells can only pass ranges and values to VBA functions, so your declaration must be changed to:

Function Test(Table As Variant)
    MsgBox TypeName(Table)
End Function

 


Comment by: Tjeerd (7/13/2010 8:14:15 AM)

Hello,

How can I fill the values of a range of cells with the visible values of a column of a listobject (without using the copy/paste method, which always gives me many runtime errors), using VBA?

This works for the complete list:
Range(destination).value = Listobjects("x").listcolumns(3).databodyrange.value

But I need this for only a part of the list values, based on a criterium. You know of a way to do this without copy/paste?

Thx in advance

 


Comment by: Jan Karel Pieterse (7/13/2010 10:17:34 AM)

Hi Tjeerd,

You could loop through the specialcells collection, cell type xlCellTypeVisible and use that.
Sub Demo()
    Dim lCt As Long
    Dim ocell As Range
    For Each ocell In ActiveSheet.ListObjects(1).DataBodyRange.SpecialCells(xlCellTypeVisible).Cells
        lCt = lCt + 1
        Range("a20").Offset(lCt).Value = ocell.Value
    Next
End Sub

 


Comment by: MARCO (7/13/2010 3:06:31 PM)

Hi,thank you for the usefull tips,
have you some experience in searching data within a table.
in excel is there the Vlookup function that works fine. Is there something similar the have a specific info from a table in VBA?
thank you for tha answer...
BRGDS
Marco

 


Comment by: Jan Karel Pieterse (7/13/2010 11:58:02 PM)

Hi Marco,

In VBA you can use
Application.WorksheetFunction.VLookup([argument list])

 


Comment by: Fred (8/5/2010 4:50:41 AM)

How can I know if the selected cell is a table cell?

 


Comment by: Kurt Roy (8/10/2010 12:56:54 PM)

Hello,

I have a range of cells bound to a ListObject. I would like to be able to have users type into one of its cells "=SUM(A2:B2)" (or whatever), and have the cell "remember" the formula.

Currently, When I type a formula into a cell backed by a list object, it immediately runs the formula for all cells in the column. I realize this is the "Calculated Fields" feature, but I would like to turn this off.

Any ideas would be appreicated.

 


Comment by: Rhoda Collins (8/10/2010 3:13:30 PM)

My excel spreadsheet is telling me when I try to access Visual Basics, that I am out of Memory.....How do I add more memory
Rhoda

 


Comment by: JEFF (8/16/2010 3:19:25 AM)

I am attempting to link a view in Sharepoint 3.0 with Excel 2007 using the following code:

Sub LINKPAGES()

ActiveSheet.ListObjects.Add SourceType:=xlSrcExternal, _
Source:=Array("http://server:45261/sites/Schaefer/Quality/_vti_bin", _
"{94F47A76-7A06-4BBC-B057-4D036508CD24}", _
"{BC63DC59-6685-4613-8F19-3BBABAB840ED}"), _
LinkSource:=True, Destination:=Range("A10")


End Sub



It works fine and will synchronize fine. The problem is the view in Sharepoint shows all folders and files in folders and subfolders. The linked view shows only the three folders of the root library.

How can I show all files and folders in the linked table?

Thanks in advance for your help.

 


Comment by: Jan Karel Pieterse (8/16/2010 3:20:23 AM)

Hi Jeff,

I'm sorry, I know close to nothing about Sharepoint lists!

 


Comment by: Jan Karel Pieterse (8/16/2010 3:29:42 AM)

Hi Fred,

Code like this:
If ActiveCell.ListObject Is Nothing Then
        MsgBox "Not in a table"
    Else
        MsgBox ActiveCell.ListObject.Name
    End If

 


Comment by: Jan Karel Pieterse (8/16/2010 4:31:10 AM)

Excel automatically fills a formula entered into a table cell in the entire column. You can click undo to undo that.

 


Comment by: Jan Karel Pieterse (8/16/2010 4:32:23 AM)

Hi Rhoda,

I expect memory has little to do with this. Maybe there is a problem with your VBA project. Try downloading and running Rob Bovey's code cleaner, to be found at http://www.appspro.com

 


Comment by: Damian (9/2/2010 9:44:34 PM)

How do determine if a column exists in a table?

 


Comment by: Jan Karel Pieterse (9/3/2010 7:30:00 AM)

Hi Damian,

You could loop through the cells of the listobject's HeaderRowRange:

Dim oCell as Range
For Each oCell in ActiveSheet.ListObjects(1).HeaderRowRange
    'Test here
Next

 


Comment by: Guy (9/12/2010 7:25:34 PM)

Hi Jan Karel,

Thanks for the excellent stuff!

I have a table in the range of B1:C2.
When I select C2, I want to get a column number within the table range.
For example, the column number of C2 is 3 in worksheet but it should be 2 in the table range because the table starts from column B.
How can I get it?

Thanks,
Guy

 


Comment by: Jan Karel Pieterse (9/12/2010 11:47:56 PM)

Hi Guy,

Fairly simple:
ActiveCell.Column - ActiveCell.ListObject.Range.Cells(1,1).Column

 


Comment by: Guy (9/13/2010 9:39:26 AM)

Hi Jan Karel,

Thanks a lot for your simple but very effective code.
I added '+1' at the end of your code because when I selected C2, it was returning not 2 but 1.

Would appreciate your advice to make my below macro simpler and more effective.

============
Sub Filter_Value()
    Dim iFieldCol As Integer
    Dim vValue As Variant
    Dim i As Integer
    Dim lDate As Long
    Dim iTbActiveCol As Integer
    
    iFieldCol = ActiveCell.Column
    vValue = ActiveCell.Value
    On Error GoTo 1
    lDate = vValue
    
    If Not (IsError(vValue)) Then
        If Not (IsError(lDate = vValue)) And vValue <> "" And lDate > 0 Then
            
            ActiveCell.AutoFilter Field:=iFieldCol, Criteria1:=">=" & lDate, _
                Operator:=xlAnd, Criteria2:="<=" & lDate
        Exit Sub
        End If
    End If
1
    If IsError(vValue) Then
        Select Case vValue
            Case CVErr(xlErrDiv0)
                vValue = "#DIV/0"
            Case CVErr(xlErrNA)
                vValue = "#N/A"
            Case CVErr(xlErrName)
                vValue = "#NAME?"
            Case CVErr(xlErrNull)
                vValue = "#NULL!"
            Case CVErr(xlErrNum)
                vValue = "#NUM!"
            Case CVErr(xlErrRef)
                vValue = "#REF!"
            Case CVErr(xlErrValue)
                vValue = "#VALUE!"
        End Select
    End If
    If Len(ActiveCell.Value) <= 255 Then
        If ActiveCell.ListObject Is Nothing Then
            On Error Resume Next
            Selection.CurrentRegion.AutoFilter Field:=iFieldCol, Criteria1:=vValue
        Else
            On Error Resume Next
            iTbActiveCol = ActiveCell.Column - ActiveCell.ListObject.Range.Cells(1, 1).Column + 1
            Selection.CurrentRegion.AutoFilter Field:=iTbActiveCol, Criteria1:=vValue
        End If
    Else
        MsgBox "Cannot filter because text length is greater than 255!", vbCritical, "FILTER"
    End If
End Sub
============
Thanks,
Guy

 


Comment by: Ngo Cham (9/17/2010 11:20:06 AM)

Hi Jan Karel,
Thank for your writes,
I have a table in a worksheet, when I set password to protect sheet with some cells (not in table), table does not work.
What can I do?

 


Comment by: Jan Karel Pieterse (9/19/2010 9:53:05 AM)

Hi Ngo,

I'm afraid that is a limitation of the table (list) object, when the wrksheet is protected, you cannot make the list larger or smaller, only edit the contents of the cells, provided you unlocked them.

 


Comment by: Lauri Reeves (9/21/2010 6:22:00 AM)

I have several tables on one worksheet (this is what my boss wants) and I am trying to add rows, which works fine until there are not rows between the tables. Then it errors out stating cannot shift cells. I know why this is happening, I just don't know how to keep a blank row between tables at all times. These tables grow on a weekly basis.

Any help would be appreciated.

Thank you, in advance, for any help.

 


Comment by: Jan Karel Pieterse (9/21/2010 7:16:20 AM)

Hi Lauri,

You must either have sufficient rows between tables, or have the tables next to each other instead of below each other. The only way to prevent the cannot shift error is by inserting empty rows between the tables before adding data.

If I were you, I'd tell your boss this is considered bad spreadsheet design (having multiple tables on one sheet that can grow).

 


Comment by: Leirimaa (10/11/2010 4:22:48 AM)

Hi,
I have 6 charts as objects in Chart sheet. I want to re-size the chart as I click on it. This works with 2003, but not with 2007. Macro recording does not give any help. What should I change t be able to use same functionality with 2007?

Here is the code that works with 2003:
***********************************************
Public Sub ZoomGraph_02()
    ActiveSheet.ChartObjects("Chart02").ShapeRange.ZOrder msoBringToFront
    With ActiveSheet.ChartObjects("Chart02")
        .Top = 0 ' reposition
        If .Height < 300 Then
            .Height = 500 ' resize
            .Left = 0 ' reposition
        Else
            .Height = 230
            .Left = 245 ' reposition
        End If
        If .Width < 300 Then
            .Width = 750 ' resize
        Else
            .Width = 245
        End If
    End With
End Sub
***********************************************
Thanks in advance
Markku

 


Comment by: Jan Karel Pieterse (10/11/2010 8:01:53 AM)

Hi Leirimaa,

I apologize, but I'm a bit too busy to answer your question on short notice I'm afraid.

So I'd suggest to go to www.eileenslounge.com with this question.

 


Comment by: Mr. Lost (10/13/2010 8:33:20 AM)

I havent used Excel in a while and my office is using 2007. Everything has changed dramatically. Where do I type this code? I dont even know where to start.

Thanks,

Mr. Lost

 


Comment by: Jan Karel Pieterse (10/13/2010 11:22:03 AM)

Hi Mr. Lost,

Surely, the VBA editor hasn't changed at all and luckily, VBA is barely touched too. You can get into the VBA editor by hitting alt+F11. Most of the code samples go into a normal module (Insert, Module).

 


Comment by: Jaideep Koratagere (10/16/2010 6:31:44 AM)

Is there a way to copy a custom table style from one workbook to another?

 


Comment by: Jan Karel Pieterse (10/16/2010 10:40:36 AM)

Hi Jaideep,

One way is by copying the table and pasting it somewhere into the other file. After that, the new style is available to use on other tables and you can remove the copy.

 


Comment by: Jaideep Koratagere (10/16/2010 1:23:50 PM)

Hi JKP,
Thanks for the reply, it worked! Couple of other questions now

1. If you save the theme for the excel file containing the custom table, is the custom table saved as part of the theme.

2. When you create a new table style, why is the font disable, i.e unable to set the font for the table style

 


Comment by: Jan Karel Pieterse (10/17/2010 5:13:02 AM)

Hi Jaideep,

I don't think the table style becomes part of the theme, it is only saved with the workbook.
I think different elements of the style can have different kinds of formatting being part of the style or not, depends on what part of the table style you select.

 


Comment by: Martha Jordan (10/24/2010 8:27:26 PM)

I have 3 locked tables on a worksheet, adjacent to each other. The sheet also contains a lot of other data, all locked or limited. The users need to be able to add table rows to the 3 mentioned (that's easy - just add to the bottom of each table using table name after unlocking in VBA)... BUT ALSO the ability to delete rows (that I can't accomplish alone - the active cell can be anywhere in the one-column table) through VBA to turn off the protection and then back on when done. I can't delete entire rows or more than one table will be affected.

I want to use
ActiveSheet.ListObject.ListRows(3).Delete
- without naming the table row. Can I pull the active cell automatically? I can't ask the user in an inputbox for a row number, because it's not the same as a table row number.

PLEASE HELP! Your resource here was sooooo close. Thank you in advance. :-)

MJ

 


Comment by: Jan Karel Pieterse (10/26/2010 12:54:54 AM)

Hi Martha,

You're close. The sample below takes the intersect of the current row and the databodyrange of the listobject (note that there can be no databodyrange if the list is empty, which will cause this code to error out!):

    With ActiveCell.ListObject
        Intersect(.DataBodyRange, ActiveCell.EntireRow).Delete xlUp
    End With

 


Comment by: Martha (10/26/2010 5:39:30 AM)

Thank you very much! After so much headache, I tried another way last night (before getting your answer) and it also works:
ActiveCell.Delete xlShiftUp


Don't you love that there's always multiple ways to solve any problem in Excel!?

Martha

 


Comment by: Jan Karel Pieterse (10/26/2010 5:43:56 AM)

Hi Riel,

I wouldn't have guessed that code to work, as it only appears to delete the active cell. But because the cell is in a table, VBA seems to assume it has to remove the entire datarow in that table.

 


Comment by: Abdul Azeez (11/9/2010 4:37:26 PM)

i have written code in excel module as below
-----------------------
Function HireCharges(TotHr As Date, TotKm As Integer)
Dim HRate As Integer, EKms As Integer
Dim Ehrs As Date, BRate As Integer
Dim Vhr As Integer, ACel As Variant
MaxT = Format(TimeValue("12:00 PM"), "h:mm:ss")
MinT = Format(TimeValue("06:00 AM"), "h:mm:ss")
ZroT = Format(TimeValue("00:00 AM"), "h:mm:ss")
TotHr = Format(TotHr, "h:mm:ss")
MaxK = 80: MinK = 40
FullRt = Range("K2")
HalfRt = Range("L2")
PerKm = Range("M2")
PerHr = Range("N2")
'Fixing Rates
If TotHr >= MaxT Or TotKm >= MaxK Then
    HRate = FullRt
Else
    HRate = HalfRt
End If
'Fixing Extra Kilometers
If TotHr >= MaxT And TotKm >= MaxK Then
    EKms = TotKm - MaxK
ElseIf TotHr > MinT And TotHr < MaxT And TotKm > MinK And TotKm < MaxK Then
    EKms = TotKm = MinK
End If
'Fixing Extra Hours
If TotHr > MaxT Then
    Ehrs = TotHr - MaxT
ElseIf TotHr < MaxT And TotHr > MinT And HRate = HalfRt Then
    Ehrs = TotHr = MinT
End If
'Base Rate Calculation
Vhr = (Ehrs - Int(Ehrs)) * 24
BRate = HRate
BRate = BRate + Round(EKms * PerHr, 0)
BRate = BRate + Round(Vhr * PerKm, 0)

ACel = ActiveCell.Address
RowX = ActiveCell.Row
ColX = ActiveCell.Column
CelX = ActiveCell.NumberFormat

If ColX = 5 And CelX = "0" Then
    XCel = ActiveCell.Address
    
    Selection.Offset(5, 0).Range("A1").Activate
    CelX = ActiveCell.NumberFormat
    ColX = ActiveCell.Column
End If

End Function

the offset command line is not working
i want the line working at this point
what shall i do

 


Comment by: Jan Karel Pieterse (11/10/2010 4:13:17 AM)

Seems to work fine for me. What error do you get?

 


Comment by: Abdul Azeez (11/16/2010 8:05:20 AM)

for Jan Karel Pieterse
Enter 10 in cell A1
Enter =Checkdoubt(a1) in B1
write the following code in excel module

function checkdoubt(x)
range("c1")=x*2
end function


now edit a1 and see what happens
this is the problem i am facing
i want the code run at this place

 


Comment by: Jan Karel Pieterse (11/16/2010 8:07:54 AM)

Hi Abdul,

A VBA function (which we call a User Defined Function or UDF) called from a cell cannot change the content of another cell. A UDF function only returns a value to the cell that called the function. So in your example, the proper code for the function is:

function checkdoubt(x)
checkdoubt=x*2
end function

 


Comment by: Abdul Azeez (11/23/2010 8:26:07 AM)

Thank you very much

 


Comment by: James (11/29/2010 8:45:37 AM)

Hi, I was wondering if you could shine a light on accessing specific parts of a table via a macro. For example

Type, Name, Status

Orange, Orange1, ripe
Orange, Orange2, mouldy
Apple, Apple1, firm
Banana, Banana1, ripe

say i want to operate on only the orange subset, and read all the values from name and status into a string (my actual database is much much larger) via a macro. the thing is, more subsets are added in all the time, so hardcoding isn't really an option. i was trying to use the dropdown menus to isolate the desired items and work on them from there. Do you have any suggestions?
help would be much appreciated

 


Comment by: Jan Karel Pieterse (11/29/2010 10:29:42 AM)

Hi James,

Depends what you want to do with the resulting data I guess. Could you perhaps provide a bit more detail?

 


Comment by: James (11/29/2010 3:20:12 PM)

the data im trying to get a hold of (from the macro) is a list of contact email addresses, i want to be able to send a subset of people an email by selecting their subset via dropdown filter on the table then running a macro, or is this not possible? or for the sake of simplicity, just copying the relevant info to a semicolon separated string (i've already written a macro so send an email to everyone in the list, easy peasy)
im not a vb programmer, more c#, the language difference to me is striking haha.

example:
Friend Type, Name, eMail

Uni, Bob, Bob@bob.com
Uni, Alice, Alice@alice.com
Uni, Charlie, Charlie@charlie.com
School, Giles, Giles@giles.com
School, Vicky, Vicky@vicky.com
Work, Ryan, Ryan@ryan.com

i would like to be able to send an email to say, all uni friends (there are many subsets so individual subs for each subset is impractical) how would i go about this?

 


Comment by: Jan Karel Pieterse (11/29/2010 11:13:45 PM)

Hi James,

You can use code like this to fetch the email addresses:

Function GetAddresses() As String
    Dim oCell As Range
    For Each oCell In ActiveSheet.ListObjects(1).DataBodyRange.Columns(1).SpecialCells(xlCellTypeVisible)
        GetAddresses = GetAddresses & oCell.Value & ";"
    Next
    GetAddresses = Left(GetAddresses, Len(GetAddresses) - 1)
End Function


You can either use this function from any sub in VBA or call it directly from a cell:

=GetAddresses()

In order for the function to work, you must be on the same sheet as where the list is.

 


Comment by: Andres (12/6/2010 3:25:17 PM)

Hello,

I am interested in copying information from a pivot table over to a new sheet, the thing is, the pivot table data is not always going to occupy the same region, so I want to account for that in the VBA code.

Once I select that data and place it in a new sheet, I want to create a table that will house the data.

the thing is I want to use VBA code to copy/paste the information from one sheet to another, and then create a table that will automatically stop on the last row and last column.

Hopefully my question makes sense.


Thanks,
Andres

 


Comment by: Jan Karel Pieterse (12/7/2010 12:49:36 AM)

Hi Andres,

This selects the entire pivot table:

activesheet.pivottables(1).tablerange1.select

 


Comment by: Andres (12/7/2010 8:23:46 AM)

Thanks!

That helped a lot.

Last question, is there a way to choose specific information, or set a row limit within a pivot table where it can copy information from and past in another location. let's say for example, my limit would be the last row that contains "Alerts" on Column "A".

Thanks.

Andres

 


Comment by: Jonathan (12/9/2010 3:36:00 AM)

Greetings,

First off - thanks for this article, I've been able to glean quite a bit from it. Thank you very much.

So I've read how you convert a table back to a normal range, but am wondering if you can convert a single row back to a normal range, and not the whole table?

The reason why I'd like to do this, is to allow myself to delete a table row, but only those cells within the table, and not the entire row itself. Doing so when the row is still a table gives you the "Operation not valid. Attempting to shift cells within your table" error.

Thanks,
Jonathan

 


Comment by: Jan Karel Pieterse (12/9/2010 1:45:36 PM)

Hi Andres,

See if this code example helps you out:
Sub SelectPivotUpToAlerts()
    Dim oCell As Range
    Dim oRange As Range
    Dim oSmallerRange As Range
    Set oRange = ActiveSheet.PivotTables(1).TableRange1
    For Each oCell In oRange.Columns(1).Cells
        If oCell.Value = "Alerts" And oCell.Offset(1).Value <> "Alerts" Then
            Exit For
        End If
    Next
    Set oSmallerRange = ActiveSheet.Range(oRange.Cells(1, oRange.Columns.Count), oCell)
    oSmallerRange.Select
End Sub

 


Comment by: Jan Karel Pieterse (12/9/2010 1:48:45 PM)

Hi Jonathan,

I'm afraid you'll either have to convert the entire table back to a normal range, or alternatively, change the size of the table range (resize table button on the properties group of the Tabletools design tabl on the ribbon), so the table ends above the area where you want to delete rows. Then after deleting the rows, resize the table back to the size you want it to be.

 


Comment by: diem (12/17/2010 2:20:10 PM)

true or false The only way to filter data is by selecting from a list of data.

 


Comment by: Jan Karel Pieterse (12/19/2010 12:13:54 PM)

Hi Diem,

Not entirely true, you can also use advanced filter.

 


Comment by: Larry T (1/3/2011 1:11:12 PM)

Here's what I'm trying to accomplish. For the active sheet, I need to import three different text files using data import. I've written a macro to accomplish this and massage the data the way it need it to. This works fine using ActiveSheet.QueryTable.Add. Here's the problem. For that same worksheet, I may need to reimport the data. The old data is no longer valid. So my process is to select the all the data in the sheet and to delete it and then reimport and process the data. This works too, but it keeps adding each query to the Query tables and of course to the name tables. I would like the query to actually be deleted when when I delete the data, but its not. If I do it manually, excel asks if you want to delete the query and if I say yes its deleted. I tried recording a macro this way and its no different from what I already have. Any suggestions on how I can delete the query and the names from the name table?

Cheers, Larry

 


Comment by: Jan Karel Pieterse (1/3/2011 10:47:37 PM)

Hi Larry,

Instead of removing your old QT and inserting new ones every time, why not just change their source file:

Sub ChangeQT()
    If ActiveSheet.QueryTables.Count < 1 Then
        'Add querytables here
    Else
        'I've assumed all QT remained...
        With ActiveSheet.QueryTables(1)
            .Connection = "TEXT;C:\Users\UserName\Documents\Copy of Same1.txt"
            .Refresh False
        End With
        With ActiveSheet.QueryTables(2)
            .Connection = "TEXT;C:\Users\UserName\Documents\Not Same.txt"
            .Refresh False
        End With
    End If
End Sub

 


Comment by: YOGESH K.S. (1/10/2011 11:25:20 PM)

how to extract the folder and inside folder(file) name in MS excel 2007 work sheet.kindly do the need ful.

regards,
Yogesh

 


Comment by: Jan Karel Pieterse (1/11/2011 4:59:33 AM)

Hi Yogesh,

Please ask your question here:
www.eileenslounge.com

 


Comment by: James P (1/13/2011 4:32:15 AM)

Hi

Bit of a basic question but what if I want to select a table and name it, in many different files but the number of rows always varies?

Many Thanks

Regards

James

 


Comment by: Jan Karel Pieterse (1/13/2011 4:54:44 AM)

Hi James,

So the files you refer to have "tables" on certain sheets, but they have not been formatted as a table yet?

If each "table" has no empty cells then you could use the CurrentRegion property of the range object to convert them to tables:

ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$1").CurrentRegion, , xlYes).Name = _
        "Table1"

 


Comment by: James P (1/13/2011 5:20:54 AM)

Hi

Thank you for your time. I tried to follow your guide on sorting by colour, but how would I combine that with sorting of coloumn 1 (A) and coloumn 10 (J)

        ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$10").CurrentRegion, , xlYes).Name = _
        "Table1"
    With ActiveWorkbook.ActiveSheet.ListObjects("Table1")

        .Sort.SortFields.Clear
        .Sort.SortFields.Add( _
                Range("Table1[[#All],[Column1]]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
        xlSortNormal
                Range ("Table1[[#All],[Column10]]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
        xlSortNormal
        With .Sort
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With


I know it's going to be something really simple, but this the first time I'm trying to code it rather than use the record macro.

Thank you again for your time and patience.

Regards

James

 


Comment by: Jan Karel Pieterse (1/14/2011 3:12:12 AM)

Hi James,

The simplest way to see how to sort by color on more than one column is by recording a macro whilst setting up one.
Basically, you repeat the Sortfields.Add line for each separate sort rule before issueing the Sort.Apply command.

 


Comment by: James P (1/14/2011 3:27:21 AM)

Hi

I realised after I posted I hadn't made myself clear and couldn't edit. I don't want it to sort off colour, I just want ascending sort off two columns and was basing it off your code for the colour sort. When I recorded the macro it records the specific range of cells for that particular set of data. So I'm trying to get a generic code running but the debugger is giving me errors on the .add lines of code and I can't see what's the difference between my code and yours other than what we want to sort by.

Thank you again.

Regards

James

 


Comment by: Jan Karel Pieterse (1/14/2011 3:53:48 AM)

Hi James,

OK, got it.

You have:
.Sort.SortFields.Add( _
                Range("Table1[[#All],[Column1]]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
        xlSortNormal
                Range ("Table1[[#All],[Column10]]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
        xlSortNormal


I think that should be:

.Sort.SortFields.Add( _
                Range("Table1[[#All],[Column1]]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
        xlSortNormal)
.Sort.SortFields.Add( _
                Range("Table1[[#All],[Column10]]"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
        xlSortNormal

 


Comment by: Lauri (1/19/2011 2:17:09 PM)

I have a worksheet ("TempData"). If cells in column C say "Empty" then add that row to Table1_1 which resides in worksheet ("DataSource"). I get an error message that states: "Object variable or With block variable not set." I finally realized this is because I had to select the datasource worksheet before I run the macro. My question is, is there a way to specify the worksheet other than Worksheets("DataSource").Select, which, by the way I added before the 'For each' statement. Just curious to see if there is a better to do this. Thank you for your help and time. (By the way, thanks for oNewRow help.)

Sub UpdateSource()
    

Dim oNewRow As ListRow

'Set variables
WB1 = ActiveWorkbook.Name '=the name of the active workbook
WS1 = "TempData"


    Set rng1 = Workbooks(WB1).Sheets(WS1).Range("C2:C" & Workbooks(WB1).Sheets(WS1).Range("C" & Workbooks(WB1).Sheets(WS1).Rows.Count).End(xlUp).ROW)
    'Set rng2 = oNewRow

    For Each a In rng1
        If a.Value = "Empty" Then
        Set oNewRow = Selection.ListObject.ListRows.Add(AlwaysInsert:=True)
        oNewRow.Range.Cells(1, 1).Value = a.Offset(0, 1).Value
        oNewRow.Range.Cells(1, 4).Value = a.Offset(0, 2).Value
        oNewRow.Range.Cells(1, 3).Value = a.Offset(0, -1).Value
        oNewRow.Range.Cells(1, 2).Value = a.Offset(0, -2).Value
    End If
Next a
End Sub

 


Comment by: Jan Karel Pieterse (1/19/2011 10:51:31 PM)

Hi Lauri,

I modified your code a little bit:

Sub UpdateSource()

    Dim WS1 As String
    Dim oNewRow As ListRow
    Dim rng1 As Range
    Dim a As Range
    'Set variables
    WS1 = "TempData"

    With ActiveWorkbook.Sheets(WS1)
        Set rng1 = .Range("C2:C" & .Range("C" & .Rows.Count).End(xlUp).Row)
    End With

    For Each a In rng1
        If a.Value = "Empty" Then
            Set oNewRow = ActiveWorkbook.Worksheets("Datasource").ListObjects(1).ListRows.Add(AlwaysInsert:=True)
            oNewRow.Range.Cells(1, 1).Value = a.Offset(0, 1).Value
            oNewRow.Range.Cells(1, 4).Value = a.Offset(0, 2).Value
            oNewRow.Range.Cells(1, 3).Value = a.Offset(0, -1).Value
            oNewRow.Range.Cells(1, 2).Value = a.Offset(0, -2).Value
        End If
    Next a
End Sub

 


Comment by: mohd (1/23/2011 2:27:43 AM)

thanks for ur help but i need the rows and column to be format.

thanks in advance

 


Comment by: Jan Karel Pieterse (1/23/2011 6:36:41 AM)

Hi Mohd,

Can you explain what you need more precisely?

 


Comment by: Mohd (1/25/2011 8:10:54 AM)

Hi James,


Please note that above code expend the line formate down between Rows while im looking to have border around cell as





 


Comment by: Jan Karel Pieterse (1/25/2011 10:22:52 PM)

Hi Mohd,

You can modify a table's style by creating a custom style (described elsewhere in the article), but I doubt if you can set it up to have alternating borders.

 


Comment by: Hans (1/28/2011 9:23:39 AM)

In your article you show how to remove a table. But how do you simply restore the worksheet to its original plain form without the table formatting yet maintaining whatever data exists?

 


Comment by: Jan Karel Pieterse (1/28/2011 12:35:37 PM)

Hi Hans,

The "Convert Table to range" button does what you need.
In VBA it is the Listobject.Unlist method.

 


Comment by: Hans (1/28/2011 4:20:41 PM)

That's what I thought but it appears that the Listobject.Unlist method results in removing the table but not the formatting if one of the tablestyles has been used.

I have no problem selecting the table and then clicking on Cell Styles - Normal, but I would like to do it programmatically.

 


Comment by: Jan Karel Pieterse (1/29/2011 3:01:06 AM)

Hi Hans,

You could:


Dim oRng as Range
Set oRng=ActiveSheet.ListObjects(1).Range
ActiveSheet.ListObjects(1).Unlist
oRng.Style="Normal"

 


Comment by: Hans (1/30/2011 4:38:46 PM)

Thanks for your help. As expected, it works. Now for another question:

I have set a worksheet object: objws=Worksheets(1).ActiveSheet
I then create a ListObject using
     objlistobj = objws.Listobject.Add . . . .

which produces the desired listobject. I then remove the table
     objlistobj.unlist

That works too. But the following unexpected event happens.

    The object "objws" is set to nothing.

Presumably it's because it's part of the objlistobj definition. But the intention is merely to remove the ListOject from the Worksheet, not to lose the Worksheet object, also. Am I missing something?

 


Comment by: Jan Karel Pieterse (1/30/2011 10:16:55 PM)

Hi Hans,

I assume you do use the Set keyword in you code:
Set objws = ActiveSheet
?

I cannot repro your issue in Excel 2010.

 


Comment by: Hans Gruenberg (1/31/2011 6:04:34 AM)

I used: set objws = Worksheets(1).ActiveSheet

My Excel version is 2007 v.12.0.6300.5000

In my code I followed the .unlist statement with another using objws. and received a "Need object" type of error.
I then repeated the set objws statement between the unlist and the next objws. statement and the error went away.

 


Comment by: Jan Karel Pieterse (1/31/2011 6:26:34 AM)

Hi Hans,

The correct syntax is either:
Set objws = ActiveSheet
or
Set objws=Worksheets(1)
depending on wich worksheet you need.

This code works fine for me on my Excel 2007:

Sub foo()
Dim objws As Worksheet
Set objws = ActiveSheet
objws.ListObjects(1).Unlist
MsgBox objws.Name
End Sub

 


Comment by: Torstein S. Johnsen (2/4/2011 3:24:44 AM)

Thanks for your great article about excel tables and VBA, and as you say "On the VBA side there seems to be nothing new about Tables".
Is there a way to make some VBA code work on "the ActiveTable". I have been looking for such an expression, but it's not there.
I have several similar tables, and I have made a sort-procedure that I would like to work on the table thats selected when the procedure is started.

 


Comment by: Jan Karel Pieterse (2/4/2011 3:46:17 AM)

Hi Torstein,

You can access a table belonging to the activecell like this:

ActiveCell.ListObject
Should the activecell not be part of a table, then this is Nothing:

If ActiveCell.ListObject Is Nothing Then
    MsgBox "Actve Cell not in a table"
ENd If

 


Comment by: Marco V. (2/17/2011 4:52:27 PM)

Hello, thanks for the info!

Can you tell me how i can change the name of a table? i use now this script but the name is stil a problem because the pivot table is looking at table name.

Application.Wait Now + TimeValue("00:00:01")
Application.ScreenUpdating = False
Dim myLastRow As Long
Dim myLastColumn As Long
Range("A2").Select
On Error Resume Next
ActiveSheet.ListObjects.Unlist
    Range(Selection, Selection.End(xlDown)).Select
    Range(Selection, Selection.End(xlToRight)).Select
myRange = "A2:" & myLastCell
ActiveSheet.ListObjects.Add.TableStyle = "TableStyleMedium2"
Application.ScreenUpdating = True
Range(myRange).Select

 


Comment by: Jan Karel Pieterse (2/20/2011 11:09:05 AM)

You could change the last part of your code to:

With ActiveSheet.ListObjects.Add
.TableStyle = "TableStyleMedium2"
.Name="TableNameGoesHere"
End With
Application.ScreenUpdating = True
Range(myRange).Select

 


Comment by: Jay (3/12/2011 10:03:50 PM)

Thanks for this information - I have been looking for info specific to table row manipulation and not just ranges.
I am tinkering around with an employee progress tracking sheet that monitors how many "widgets" they sell each day during a week. With your help from above I have the ability to add a button at the top of each table (1 table per store department) and by clicking it a new row is inserted which indicates someone was hired.

I have gotten the ability to insert using the code:

' Each department has a button that runs the first Sub below and passes on an argument to the add_employee(dept) Sub.
Sub add_ladies_wk1() 'Button on Ladies table activates this
    Dim dept As String
    dept = "ladies"
    add_employee (dept)
End Sub

Private Sub add_employee(dept As String)
    Dim oSh As Worksheet
    Set oSh = ActiveSheet
    oSh.ListObjects(dept).ListRows.Add AlwaysInsert:=True
End Sub

Now what I need is a way to fire people - I would love for a button to be in a cell next to each of their names that can be clicked with a confirmation dialog box. On click it would delete that record and shift rows up as to not leave blank spaces. Any ideas?

Thanks for the help!
Jay

PS - Sorry if this double posts. I didn't see the message to use the VB tags around the code

 


Comment by: Jan Karel Pieterse (3/13/2011 11:42:51 AM)

Hi Jay,

Thanks for sahring your code. I removed your duplicate post, no problem at all!

 


Comment by: Ayaz S. Zanzeria (3/16/2011 6:24:32 AM)

Hi,

I have an 2007 excel sheet that has a table whose data is populated from an external data source. This data has various vendors in a column called "vendor". Based on the Vendor, I want to segregate the data in different sheets for the different Vendors. Please let me know how do I reference the individual table values in a loop. I have these two lines of code as an example which are a no go.

First Attempt:
Select Case Table_WOV.Range("[#This Row],[vendor]").Value


Second Attempt:
Select Case Range("Table_WOV[[#This Row],[vendor]]").Value


Thanks in advance for your help.

Thanks & Regards,
Ayaz S. Zanzeria.

 


Comment by: Jan Karel Pieterse (3/16/2011 8:13:18 AM)

Hi Ayaz,

You can access a specific column in a listobject on the active worksheet like so:

Sub GetValueFromTable()
    Dim oLo As ListObject
    Set oLo = ActiveSheet.ListObjects("Table_WOV")
    MsgBox oLo.ListColumns("vendor").DataBodyRange.Rows(1).Value
End Sub

 


Comment by: Jonathan (3/27/2011 2:41:46 AM)

Greetings,

Your work here has really helped in my development of some Excel/VBA projects at my work, however I'm experiencing one problem.

In my Excel project I have a table where people log information, from this table I've created a function to search the table and calculate a number of different sets of data. In order to search the table, I've followed your example in referencing the ListObjects as seen below:

Dim oSh As Worksheet
Set oSh = ActiveSheet

For c = 0 to (k - oSh.ListObjects("Hours").ListRows(1).Range.Row)
....
....

The function works great when the sheet where the data is located at is selected. However I have a number of graphs that are based on this data on additional sheets, and when those sheets are selected my data somehow goes away. I'm guessing this is due to my function using "ActiveSheet" - Is there anyway to specify which sheet that my ListObjects is referring to.

I've tried..

Set oSh = Worksheets(1)
Set oSh = Sheets(1)

and neither has worked.

Thanks,
Jonathan

 


Comment by: Jan Karel Pieterse (3/27/2011 11:14:26 AM)

Hi Jonathan,

You could use
Set oSh = Worksheets("SheetNameGoesHere")

 


Comment by: Scott Bernard (4/13/2011 5:59:56 AM)

Sorry if I am not posting correctly. To preface my question, I use vba code to parse out text docs(not important) to create tables and link them to a Sharepoint list (not important). I then *attempt* to update and modify the data.
My question is regarding the tables - after modifing the data I can not get around the table duplicated the rows with the new data.

Thanks

 


Comment by: Jan Karel Pieterse (4/13/2011 9:33:24 AM)

Hi Scott,

Nothing wrong with your post!
I know close to nothing about sharepoint lists, so all I can suggest is to find a forum on Sharepoint to ask your quetsions.

 


Comment by: Scott (4/13/2011 9:42:01 AM)

I understand, I was kind of misleading. The question really pertains to excel tables (2010/2007). When I attempt to copy data (vba) sometimes rows seem to duplicate.

 


Comment by: Jan Karel Pieterse (4/14/2011 1:44:59 AM)

Hi Scott,

Can you post the relevant piece f code please?

 


Comment by: scott (4/14/2011 7:32:25 AM)

I am using a simple copy statement. I am not sure if it is a coincidence but the code is working now. The only thing I did differently is to add Set for workbook & sheets (instead of naming the workbook). However, instead of copying just the modified data, I started to copying the same range e.g "A2:D2000" (blanks and all).
Thanks though :)

 


Comment by: John Redmon (4/17/2011 7:46:23 AM)

Hi Jan,
I've been using your examples to gain a better understanding of VBA and tables and they have helped tremendously. I have encountered one problem I can't resolve. I'm using Excel 2007.
Sub SelectingPartOfTable()
    Dim oSh As Worksheet
    Set oSh = ActiveSheet
    With oSh.ListObjects("Table1")
        'Select third column
        .ListColumns(3).Range.Select
        'Select a column by name
        .ListColumns("Part#").Range.Select
    End With

    
This works with a pound sign in name column name, got the same results as using the column number.

The following fails if a "#" pound sign is in a column name.
'select an entire column (data plus header - Using name of column)
    'Will fail if "#" sign is in column name - Works if using a column name without pound sign.
    oSh.Range("Table1[[#All],[Part#]]").Select
    End Sub


Is there a way to get VBA to accept the pound sign in a column name using this statement?
Thanks,
John

 


Comment by: Jan Karel Pieterse (4/17/2011 10:10:18 AM)

Hi John,

Looks like when the column name has a pound sign in it you can't do it that way indeed. I guess the first example you gave is the only option then.

 


Comment by: Jono (5/2/2011 12:24:35 AM)

Hi

Thanks for this article, it's very informative.

I was just wondering, is there any way to take the currently selected cell and find the number of the row it's in?

As context, I've got some buttons on my spreadsheet that are used to add new rows to or delete rows from various tables on the page. For the 'delete' function, I'd like to highlight the entire table row based on the selection while a confirmation box is displayed, so my users can see exactly what will be deleted.

 


Comment by: Jan Karel Pieterse (5/2/2011 3:43:29 AM)

Hi Jono,

If the current cell already is in the table it is easy:

intersect(activecell.EntireRow,activecell.ListObject.DataBodyRange).Select

 


Comment by: Jono (5/4/2011 12:22:17 AM)

Thanks! That worked a treat!

 


Comment by: Peter (5/12/2011 5:20:42 PM)

From your example now I know how to select one column or all columns from a table. Thank you.
I would like to select only specific columns say column1 and column5. Could you please let me know how.

 


Comment by: Jan Karel Pieterse (5/13/2011 1:49:28 AM)

Hi Peter,

Can you tell me why you want to select the listcolumns?

I guess you could do it like so:


    With ActiveSheet.ListObjects(1)
        Union(.ListColumns("a").Range, .ListColumns("c").Range).Select
    End With

 


Comment by: Anthony (5/13/2011 6:57:39 PM)

Good article.

There was a bug introduced in 2007 fixed in 2010, in that if VBA code just puts values after the last row in a table/list, in 2003 1nd 2010 the table grows by one automatically, but not in 2007. Caused me nuiscence.

Also, it is a pity that XK 2003 tables don't have a border around them by default in 2007/10. Not everyone wants to update t .xlsx.

 


Comment by: Peter (5/15/2011 5:23:57 PM)

Hi Jan

Here is a sample table
FName LName City     State DOB     SSN
Peter David Seattle WA     1.1.90 123-45-6789
Kyle Eric    Redmond WA     2.2.89 987-65-4321

I want to copy the columns "FName","City" and "SSN" with the respective data and copy in a different worksheet("Sheet2") on the first three columns (the worksheet is blank). Pleast let me know how to do this. Appreciate your help





Hi Peter,

Can you tell me why you want to select the listcolumns?

I guess you could do it like so:

    With ActiveSheet.ListObjects(1)
        Union(.ListColumns("a").Range, .ListColumns("c").Range).Select
    End With

 


Comment by: Peter (5/15/2011 5:54:07 PM)

Hi Jan
I kind of figured how to do that.

Range("table1[[#all],[FName]],table1[[#all],[City]], table1[[#all],[State]]").Copy Range("M1")

If there is a better way let me know.
Thank you

 


Comment by: Anthony (5/15/2011 6:18:06 PM)

Actually, to clarify my previous comment, 2007 and 2010 appear to be consistently different from 2007. The difference is in the way the "*" insert row is created and that the ListObject.Range is different. And of course there is no insertrowrange. I actually prefered the 2003 behaviour.

 


Comment by: Jan Karel Pieterse (5/15/2011 9:09:56 PM)

@Peter: Your syntax looks fine to me. There are often many ways to do things in VBA.

@Anthony: I've seen similar problems in 2003 where it is hard to make sure your new data is appended to the table. 2007/2010 behave worse indeed. My workaround was to unlist the table/list, add the row and then re-list. But that causes havoc if you have formulas pointing to the table.

 


Comment by: Peter (5/16/2011 4:51:09 PM)

FName LName City     State DOB     SSN
Peter David Seattle WA 1.1.90 123-45-6789
Kyle Eric    Redmond WA 2.2.89 987-65-4321

I used the name of the columns (FName, City, State)in the code. It works even if the order of columns change or a new column is inserted in the table.
Actually what I really want to do is this. Delete the unnecessary columns from the table (It could be 3, 4 or .. more). I just want only these 3 columns.
Could you please let me know how to do this. Thank you.

 


Comment by: Jan Karel Pieterse (5/16/2011 10:59:33 PM)

Hi Peter,

I'd do something like this:

Sub DeleteListColumns()
    Dim oCols2Delete As Range
    Dim lCt As Long
    With ActiveSheet.ListObjects("Table1")
        Set oCols2Delete = Union(.ListColumns("City").Range, .ListColumns("State").Range, .ListColumns("DOB").Range)
    End With
    'count down to prevent VBA from getting confused
    For lCt = oCols2Delete.Areas.Count To 1 Step -1
        oCols2Delete.Areas(lCt).EntireColumn.Delete
    Next
End Sub

 


Comment by: Peter (5/17/2011 3:03:52 PM)

Hi Jan

Thanks for the quick reply. Your code works fine. It is really exciting to learn new things . Appreciate it. But there is one thing. Sorry if I am not explaining it right. I guess it is because I am not familiar with all the technical terms.

I manipulate a report which I get from a vendor site. The number of columns and the order of columns always change in that report. But it always has the columns that I wanted. I want to keep them and delete the rest of them and then do some calculations.

I just know the columns that I need. I don't know the ones I need to delete because it changes every time.

How would I do this



 


Comment by: Jan Karel Pieterse (5/17/2011 11:36:40 PM)

Hi Peter,

Sure, like this:

Sub DeleteListColumns2()
    Dim oColsNot2Delete As Range
    Dim lCt As Long
    With ActiveSheet.ListObjects("Table1")
        Set oColsNot2Delete = Union(.ListColumns("City").Range, .ListColumns("State").Range, .ListColumns("DOB").Range)
        'count down to prevent VBA from getting confused
        For lCt = .ListColumns.Count To 1 Step -1
            If Intersect(.ListColumns(lCt).Range, oColsNot2Delete) Is Nothing Then
                .ListColumns(lCt).Delete
            End If
        Next
    End With
End Sub

 


Comment by: Paul Jose (6/6/2011 7:37:28 AM)

Any idea how in Excel 2007 you hold the VBA code while the table refreshes ??

I inherited some code (below) from an old file, that doesnt seem to work in 2007.

' I open the file
ActiveWorkbook.RefreshAll
With Worksheets(1).QueryTables(1)
Do While .Refreshing = True
Loop
End With
ExistFault.Show
ActiveWorkbook.Save
ActiveWindow.Close

All help appreciated as this is doing my head in !

Paul

 


Comment by: Jan Karel Pieterse (6/7/2011 12:13:59 AM)

Hi Paul,

One way would be by doing each querytable/pivot table in turn and setting them to refresh synchronously, e.g.:

Sub Refreshall()
    Dim oPt As PivotTable
    Dim oQt As QueryTable
    Dim oSh As Worksheet
    Dim oLo As ListObject
    For Each oSh In Worksheets
        For Each oQt In oSh.QueryTables
            oQt.Refresh False
        Next
        For Each oLo In oSh.ListObjects
            On Error Resume Next
            Set oQt = oLo.QueryTable
            On Error GoTo 0
            If Not oQt Is Nothing Then
                oQt.Refresh False
            End If
        Next
    Next
    For Each oSh In Worksheets
        For Each oPt In oSh.PivotTables
            oPt.RefreshTable
        Next
    Next
End Sub

 


Comment by: Becky (6/10/2011 11:04:44 AM)

resolved issue regarding not seeing table-context-sensitive recording/formula building

saving as file type .xlsm wasnt quite enough...I needed to close and reopen the file.

I have to juggle between 2007 and 2003 compatible formatting- building a spreadsheet application that will be processing on a win 2010 or 2007 client, but then sent out to larger audience known to be limited to 2003...so I will have to see if I can use the fun features during processing before compiling a spreadsheet that could be opened for viewing in 2003.

again - I would really like to THANK YOU for putting very clear information on Excel out on the web- it was so helpful to find info I can understand and apply to help me figure out what is going on in my own world.

 


Comment by: Deepu (6/11/2011 1:57:50 PM)

I have a CSV file with large number of rows. I need to create a table in a separate worksheet, where I can just sum up the data with it's ID's, like if I have 10 rows for Monday, I need to put Monday in the table and in it's columns, I just put the total count for different names. To be more clear, on Monday, John made 5 saves, Patrick made 10, Tim made 4, etc.

So the row in the table is for Monday, and it's columns are 5, 10, 4, etc. where the header files can also be given as Day, John, Patrick, Tim, respectively. I hope I have been able to explain it clearly. I need help as soon as possible.

 


Comment by: Jan Karel Pieterse (6/14/2011 12:21:50 AM)

Hi Deepu,

I would take a 2-step approach:
1. Import the table using the steps outlined in the article
2. Create a pivot table report from the imported data.

 


Comment by: Ed (6/19/2011 5:01:10 AM)

Is there any elegant way of iterating over a table / listobject by row idiomatically like this (pseudo VBA)?

Assume a table called "People" with two columns, one headed "Firstname" the other "Surname".


Dim r As TableRow
For Each r In Table("People").Rows
MsgBox "The person is called: " r("Firstname").Value & " " & r("Surname").Value
Next r


everything I have read about VBA named ranges / tables / ListObjects seems to prevent this straightforward stanza. I have looked at how do do it, forming a collection class of table rows and binding to the table, but it seems as though this is such a simple requirement that I'm missing something blindingly obvious.

 


Comment by: Jan Karel Pieterse (6/19/2011 11:24:49 PM)

Hi Ed,

That is relatively straightforward, once you know which syntax to use :-)

Sub RunThroughRows()
    Dim oLo As ListObject
    Dim lCt As Long
    Set oLo = ActiveSheet.ListObjects("People")
    For lCt = 1 To oLo.DataBodyRange.Rows.Count
        MsgBox "Name of person number " & lCt & ": " & _
             oLo.ListColumns("firstname").DataBodyRange.Cells(lCt, 1).Value & _
             " " & oLo.ListColumns("lastname").DataBodyRange.Cells(lCt, 1).Value
    Next

End Sub

 


Comment by: Bibu Sebastian (6/21/2011 2:29:07 AM)

I have a pivot table, if I include a comment right to pivot table row, how will the comments get updated with the refresh pivot table. Kindly help.. plssssssss

 


Comment by: Rainhart (6/21/2011 4:36:17 AM)

How can I add an item to the tables contect menu, i.e. to a listObject?

 


Comment by: Jan Karel Pieterse (6/22/2011 12:44:04 AM)

Hi Rainhart,

Like this:

Sub AddItemToListPopupCommandbar()
    With Application.CommandBars("List Range Popup")
        With .Controls.Add(msoControlButton)
            .Caption = "MyCaption"
            .OnAction = "MyMacro"
        End With
    End With
End Sub

 


Comment by: Jan Karel Pieterse (6/22/2011 12:51:19 AM)

Hi Bibu,

Comments written in cells next to a pivot table will not move when you refresh the pivot table and the rows of the pivot table shift.

If you want that to happen, you could add a small table which contains all the possible row items of the pivot table (for example, all countries if you have countries as a row field) and write the comments next to that new table.

Then next to the pivot table, use a vlookup function to find the comment belonging to the pivot table's rowfield value. When building the VLOOKUP function, make sure you use a normal cell reference to the pivot field cells, not the GetPivotData function.

 


Comment by: Rainhart (6/22/2011 2:38:34 AM)

Thank you, Jan!

I had tried with "Cell" instead of "List Range Popup".

 


Comment by: AJ (6/23/2011 10:35:55 AM)

Hi,
I have a macro the adds lots of data (9000 rows and 6 cols) to a table. There is another table (9000 rows and 10 cols) calculated based on the first one. In the workbook there are also lots of formulas linked to this 2 tables. Because of this, it takes a lot of time (1-2 minute) to add the data to the first table.
The calculations is set to manual. Events and screen updating are turned off, but nothing helps reduce the time.
Can you please advise anything?

 


Comment by: Jan Karel Pieterse (6/24/2011 5:27:51 AM)

Hi AJ,

One thing you could do is add the data below the table, but leave an empty row in-between your new data and the table, thus preventing Excel from expanding the table.
Then once all data is "in", remove the empty row and then expand the table.

 


Comment by: Marina (6/24/2011 12:02:17 PM)

Hi! I want to use a specific range to create a table with a chart using the range I have selected, however it seems not to work. Could you please let me know why? Thanks!


Private Sub CommandButton1_Click()
    Dim oRangeSelected As Range
    On Error Resume Next
    Set oRangeSelected = Application.InputBox("Please select a range of cells!", _
                                             "SelectARAnge Demo", Selection.Address, , , , , 8)
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
Set objWorkbook = objExcel.Workbooks.Add()
Set objWorksheet = objWorkbook.Worksheets(1)
Set objRange = objWorksheet.UsedRange
objRange.Select

Set colCharts = objExcel.Charts
colCharts.Add

Set objChart = colCharts(1)
objChart.Activate

objChart.ChartType = 65

objChart.PlotArea.Fill.PresetGradient 1, 1, 7

objChart.SeriesCollection(1).Border.Weight = -4138
objChart.SeriesCollection(2).Border.Weight = -4138
objChart.SeriesCollection(3).Border.Weight = -4138

objChart.SeriesCollection(1).Border.ColorIndex = 2
objChart.SeriesCollection(1).MarkerBackgroundColorIndex = 2

objChart.SeriesCollection(2).MarkerForegroundColorIndex = 1
objChart.SeriesCollection(3).MarkerForegroundColorIndex = 1

objChart.HasTitle = True
objChart.ChartTitle.Text = ""
objChart.ChartTitle.Font.Size = 18

objChart.ChartArea.Fill.Visible = True
objChart.ChartArea.Fill.PresetTextured 15

objChart.ChartArea.Border.LineStyle = 1

objChart.HasLegend = True
objChart.Legend.Shadow = True

    If oRangeSelected Is Nothing Then
        MsgBox "It appears as if you pressed cancel!"
    Else
        MsgBox "You selected: " & oRangeSelected.Address(External:=True)
    End If

End Sub
.

 


Comment by: Jan Karel Pieterse (6/27/2011 2:44:02 AM)

Hi Marina,

Your code fails because you first insert a new -empty- workbook and then try to create a chart, which will have no series because there is no data. You are also instantiating a new instance of Excel, which is not needed. I think this code will do the trick:

Private Sub CommandButton1_Click()
    Dim oRangeSelected As Range
    On Error Resume Next
    Set oRangeSelected = Application.InputBox("Please select a range of cells!", _
                                             "SelectARAnge Demo", Selection.Address, , , , , 8)
    On Error GoTo 0
    If Not oRangeSelected Is Nothing Then
        Set objRange = oRangeSelected.CurrentRegion
        objRange.Select

        Set colCharts = Charts
        colCharts.Add

        Set objChart = colCharts(1)
        objChart.Activate

        objChart.ChartType = 65

        objChart.PlotArea.Fill.PresetGradient 1, 1, 7

        objChart.SeriesCollection(1).Border.Weight = -4138
        objChart.SeriesCollection(2).Border.Weight = -4138
        objChart.SeriesCollection(3).Border.Weight = -4138

        objChart.SeriesCollection(1).Border.ColorIndex = 2
        objChart.SeriesCollection(1).MarkerBackgroundColorIndex = 2

        objChart.SeriesCollection(2).MarkerForegroundColorIndex = 1
        objChart.SeriesCollection(3).MarkerForegroundColorIndex = 1

        objChart.HasTitle = True
        objChart.ChartTitle.Text = "Title"
        objChart.ChartTitle.Font.Size = 18

        objChart.ChartArea.Fill.Visible = True
        objChart.ChartArea.Fill.PresetTextured 15

        objChart.ChartArea.Border.LineStyle = 1

        objChart.HasLegend = True
        objChart.Legend.Shadow = True

    Else
        MsgBox "It appears as if you pressed cancel!"
    End If

End Sub

 


Comment by: Mandeep Mehta (6/28/2011 7:18:56 AM)

How can I have totals calculated for all columns of a list object using vba?

 


Comment by: Jan Karel Pieterse (6/28/2011 11:59:54 PM)

Hi Mandeep,

The easiest way is to record a macro while you turn on the total row for a table and study the code:

ActiveSheet.ListObjects("Table1").ShowTotals = True


Some examples to change the function in the total row of one of the columns (column "q"):

ActiveSheet.ListObjects("Table1").ListColumns("q").TotalsCalculation = _
        xlTotalsCalculationAverage
    ActiveSheet.ListObjects("Table1").ListColumns("q").TotalsCalculation = _
        xlTotalsCalculationCount
    ActiveSheet.ListObjects("Table1").ListColumns("q").TotalsCalculation = _
        xlTotalsCalculationSum

 


Comment by: Ramakrishnan (6/30/2011 11:56:52 AM)

Hi, Am very new to VBA. i want to know how to apply the coding in vba excel and and how to run a macro for any coding. i have tried many times some codes in vba but am getting some errors while am run the macro. Please teach me how to proceed.

 


Comment by: Jan Karel Pieterse (7/4/2011 1:40:32 AM)

Hi Ramakrishnan,

I suggest to get a beginner book on VBA, such as one of the Dummies series: Excel 2007 VBA for Dummies by John Walkenbach for example.

 


Comment by: ddset (7/7/2011 2:34:48 AM)

Hi, I've been busting my head with one problem for some time already. The problem is that I have worksheet of data with multiple columns. In one column I have data that is different for each cell in the column and data has been inserted so that text is all in one line (e.g. no break lines). What I want is to insert break line in each row after let's say 40 characters.
Tried with strings, but just can't get it right. Is there some other way I haven't considered maybe? In any case, thanks :)

 


Comment by: Jan Karel Pieterse (7/7/2011 5:04:12 AM)

Hi ddset,

Put this code in a normal module in your file:

Public Function Wrap(Text As Variant, LineLength As Variant)
    Dim lCt As Long
    If LineLength >= Len(Text) Then
        Wrap = Text
    ElseIf Len(Text) > 0 Then
        For lCt = 1 To Int(Len(Text) / LineLength + 0.5)
            Wrap = Wrap & Mid(Text, (lCt - 1) * LineLength + 1, LineLength) & vbNewLine
        Next
        Wrap = Left(Wrap, Len(Wrap) - 1)
    End If
End Function

Then go to your sheet and split the content of cell A1 like so (formula to go in a separate column):
=WRAP(A1,40)
After copying down the formula, copy, paste-special value this formula to get static results.
Make sure you turn on wrap text on the relevant column's cell properties.

 


Comment by: John (7/11/2011 12:13:46 AM)

Hi
please i have an excel table, that includes phone numbers of staff, i have been able to record a macros that fliters each name by the location
however i am try to get a code that updates the list alphabetically and serially when i include a new staff in the table
please help
regards

 


Comment by: Jan Karel Pieterse (7/11/2011 12:26:37 AM)

Hi John,

I suggest you ask this question here:

http://www.eileenslounge.com

 


Comment by: Paul Godfrey (7/12/2011 4:02:17 AM)

Thanks for this page. Very useful info and well explained.
Unlike the macro recorder for 2007 tables your code works.
You have saved me a lot of time.

 


Comment by: Rob (7/30/2011 6:11:10 AM)

Hi Jan,
Interesting read! You mention in Selecting parts of tables

'select an entire column (data only)
     oSh.Range("Table1[Column2]").Select

'select an entire column (data plus header)
     oSh.Range("Table1[[#All],[Column1]]").Select

But how would you select TWO (or 3) columns in both of these examples? (e.g. Col D & Col E)I've tried various ways but keep getting in to errors. My fault entirely, I'm a bit of a noob when it comes to VBA. :)

 


Comment by: Charlie (8/3/2011 12:38:13 PM)

Jan,

Is there a way to "trap" if a User manually adds / deletes a row (or column) from a ListObject? When a row is added (for example in the last row of the table: right-click > Insert > Table Rows Below) manually, the Worksheet_Change event fires. How could I determine if the Change event was a result of the row being added?

 


Comment by: Per Inge (8/6/2011 8:09:51 AM)

Hi, and thanks for a very valuable article.

Do you have any overview of the notation where you refer to rows and columns using e.g. [Column1] instead of an index?

Example:
oSh.Range("Table1[[#All],[Column1]]").Select


Best regards Per Inge

 


Comment by: sam (8/12/2011 7:08:09 AM)

excellent page! quick question - how do we copy a column from 1 table to another table (empty) in a specific column

something like


wrksource.ListObjects(tablsource).ListColumns("column1").DataBodyRange.Copy Destination:=wrkdest.ListObjects(tabldest).ListColumns("column2").databodyrange

 


Comment by: AJ Henderson (8/18/2011 9:07:23 AM)

Hello,

I am working on appending information to and removing information from a table. Is there a way to set up the code so that when I'm appending I can fill in a form and it will automatically append it to a new row in the table? Also the same thing for removing data. I would like to fill out a similar form and have it remove the row for me.

Thanks in advance.

 


Comment by: Jan Karel Pieterse (8/22/2011 2:03:47 AM)

Hi AJ,

You might be helped with the old excel 2003 Data, Form functionality, which provides a basic data entry form?

From Excel 2007 and 2010 you can find the relevant function with the shortcut key alt + d, o. You can add the bottun to your QAT, the Form button is located in the "Commands not on the ribbon" category.

 


Comment by: Jan Karel Pieterse (8/22/2011 2:29:17 AM)

Hi Sam,

The trick is to first insert the column(s) in the target listobject and then do the copy:

Sub CopyAColumn()
    Dim oLo As ListObject
    Set oLo = ActiveSheet.ListObjects(2)
    With oLo.ListColumns.Item("e")
        .Range.Columns.Insert
        ActiveSheet.ListObjects(1).ListColumns("B").Range.Copy .Range.Offset(, -1).Cells(1, 1)
    End With
End Sub

 


Comment by: Jan Karel Pieterse (8/22/2011 2:46:07 AM)

Hi Per Inge,

The correct syntax is:

ActiveSheet.ListObjects(1).ListColumns("Column1")

 


Comment by: Jan Karel Pieterse (8/22/2011 2:52:01 AM)

Hi Charlie,

You would have to keep track of the dimensions of your table *before* the event fires and then when the event fires check if they have changed and act accordingly.

 


Comment by: Per Inge Sævareid (8/22/2011 2:52:48 AM)

Thanks Jan for your answer. I actually found an overview of "Referencing cells in a table (structured referencing)" in http://www.jkp-ads.com/Articles/Excel2007Tables.asp

Powerfull and elegant, thanks!

 


Comment by: Jan Karel Pieterse (8/22/2011 2:56:43 AM)

Hi Rob,

Regarding selecting multiple columns:

ActiveSheet.ListObjects(1).ListColumns("b").range.Resize(,2).select

 


Comment by: Sean (8/25/2011 12:49:15 PM)

Hi, great article!

I am looking for any resources on creating a join between an excel 2007 table and a database table.

For example, is it possible to query the account info from a SQL server table for a given set of account numbers in a range and return the result set to the excel spreadsheet?

 


Comment by: Jan Karel Pieterse (8/26/2011 5:13:18 AM)

Hi Sean,

I think your best bet is to create an empty Access database and use two linked tables to the SQL database and to the Excel file respectively and then create a query from there.
Excel cannot join tables from multiple sources.
Another option might be to use PowerPivot, but I have little to no experience with that.

 


Comment by: Markus (9/22/2011 7:47:22 AM)

Hi Jan!

Thank´s all for the helpful tips in this thread!

Im trying to use Jan's TableInsertingExamples above. I only want to insert one row at the end of the table.

Sub TableInsertingExamples()
'insert below
ActiveSheet.ListObject.ListRows.Add AlwaysInsert:=True
End Sub


I get this error message:
Object does not support this property or method

What can i do?
Regards,
Markus

 


Comment by: Jan Karel Pieterse (9/22/2011 7:51:14 AM)

Hi Markus,

The correct syntax is:

Worksheets("Sheet1").ListObjects("Table1").ListRows.Add AlwaysInsert:=true

Or:

ActiveCell.ListObject.ListRows.Add AlwaysInsert:=true

 


Comment by: Ayaz S. Zanzeria (10/9/2011 9:05:13 PM)

Hi,

In response to your comment,

Dim myTable As ListObject
Set myTable = ThisWorkbook.Worksheets("Sheet1").ListObjects("myTable")

For CurRow = myTable.DataBodyRange.Row To myTable.ListRows.Count

myVar = myTable[[#This Row], [Header1]]").Value
'do other stuff..

'The #This Row should obviously move to the next row for each iteration of CurRow
next

I tried this bit of code but it does not work. Please let me know what is missing.

I have a table and I want to extract the values using the header names and not the column indices.

 


Comment by: Jan Karel Pieterse (10/9/2011 11:58:14 PM)

Hi Ayaz,

Like this:

    For currow = 1 To myTable.ListRows.Count

        myvar = myTable.ListColumns("Header1").DataBodyRange.Rows(currow).Value
        'do other stuff..
    Next

 


Comment by: Dovy Reiner (10/19/2011 9:38:30 AM)

Pass Column Header in Table as Argument?

I use vba to sort a table, each time on different column.
I would like to have one generic Sort procedure, and pass the column header as argument.
All my attempts failed and I had to resort to writing specific proceduure for each and every column (ugly).

MS says: "... Because column headers are text strings, you cannot use expressions within brackets..."
http://office.microsoft.com/en-us/excel-help/using-structured-references-with-excel-tables-HA010155686.aspx

Is there a workaround?

 


Comment by: Jan Karel Pieterse (10/19/2011 11:26:11 PM)

Hi Dovy,

Not sure what your problem is, but this appears to work:


Sub SortList(sColumnName As String, oLo As ListObject)
    oLo.Range.Sort key1:=oLo.ListColumns(sColumnName).Range, order1:=xlAscending, Header:=xlYes
End Sub

Sub Demo()
    SortList "a", ActiveSheet.ListObjects(1)
    SortList "b", ActiveSheet.ListObjects(1)
End Sub

 


Comment by: Dovy Reiner (10/24/2011 12:51:43 PM)

Jan,

My problem was that I insisted on using the new structured reference and forgot about the old and simple style.

At the end, I was able to get it right like this:


Sub SortManager(sHeader1 As String, Optional sHeader2 As String)
With ThisWorkbook.Worksheets("MData").ListObjects("tblMain").Sort
    .SortFields.Clear
    .SortFields.Add Key:=Range("tblMain[" & sHeader1 & "]"), SortOn:=xlSortOnValues, _
                    Order:=xlAscending, DataOption:=xlSortNormal
                    
    If sHeader2 <> "" Then
     .SortFields.Add Key:=Range("tblMain[" & sHeader2 & "]"), SortOn:=xlSortOnValues, _
                     Order:=xlAscending, DataOption:=xlSortNormal
    End If

    .Header = xlYes
    .MatchCase = False
    .Orientation = xlTopToBottom
    .Apply
End With
End Sub


Dovy

 


Comment by: Merv Gleeson (10/26/2011 12:49:32 PM)

Hi Jan

I'M new to all this, so can you help me with a small problem
please?

Example

Wk/Sheet 1 Table col 1
A    
B
C
D
E
F
G
H
I
J
K

I need to have a script to produce another wk/sheet where by it picks out every 3rd row ie
A
D
G
J etc

Does that make any sence ?

Merv

 


Comment by: Jan Karel Pieterse (10/27/2011 2:00:21 AM)

Hi Merv,

This formula will do the trick, provided you start on row 1:

=OFFSET(Sheet1!$A$1,(ROW()-1)*3,0,1,1)

 


Comment by: jay (10/27/2011 6:24:58 AM)

Hi, I have bunch of excel files (.xls or .xlsb) which i am looking to convert to pdf files with the same file name as those given to the excel files. I am looking for a vba macro and am somewhat familiar but no where near an expert. I believe we have ADOBE Acrobad 9 standard. So I have the option of goin to the excel file and printing a pdf..

I need the macro to go to individual files in a folder on my desktop and print pdf out of them and then save them automatically in another folder on desktop with the same file name as orginally assigned to as an excel file. Please HELP good sir..

 


Comment by: Jan Karel Pieterse (10/27/2011 8:17:59 AM)

Hi Jay,

Please visit http://www.eileenslounge.com for a swift answer to your question!

 


Comment by: Shafqat (11/4/2011 1:05:51 AM)

excellant work

 


Comment by: Amado (11/19/2011 5:38:05 AM)

ok, you show how to select rows, columns, etc... but how I could select only one element of the table, for example, in row 3, column 5 ?

Sorry if it's a begginer question !!

Tanks a lot, excellent article.

 


Comment by: Jan Karel Pieterse (11/20/2011 10:53:20 PM)

Hi Amado,

The third row in the list column with a title of "b" can be found like so:

ActiveSheet.ListObjects(1).ListColumns("b").DataBodyRange.Cells(3, 1)

 


Comment by: Jen (11/22/2011 7:25:02 AM)

Hi,
I'm working on a macro to find and replace the content of several columns in a table. Is there a way to adapt the line:
oSh.Range("Table1[Column2]").Select

to work for a range of columns, excluding the headings.

Thanks very much!

 


Comment by: Jan Karel Pieterse (11/22/2011 7:50:47 AM)

Hi Jen,

Something like this should do it:

oSh.range(oSh.range("table1[column1]"),oSh.range("table1[column3]"))

 


Comment by: Klaus (11/22/2011 9:53:50 AM)

Hi,

just wondering if anyone knows how to create UDFs that can read/write whole columns of an Excel 2007 table by passing them as arrays?

 


Comment by: Jan Karel Pieterse (11/22/2011 10:09:06 AM)

Hi Klaus,

You can have the UDF return an array, enter the UDF as an array formula into a range of cells. Or have I misunderstood the question?

 


Comment by: William Thornton (12/2/2011 1:04:45 PM)

Good day,

I am trying to find basic code to get vba to index a table, so I can use a macro to index the same table for dif cells. My example is as follows. In cells D6, D7 etc. I have a value 1 0r 3. In cells F6, F7..... I have a value that matches a cable size. My table has a row with all the cable sizes and two columns, one with a 1, and one with a 3. after accessing the two values I want to return a value that corresponds to the matching cell. Once I have the value I can use it in a equation. I'm pretty sure I can figure out the for or do loop structure to go thru a table from top to bottom but I have been unable to locate code that imulates the Index function in excel. Any Help is appreciated.

Thanks, Will

 


Comment by: Jan Karel Pieterse (12/5/2011 1:34:45 AM)

Hi William,

The simplest way is to add a calculated column in the lookup table which combines the two columns, using a delimiter which isn't in the data, like the pipe character (above the backslash): =A2&"|"&B2

Then use something like this to look up the data (note you have to point to the proper locations, which will fill in the proer table references in the formula below):

=INDEX(Tablereference,MATCH(COl1 & "|" & Col2,OtherTableNewColumn,0))

 


Comment by: Pavlinka (12/6/2011 7:58:27 AM)

Hello

On my active spreadsheet I have a table called Table1.
In my macro, I am writing the formulas that are used to populate certain columns of the table.
in these formuas, elements from other columns appears, but I don't know how to get them.

If for instance I want to get the value in the table at the same row, but in the column called "Np", coult I say something like:

ActiveSheet.ListObject(Table1).ListColumns("Np")DataBodyRange.Cells([[#This Row],[Np]])

???

thanks!

 


Comment by: Jan Karel Pieterse (12/6/2011 8:28:36 AM)

Hi Pavlinka,

I'm not sure what your question is.

You say you're writing formulas, but I suspect you meant to say you need the VBA syntax to get a value from the current row in a specific column inside a table.

Am I right?

Maybe you can try to explain what your macro does/should do?

 


Comment by: Alan (12/11/2011 11:03:59 PM)

First off, great page! I have learned a great deal on working with tables in 07 and 10. I am working on a project that has multiple worksheets with one worksheet containing a "base" table called "ROSTER" being filled with constants. All the other worksheets contain tables that pull info from parts of the base table. I wanted different users to be able to update certain things on their related table and record the information on the base table and then show updated data in the users range by inserting a lookup formula that reflects the constant inserted into the base table. I have worked out most of this but have run into a few hang ups and have been beating my head against the wall. I will post Question in next post due to limit of 2000 charterers.
This is the code I use on a worksheet change event:
Private Sub Worksheet_Change(ByVal Target As Range)
    Application.EnableEvents = False
    Worksheet.Unprotect "password"
    Dim myValue As String
    Dim myRange As String
    Dim myID As Integer
    Dim myRow As Integer
    Dim myColumn As Integer
    Dim myColumnName As String
    Dim myTargetColumn As Integer
    Dim myFormula As String
    myValue = Target.Value
    myRange = Target.Address(RowAbsolute:=False)
    endRange = ActiveCell.Address
    myColumn = Range(myRange).Column
    myRow = Range(myRange).Row
    myID = Cells(myRow, 1) ' first column is a unique numbered ref for each row.
    myColumnName = Cells(2, myColumn) '2 is my header row
    myFormula = Cells(myRow + 1, myColumn).Formula ' gets formula for row below target
    myTargetColumn = Application.Match(myColumnName, Worksheets("ROSTER").Rows(2), 1)
    Worksheets("ROSTER").Range(Worksheets("ROSTER").Cells(myID, myTargetColumn).Address()).Value
= myValue
    Range(myRange).Formula = myFormula
    Worksheet.Protect "password", True, True, AllowSorting:=True, AllowFiltering:=True
    Application.EnableEvents = True
End Sub

 


Comment by: Alan (12/11/2011 11:04:19 PM)

The previous code seems to work but I am having a sorting issue which I would like to allow users the ability to sort but there seems to be an issue sorting a protected table. Short of inserting Form controls over the current controls for sorting, I am at my wits end. I can't unprotect the sheet for the user because there are cells that I don't want edited. So my approach was to Trap their input into the default control, set in variables, and perform the sort through VBA. It is just a matter of catching the values of the users sort input which I can't seem to figure out. (Most important)
The next project will be allowing users to insert columns into their prospective worksheets and name it, once named, create a new column in the base table and name the column with the same name so my lookup formulas work and apply those formulas to the column the user created. As it is now Users must ask me to sort the data when they need it in different formats and add columns for them.
It would be nice to do it through VBA, Any help would be greatly appreciated and any suggestions on the code already developed would be equally welcomed.

I hope I have explained myself well enough, Thanks for any input!

 


Comment by: Jan Karel Pieterse (12/11/2011 11:08:32 PM)

Hi Alan,

I see no problem with using VBA to do the sort where you start out by unprotecting the sheet, then doing the sort and finally protecting the sheet again.
Recoridng a macro when doing a manual sort whould give you a head start on the code.

 


Comment by: Asher Rodriguez (12/16/2011 12:47:35 PM)

Hello JKP,

Regarding this section: "Special stuff: Sorting and filtering"

I see how you can call out a sort range by table and column name now ex: "Sort.SortFields.Add( _
                Range("Table1[[#All],[Column2]]")"

I am trying to figure out how to do that with the Autofilter. My problem is that if I use the column number for the "Field:=2" argument, then if someone inserta a column into the table, the macro will give me the wrong information.

But if in 2007 there is a way to call out the Field argument (range) by the table and column name, it would always look for the name and not the number so I will get the correct data no matter what columns are added (or removed).

Please let me know if this is possible.

Thanks for your time,

Asher

 


Comment by: Jan Karel Pieterse (12/18/2011 11:08:57 PM)

Hi Asher,

You would have to "sort out" the columns number prior to setting up the filter, something like:

    Dim oLo As ListObject
    Dim lCol as Long
    Set oLo = ActiveCell.ListObject
    lCol = oLo.ListColumns("Column2").DataBodyRange.Column - oLo.DataBodyRange.Cells(1, 1).Column + 1

 


Comment by: Asher Rodriguez (12/23/2011 11:42:34 AM)

How do Select the first cell in the first column in the first row of a listObject (not headers)?

 


Comment by: Bill (12/27/2011 10:18:52 PM)

Hi Jan,

I am working on a macro that clears the data within a table that has been created. My purpose in doing so is to be able to repopulate the table later on. I find this useful because i have another table that has formulas linking to this one. The problem i am having is that once the table has no data, i seem to get an error preventing me from repopulating the table. Do you know why this is occurring and have any suggestions to fix this problem? I found this page to be invaluable. Thanks for your help!

Bill

 


Comment by: Jan Karel Pieterse (12/29/2011 7:11:01 AM)

Hi Asher,

ActiveSheet.ListObjects(1).DataBodyRange.Cells(1,1)

 


Comment by: Jan Karel Pieterse (12/29/2011 7:12:26 AM)

Hi Bill,

Which error do you get and can you show the relevant bit of code please?

 


Comment by: Asher Rodriguez (1/10/2012 1:52:19 PM)

Hi JKP,

I am implementing the code bundle you gave me before above "You would have to "sort out" the columns number prior to setting up the filter, something like:

    Dim oLo As ListObject
    Dim lCol as Long
    Set oLo = ActiveCell.ListObject
    lCol = oLo.ListColumns("Column2").DataBodyRange.Column - oLo.DataBodyRange.Cells(1, 1).Column + 1 "

and I have a question.

It looks like this part: "lCol = oLo.ListColumns("Column2").DataBodyRange.Column" gives me the column number I need for the filter, so, what is this part: "- oLo.DataBodyRange.Cells(1, 1).Column + 1 " for? Is it necessary in some way that I am not figuring out?

Thanks for your time,

Asher

 


Comment by: Jan Karel Pieterse (1/11/2012 4:41:52 AM)

Hi Asher,

The column number autofilter needs is counted from the top-left cell of the table you're autofiltering, whereas the Column property returns the column index number counting from column A (=col. 1) of the sheet. This is why I subtract the column number of the top-left cell of the table from the found column number and add 1.

 


Comment by: Asher Rodriguez (1/11/2012 6:35:49 AM)

Oh I see. The reason it seems redundant in my code is because my table just happens to start at A1 (so to me it looked like it was subtracting 1 then adding 1).

But if my table started anywhere else in the sheet, the code would give a wrong index for the filter without that last portion. That's important to know.

Thanks for explaining!

 


Comment by: Wyeth (1/13/2012 2:33:03 PM)

I am trying to name a table created withing a macro and getting an error. Debugger is telling me the following text is the issue.

ActiveSheet.ListObjects("BinderL").Name = "BinderLog"


I am VBA illiterate (pretty much) but have been able to stumble may way through some basics. Hope you can help. Thanks!

 


Comment by: Jan Karel Pieterse (1/15/2012 11:12:57 AM)

What error do you get? Maybe the activesheet doesn't have alistobject by the name of BinderL, or alternatively it already has a listobject named "BinderLog"

 


Comment by: Craig (1/26/2012 10:09:26 AM)

I'm trying to delete rows in my table where a certain field has a specific value. Can you show me some sample code for that?
thanks! -Craig

 


Comment by: Deepak kumar (2/6/2012 9:53:42 AM)

I want to connect excel data base file to vba user form on click commond button and store the vba text data to excel file.

 


Comment by: Jan Karel Pieterse (2/8/2012 2:35:17 AM)

Hi Deepak,

Please ask your question at:

http://www.eileenslounge.com/

 


Comment by: David (2/10/2012 6:31:43 AM)

Is it possible to use ADODB connections to work with the data in an excel 2007 table using SQL?

I.e. I'd like to insert a table via the insert->table menu then in vba be able to access rows or cells from the table by writing sql.

E.g. "select column2 from Table1 where column1 = 150"

I know I should probably use an access database for things like this but I'm curious if it can work anyway.

 


Comment by: john coyne (2/21/2012 11:12:52 AM)

how do i loop through the rows in a table once selected - here's essentially what i want to do:


For Each oLo In oSh.ListObjects
    For Each Row In oLo
        MsgBox oLo.Name & "row: " & this.rownumber
    Next
Next

 


Comment by: Jan Karel Pieterse (2/23/2012 3:04:20 AM)

Hi John,

You could use

Dim oRow as Range
For Each oRow in ActiveCell.ListObject.DataBodyRange.Rows
    MsgBox oRow.Address
Next

 


Comment by: Patrick (2/23/2012 9:00:01 AM)

The code for sorting a table based on the contents of a specifici column works fine:


.Sort.SortFields.Add(Range("Table1[[#All],[Column2]]"),xlSortOnCellColor, xlAscending, , xlSortNormal).SortOnValue.Color = RGB(255, 235, 156)
.

but what if I need a routine in which I can dynamically change that column?

Say, I want to change [Column2] by whatever column was selected through a combobox on a userform.

I just can't get the required syntax right and always get a run-time error.


Sub Sort_By_Column(Col_Name As String, Sort_Order As Long)
    ActiveWorkbook.Worksheets("TaakDB").ListObjects("Table3").Sort.SortFields.Clear
    ActiveWorkbook.Worksheets("TaakDB").ListObjects("Table3").Sort.SortFields.Add _
        Key:=Range("Table3[[#All],[Col_Name]]"), SortOn:=xlSortOnValues, Order:= _
        xlAscending, DataOption:=xlSortNormal
    
        With ActiveWorkbook.Worksheets("TaakDB").ListObjects("Table3").Sort
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
End Sub
.

 


Comment by: Jan Karel Pieterse (2/24/2012 7:57:13 AM)

Hi Patrick,

The key is with this part of your code I expect:

... Key:=Range("Table3[[#All],[Col_Name]]"), ...

Suppose the name of the column is in a variable names sColName, then change the piece above to:

... Key:=Range("Table3[[#All],[" & sColName & "]]"), ...

 


Comment by: Patrick (2/27/2012 1:52:57 AM)

Thanks Jan Karel,

It's working now! :-)

 


Comment by: John (3/10/2012 10:31:01 PM)

New to VBA in excel, understand the context, have a table macro that auto sorts when a value of a cell is changed according to an input reference. ie. value of "AWP,FMC" etc. All values change and auto sort except the first row (8). One site referenced changing .Header = xlYes to xlNo. Same problem exist. I have been looking for a reference to .Header objects for an explenation but get more "add a picture to a header, change a header" reference on the "Internut". (1) is there a reference book or sheet for each line object(tag) for reference so I can understand what I am looking at as termenology goes (2) a .Header would tell me that there is a header in the table and should not be used in value of (H8:H23). If I am wrong please advise.

Thank you for your time

 


Comment by: Jan Karel Pieterse (3/12/2012 12:59:10 AM)

Hi John,

Can you perhaps post the relevant part of your VBA code?

 


Comment by: Arretta (3/14/2012 9:23:21 AM)

I have a dataTable in Excel 2007 that contains columns A-P that are entered via a UserForm which works perfectly. There are formulas in columns Q through KO (285 columns, wow). So far so good.

Steps my user goes through:
Step 1) Enter the data via UserForm starting on row 2 of the dataTable
Step 2) Generate Reports, Graphs, Etc. for this project
Step 3) Saves the data only (columns A-P) to an external file (which can be imported later if need be)
Step 4) Clears dataTable to start new project

Steps 1 through 3 are working fine, it is step 4 that is causing the problem. When I clear the data in the table I leave row 1 intact so it keeps the formulas in columns Q-KO. This works if I do it manually but when I do it with this macro, the next time they add data the formulas don't continue down. I am beginning in the 2nd row of the dataTable, could that be the problem? Also, I am using EntireRow.Delete for rows 2 to the end because there could be 500 or so rows of data.

Your help is greatly appreciated.


Sub ResetData()
    Application.ScreenUpdating = False
    ActiveSheet.DisplayPageBreaks = False

    Sheets("Main Menu").Select
    Sheets("data").Visible = True
    Sheets("DATA").Select
    ActiveSheet.Cells.EntireColumn.Hidden = False
    ActiveSheet.Cells.EntireRow.Hidden = False
    Range("A7").Select

    Range("dataTable[[plot]:[vc3]]").Select
    Range(Selection, Selection.End(xlDown)).Select
    Selection.EntireRow.Delete 'ClearContents

'I tried this but then the formulas are gone completely
'    Range("dataTable").Offset(1).SpecialCells(xlCellTypeConstants).ClearContents

    Range("dataTable[[L1length]:[Form Class]]").Select
    Selection.EntireColumn.Hidden = True
    Range("A6").Select
    Sheets("data").Visible = False

    Application.ScreenUpdating = True
End Sub

 


Comment by: Bjørnar (3/14/2012 8:24:53 PM)

Hi.

At work we use an excel sheet to keep track of inventory in our storage. I have created a few macros to help us with this, but I see now I'm not completely there. I have made a button that copies the latest storage layout with inventory and sums it up. The problem is that when copying to a new sheet, a table I have gets a new name, and the macro does not work, because it is set to work with "Table1".

I guess the solution is in the chapter "Listing the tables". I get that to work fine, but I am clueless how to actually get the macro to use the table name it comes up with. I only have one table for each active sheet.

The code in the "Listing the tables" - chapter returns for example "Table148773". (Seems it adds a number every time, instead of just going from 1 to 2 to 3 etc). So what I need is to put the "TableXXXXX" it returns into this code, instead of Table1:

Range("Table1[[#Headers],[Product]]).Select
ActiveSheet.ListObjects("Table1").sort.SortFields.Clear
-------- more code
Key:=Range("Table1[Product]"), SortOn:= etc....


This will then sort the products alphabetically.

Most of this is stuff I have recorded, but I did not think about the fact that the Table gets a new name for each sheet.

I've seen in the name manager, that the header Product exists for all the tables, so that one is being copied.

I've searched for hours now, and I never got further than getting to read the table number.

I'd appreciate any help you can give me.

 


Comment by: Jan Karel Pieterse (3/15/2012 2:38:26 AM)

Hi Arretta,

Have you tried to replace:

Selection.EntireRow.Delete 'ClearContents

with:

Selection.Delete Shift:=xlUp

 


Comment by: Jan Karel Pieterse (3/15/2012 2:45:20 AM)

Hi Bjørnar,

This seems to do the same and always uses the first table on the active sheet, regardless of its name:

Dim oLo As ListObject
Set oLo = ActiveSheet.ListObjects(1)
oLo.ListColumns("Product").Range.Rows(1).Select
oLo.Sort.SortFields.Clear

 


Comment by: Bjørnar (3/15/2012 12:05:59 PM)

This did the trick! Thanks a million!

 


Comment by: Silke (4/3/2012 8:59:07 AM)

Hello,

I would like to know how I add rows with data to an existing table.
In the example I copy data from two tables ("JDE" and "WISE") into one table ("upload").
So far I have this:


Sheets("JDE").Select
Range("JDE[QTY],JDE[SALES]").Select
Selection.Copy
Sheets("upload").Select
Range("upload[[#Headers],[IDINAD]]").Select
Selection.End(xlDown).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False


My problem is that every time I copy and paste the second table (doesnt matter which one it is) the last column is overwritten. Which makes sense as xldown finds exactly that last row.

I have tried to solve the whole thing with 'offset' but then the data are pasted but not part of the table.

The code might look a wee bit odd due to the fact that I am a beginner with VBA so lots of google, forums, books, recording macros copy & paste...

Thank you so much for your help.

S.

 


Comment by: Jan Karel Pieterse (4/3/2012 10:30:19 PM)

Hi Silke,

You could do it like this:
'...Part of your code up to:
Selection.Copy
Worksheets("upload").Activate
With Worksheets("upload").ListObjects("upload")
.DataBodyRange.Row(.DataBodyRange.Rows.Count).Select
End With
ActiveSheet.Paste Selection.Offset(1)

 


Comment by: Al (4/6/2012 9:09:43 PM)

I am adding multiple records from an invoice form to another worksheet that holds all of the order lines of the all invoices. Even though the records are added to the bottom of the table6 they do not seem to be part of the table structure. Any formulas that are part of table6 are not implemented in the new records.

I'm not sure how to us the ListObjects object to add these records to the table. Data is added to cells A through AD in the new record, but I need to bring down the formulas from columns AK through AO, that allows me to automatically extract data to another worksheet if there is unique data in the new record, for example new customer name.

Also is there a simple way to refresh a pivot table that uses this table6 as its data source after the new records are added? Right now I just copied a macro that did the refresh.

Sub MoveRecord()

    Dim Increment As Integer 'looping variable
    Dim WSF As Worksheet ' Invoice worksheet Dim WSD As Worksheet ' SalesData worksheet
    Set WSF = Worksheets("Invoice")
    Set WSD = Worksheets("SalesData")
    NextRow = WSD.Cells(Rows.Count, 2).End(xlUp).Row + 1 ' (Rows.Count, 2), the 2 says which column number to check if blank
For Increment = 19 To 34                
    If WSF.Cells(Increment, 3) <> "" Then
    
    WSD.Cells(NextRow, 1).Resize(1, 31).Value = Array([D4], [F4], [P4], [C16], [F3], [A16], [B16], [c9], _
    Cells(Increment, 3), Cells(Increment, 4), Cells(Increment, 6), Cells(Increment, 7), Cells(Increment, 12), Cells(Increment, 2), Cells(Increment, 13), Cells(Increment, 8), Cells(Increment, 14), [D3], [D3], [D3], [D3], Cells(Increment, 15), Cells(Increment, 16), Cells(Increment, 17), Cells(Increment, 18), Cells(Increment, 19), [D3], [C8], [C13], [F6], [F16])
    
NextRow = WSD.Cells(Rows.Count, 2).End(xlUp).Row + 1

    End If
    
Next Increment

RefreshSalesData

End Sub



Thanks

 


Comment by: Jan Karel Pieterse (4/9/2012 10:11:18 AM)

Hi,

This adds a new row below a table AND expands the table:

With Worksheets(1).ListObjects(1)
.DataBodyRange.Row(.DataBodyRange.Rows.Count + 1 ).Value = "New Row"
End With

 


Comment by: AlexJ (4/13/2012 10:57:58 AM)

Jan Karel,
Do you know if it is possible to create events for ListObjects in Excel 2010? If so, do you have an example?

 


Comment by: Jan Karel Pieterse (4/15/2012 10:05:09 PM)

Hi Alex,

No, there are no specific ListObject events as far as I know. You'll have to use the standard worksheet events.

 


Comment by: Chris (4/19/2012 4:10:39 PM)

To AlexJ,

A good question and something i am currently looking at developing for our team.

Expanding on Jan Karel's response:

An idea might be to;

1. Use the worksheet cell 'change' or 'calculate' event to create a catch for changing cells.

2. Using a simple function that includes the VBA "Intersect" method you could test if the changed cell falls within the ObjectList.Range of your table.

EG.
'### Worksheet Change Event Capturing Cell
Private Sub Worksheet_Change(ByVal Target As Range)
Dim ActCell As Range
Dim ActSheet As WorkSheet

Set ActSheet = ActiveSheet

Set ActCell = Target

Call IsInTable(ActCell,ActSheet)

End Sub

Function IsInTable(ActCell As Range, ActSheet As WorkSheet) As Boolean

Dim ObjLists As ListObjects
Dim ObjList As ListObject
Dim IsectRange As Range

Set ObjLists = ActSheet.ListObjects
IsInTable = False

For Each ObjList in ObjLists
Set IsectRange = Application.Intersect(ObjList.Range,ActCell)
If Not ISectRange Is Nothing Then
IsInTable = True
MsgBox "Cell found to be part of..." & Objlist.Name
Exit For
End If
Next ObjList

End Function


End Function

#### Warning #### may be mistakes above as i wrote this in a hurry and without testing. Hopefully it helps with ideas though.

Kind Regards.

 


Comment by: Jan Karel Pieterse (4/20/2012 2:55:35 AM)

Hi Chris,

Your function can be simplified:

Function IsInTable(oRng As Range) As Boolean
    Dim oLo As ListObject
    On Error Resume Next
    Set oLo = oRng.Cells(1, 1).ListObject
    IsInTable = (Err.Number = 0) And Not oLo Is Nothing
End Function

 


Comment by: Osian Jones (4/20/2012 8:17:00 AM)

Hi,

I'm having trouble trying to refer to data contained within Excel tables through a VLOOKUP formula in VBA.

My code never seems to be able to locate the Excel tables in my workbook even though I know their names are correct.

It always returns an Error 1004 which means it can't find the table. They are on a different worksheet so perhaps that may be the problem, in which case I don't know how to diplay this.

I'm querying multiple tables in a loop so it needs to vary the table name (FK_Header) within the VLOOKUP formula as shown:


For i = 1 To lookup_col_count - 1
    
        Lookup_col = 1 + i
        
        For r = 1 To cckdpt_row_count
    
        Cells(1 + r, Last_Column + (FK * i)).Select
        ActiveCell.FormulaR1C1 = _
        "=VLOOKUP([@" & FK_Header & "],Table_" & FK_Header & "_1," & Lookup_col & ",0)"
        
        Next r

    Next i


Any suggestions on how this works?

Thanks
Osian

 


Comment by: Ito (4/23/2012 4:43:56 PM)

I am trying to assign only the filtered (visible cells) of a table to an array based on your example. I used the following code :

Dim oDataTable() as Variant

oDataTable = oSheet.ListObjects(sDataTable).Range.SpecialCells(xlCellTypeVisible).Value


I am getting up to the part where I have no hidden rows. My array size (1 to 31, 1 to 24) is up to the un-hidden rows ( i.e. rows 1 to 31 are not hidden but 32 to 34 are but 35 is not and so on.

Any help would really be appreciated

thx




 


Comment by: Jan Karel Pieterse (4/23/2012 11:25:24 PM)

Hi Osian,

Does the formula get entered into the cell?
If so, is the formula correct?
One way to get the proper formula in VBA is to first enter a working formula in Excel. Then (with that cell active) go to the VBA editor, hit control+g and enter:

?Activecell.formula

and hit enter at the end.

Any quotes within the formula must be doubled-up:

=IF(A1="test","Yes","No")

becomes:

=ActiveCell.Formula = "=IF(A1=""test"",""Yes"",""No"")"

 


Comment by: Jan Karel Pieterse (4/23/2012 11:26:36 PM)

Hi Ito,

You cannot assign filtered cells to a variant array, all values will be pushed into the array. This is "by design".

One way is to filter the array after it has been sent to VBA using array looping.

 


Comment by: Ito (4/24/2012 9:27:48 AM)

Thank you for your prompt reply.
Is there a way to assign the non contiguous cells (from the table) to the arrray without having to loop through all the visible cells. By looping through the areas and assigning them to the array.

From what I unerstand assigning a range to an array is more
set Array = Range ...Value

efficient then loopping throug the cells, then assigning them one by one to the array.

Thx Again for ur help

 


Comment by: Jan Karel Pieterse (4/25/2012 1:03:40 AM)

Hi Ito,

No, you simply cannot do that efficiently. The only way is to either pull in the entire range and filter in VBA, or to loop through the visible areas and fill arrays from there.

 


Comment by: venugopal (4/30/2012 6:03:55 AM)

how do i locate a particular value in a table of numbers

 


Comment by: Jan Karel Pieterse (5/1/2012 4:47:31 AM)

Hi Venugopal,

Use the Find option perhaps? (Control+F)

 


Comment by: Venugopal (5/6/2012 8:18:55 PM)

Thanks for the help Jan KP

 


Comment by: AM (5/7/2012 11:10:48 PM)

Hi,

I used your creating a table example just as a test.
I now do not know how to get rid the effects of running it on my worksheet.
I know this is a pretty silly situation, but could you please help me with how to 'undo' it?

Thanks!

 


Comment by: Jan Karel Pieterse (5/8/2012 2:04:38 AM)

Hi AM,

You can convert a table back to a range.

Select any cell in the table

Press the Table Tools, Design tab item on the ribbon.

On the left-hand side of the ribbon it says "Convert to range". Press that button.

 


Comment by: Am (5/8/2012 5:01:56 PM)

Thanks!

 


Comment by: Simon (5/31/2012 1:21:26 PM)

Hi,
I have a table that I get from a sharepoint site that I am automating the creation of Pivot tables. Before I do that I would like to delete some of the rows based on criteria. In order to keep it as dynamic as possible I would like to automate the deletion based on the criteria and the column title rather than the position of the column. Is there a simple way of doing that?

 


Comment by: Jan Karel Pieterse (5/31/2012 2:08:47 PM)

Hi Simon,

I don't have a Sharepoint environment to test, but can't you specify criteria when pulling in the sharepoint list?

 


Comment by: Simon (5/31/2012 2:44:13 PM)

Hi Jan,
The way that I have handled that is by customising the sharepoint view with filters, unfortunately sharepoint has an inbuilt limit of 10 filters per view, and this is the 11th criteria. The code to import only pulls the data table in and doesn't manipulate it. Using your examples and explanations above it would be simple enough for me to do it based on the column number, but I was hoping to avoid that and treat it as any excel table regardless of where it comes from?


ActiveSheet.ListObjects.Add SourceType:=xlSrcExternal, _
    Source:=Array("URL string", "{LISTNAME string}", _
    "{VIEWNAME string}"), LinkSource:=False, Destination:=Range("A1")

 


Comment by: Jan Karel Pieterse (5/31/2012 3:01:11 PM)

Hi Simon,

One thing you could do is -after refreshing the sharepoint list in Excel- save the file. Then base your pivot table on an external data source, use Excel as the data source and point it to the same excel file. Then you can use the query wizard to specify criteria.

 


Comment by: Simon (5/31/2012 3:26:47 PM)

Thank you Jan, I will have a go!

 


Comment by: Gary (6/15/2012 6:12:58 PM)

Thank you so much for all of this information! I am working with a list/table in excel 2007 that has mapped XML elements to retrieve data from an XML file.
I have noticed on initial load, when sending data to this list, it is extremely slow - but if I remove/or convert the list/table to a range, it is MUCH faster - but then I lose all of my mappings. Is there a way to "deactivate" the list or "hide" and can then reactivate it after the data initially comes across?
or, is there a way to create the XML map within VBA?
Thanks!

 


Comment by: Jan Karel Pieterse (6/18/2012 6:53:59 AM)

Hi Gary,

If there is a lot to add to the list, one way to speed things up is by first gathering everything that needs to go into the list on a separate location. Then when all rows are ready to go, copy them in one go below the list.

 


Comment by: George Spaniak (6/19/2012 5:50:33 PM)

Dear Jan,

I just wanted to thank you for your wonderful website. I am an amateur vba coder who spends a great deal of time on google trying to figure out solutions to my coding problems. Of all the excel help sites on the internet, I find myself coming back to yours by far the most. I wanted to thank you for both creating this site and sharing your knowledge. It has helped me a great deal and is greatly appreciated.

Sincerely,

George Spaniak

 


Comment by: Jan Karel Pieterse (6/19/2012 6:13:03 PM)

Hi George,

You're welcome!

 


Comment by: Gary (6/22/2012 4:17:11 PM)

Thank you very much for the reply!

Unfortunately, I am already bringing the data from SQL db to a separate sheet, then sending it over to the other page, which contains the list/table. I am stuck as I need the list as it contains the mapping to the XML elements, but it is also the sole cause (to my knowledge) of the slow down on load...

Is it possible to disable/re-enable a list/table? can the mapping be recreated in VBA, or can mappings only be created manually?

Thanks again!

 


Comment by: Henri Kayali (6/24/2012 10:46:15 AM)

Hello Jan,

Again with tables.Thanks for all your help.

When inserting a table, Excel guesses automatically the data range.

I was wondering if you knew of some way in VBA to get this "guessed" range without necessarily having to insert the table.

Thanks a lot.

 


Comment by: Jan Karel Pieterse (6/25/2012 7:04:13 AM)

Hi Henri,

That would be the Worksheets("Sheet1").CurrentRegion property.

 


Comment by: Jan Karel Pieterse (6/25/2012 7:37:59 AM)

Hi Gary,

Yes you can programmatically add mappings. Perhaps you can find the information you need here (Look for page 99 to start):

http://books.google.nl/books?id=gtPQMxO8XuoC&printsec=frontcover&dq=cXML+pro+excel+2007+VBA&hl=nl&sa=X&ei=JfjnT9SLK-PE0QWu3fGfCQ&ved=0CD4Q6AEwAA#v=onepage&q&f=false

 


Comment by: Shagun Ajmera (6/29/2012 12:01:47 PM)

can you tell me how to select the n'th cell in i'th column in a table

 


Comment by: Jan Karel Pieterse (6/29/2012 2:38:20 PM)

Hi Shagun,

Untested:
ActiveSheet.ListObjects(1).ListColumns(i).Cells(n,1)

 


Comment by: R C Cox (7/28/2012 4:55:59 PM)

Thanks for the introduction to coding Tables.

Reading the comments I think you have a typo in one answer. CurrentRegion needs a cell reference as well as the sheet.

 


Comment by: Jan Karel Pieterse (8/7/2012 11:27:42 AM)

Hi R C,

You are right of course!

Worksheets("Sheet1").RAnge("A1").CurrentRegion

 


Comment by: Simon Knapper (8/30/2012 11:36:03 AM)

Hello Jan
I found your article very informative and useful.
My question concerns the use of tables as a datasource in an ADO recordset.
Currently I use named ranges which works OK e.g.
myRecordset.Open "SELECT * FROM myNamedRange", myAdoConnection


but if I use a table
myRecordset.Open "SELECT * FROM myTable", myAdoConnection

It doesn't. Is it possible to use tables in this way?
Simon

 


Comment by: Jan Karel Pieterse (8/30/2012 12:58:44 PM)

Hi Simon,

Unfortunately, you cannot use Excel Tables in ADO directly. However, if you create a "normal" range name which points to the table, you can use the normal range name.
Benefit: the range name will expand and contract with the size of the table.

 


Comment by: Tom Groszko (9/2/2012 7:16:30 PM)

This page has helped me quite a bit, I am very new to VBA but an experienced developer. Your first example does not work if the table has no data. How do I test for the absense of data in a table? Likely obvious and simple but I am having trouble figuring this out.

Thanks

 


Comment by: Tom Groszko (9/2/2012 7:18:55 PM)

that should have been the second example not the first, sorry about that.

Thanks

 


Comment by: Jan Karel Pieterse (9/3/2012 9:37:10 AM)

Hi Tom,

One way could be by testing for the number of listrows:

If ActiveSheet.ListObjects(1).ListRows.Count = 0 Then
'No data
Else
'We have data
End If

 


Comment by: Deon (9/11/2012 8:22:38 PM)

Best Article on VBA for Tazble I could find on the web so I hope you can assist me. (I am a real amateur when it comes to VBA)

I am working with a workbook in which I copy Worksheet which has two Tables on it. I rename the new worksheet to a date reference e.g. 11-09-2012 the tables are given names similar to the master sheet but with different numbers e.g. (Table 1 becomes Table 5 and Table 2 becomes Table 6) now I do not know what these numbers are going to be so I cannot use that table names in the following code I need to write. When I create a second or third copy of the Master sheet the Table numbers just keep on incrementing.

I want to use the code you provided to ListObjects but get dont seem to get the right way to use the Name which is displyed in teh Msgbox in a code line to rename it. Then If I have that Code how do i change the name for the second table

    Dim oSh As Worksheet
    Dim oLo As ListObject
    Set oSh = ActiveSheet
    For Each oLo In oSh.ListObjects
        Application.Goto oLo.Range
        oLo.Range.Select
        Selection.ListObjects.Name = "MasterData" & Range("H" & 2).Value
    Next

The Idea is to rename
Table1 to MasterData11-09-2012(Date Identified in Cell H2)
Table2 to SlaveData11-09-2012

 


Comment by: Jan Karel Pieterse (9/12/2012 9:48:22 AM)

Hi Deon,

You could do it like this:

Sub RenameTables()
    Dim oLo As ListObject
    For Each oLo In ActiveSheet.ListObjects
        If LCase(oLo.Name) Like "table1*" Then
            oLo.Name = "MasterData" & Range("H2").Value
        Else
            oLo.Name = "SlaveData" & Range("H2").Value
        End If
    Next
End Sub

 


Comment by: David Darby (9/17/2012 1:52:52 AM)

This button code works like a charm to clear all filters in my xl2010 datasheet.
How can I make it work on the addition of "Table1" to the sheet?

Private Sub CommandButton1_Click()
With ActiveSheet
    If .AutoFilterMode Then
     If .FilterMode Then
        .ShowAllData
     End If
    End If
End With
End Sub

 


Comment by: Jan Karel Pieterse (9/17/2012 9:24:53 AM)

Hi David,

Probably like this:


Sub RemoveFilters()
    Dim oLo As ListObject
    For Each oLo In ActiveSheet.ListObjects
        oLo.AutoFilter.ShowAllData
    Next
With ActiveSheet
    If .AutoFilterMode Then
     If .FilterMode Then
        .ShowAllData
     End If
    End If
End With
End Sub

 


Comment by: prakash (9/23/2012 3:06:13 PM)

How do you copy a range in table

 


Comment by: Jan Karel Pieterse (9/24/2012 11:42:13 AM)

Hi Prakash,

Depends; what "range" do you want copied and to where?

 


Comment by: NigelG (10/7/2012 10:59:04 PM)

Hi, Great thread however when I got to the end, had forgotten what I was looking for despite picking up 'never know when I might need that' code snippets!

I have a version of this which works using conventional 'range' notation. The challenge I have is to convert the process to work with a Table/ListObject notation hopefully using structured references.
The process involves 'resetting' a table by:
a. Archiving rows based on filtered 'Status' onto a newly added worksheet using Copy with 'visible' cells and multiple PasteSpecial(s) (this works).
b. Deleting the archived rows from the original worksheet (I can't get any combination of ListObject syntax to work)
c. Applying ClearContents to complete columns (less headers of course) (This works)
d. Applying pre-sets to multiple columns in the rows selected by filter (this works).

Code snippet:
VB
With oloTableName
        .Range.AutoFilter Field:=1, _
            Criteria1:="<>Paid", Operator:=xlAnd
    ' Copy the visible cells including the headings
        .Range.SpecialCells(xlCellTypeVisible).Copy
    ' Use Paste Special to transfer to the new worksheet
        With wksArchive.Range("A1")
            .PasteSpecial Paste:=xlPasteColumnWidths,        
operation:=xlNone, _
                skipblanks:=False, Transpose:=False
            .PasteSpecial Paste:=xlPasteValuesAndNumberFormats, operation:=xlNone, _
                skipblanks:=False, Transpose:=False
        End With
    ' Now delete the rows offloaded to archive
    ' .Range.SpecialCells(xlCellTypeVisible).ListRow.Delete

 


Comment by: Nigelg (10/7/2012 11:25:00 PM)

Tried to post earlier but 'submit' sent before I had finished so this time a lot briefer;
What is the syntax for deleting rows from Tables/ListObjects when the table has a filter applied that is I only want to delete the rows that are 'visible'?

Thanks,
A great thread by the way. Code snippets all the way.
Nigel

 


Comment by: Hi Nigel, (10/8/2012 8:49:19 AM)

I expect it might take something like this:

Sub RemoveFilteredRows()
    Dim oCell As Range
    Dim lCt As Long
    With ActiveSheet.ListObjects(1)
        For lCt = .ListRows.Count To 1 Step -1
            If .ListRows(lCt).Range.EntireRow.Hidden = False Then
                .ListRows(lCt).Range.EntireRow.Delete
            End If
        Next
    End With
End Sub

 


Comment by: NigelG (10/9/2012 10:25:41 AM)

Hi Jan,
Thanks for the prompt answer re: Deletion of only "visible" rows in a filtered table I was trying to optimise the process just to one statement rather than an iterative process which you have offered. Is it me or are there inconsistencies in the way that VBA Object, methods and properties are referenced?

For example, I can copy all visible rows using

With oloTableName
' Copy the visible cells including the headings
        .Range.SpecialCells(xlCellTypeVisible).Copy
' Cut also works but that cuts the headings as well- Doh!
' Attempted deletion that follows doesn't work
' Now delete the rows offloaded to archive
    ' .Range.SpecialCells(xlCellTypeVisible).ListRow.Delete
End With

When I recorded the original macro along with the usual smattering of '.Select' this and Selection.that statements captured, having selected the visible rows (and header) it left me with a very simple Selection.EntireRow.Delete. I have tried the EntireRow.Delete method specification and that didn't work in my code.
Any idea why the methods that are applicable to a 'Selection' are not available to object referenced streamlined code (that is code that removes all the supposed inefficiencies of 'Select' and 'Activate' stuff).
Thanks, Nigel

 


Comment by: Jan Karel Pieterse (10/9/2012 10:31:13 AM)

Hi Nigel,

I just tried and it appears you cannot delete a set of non-consecutive rows when one or more of the rows are part of a table. Hence the iteration.

 


Comment by: Newb (11/14/2012 3:42:45 PM)

I liked the section on inserting a new row to a table, however I'm trying to insert the row to the end of the table and then select the first cell of that new row. H E L P (I have no idea what I'm doing). Thanks for this thread! Vette

 


Comment by: Jan Karel Pieterse (11/16/2012 4:01:58 PM)

Hi Newb

Does my answer to this comment:

"Comment by: Silke (4/3/2012 8:59:07 AM)"

Help?

To view all comments, click:

http://www.jkp-ads.com/articles/Excel2007TablesVBA.asp?AllComments=True

 


Comment by: Jim Malkowski (11/24/2012 12:57:36 PM)

Hi. Got to share this with this great thread. It's some code I wrote to make row deletes from a table. I found that it is possible to delete non-contiguous selections from a protected table, and without sorting. Anyone who can improve this, please post back.

Private Sub DeleteRow_Click()                     ' delete all rows which have any cell in the row selected

Dim xLoop As Long                                 ' xLoop counts rows to be deleted
Dim xMyCell As Range, xMyRange As Range, fRange As Range 'fRange is the range of rows to be deleted
Dim xMyArray() As String                         ' xMyArray accumulates the unique row numbers to be deleted
Dim xz As Variant                                 ' xz is used for the array search to make sure rows aren't duplicated

Application.ScreenUpdating = False 'set selection to visible cells, ActiveCell if only 1 cell selected; initialize fRange with 1st selected cell
Set xMyRange = IIf(Selection.Count > 1, Selection.SpecialCells(xlCellTypeVisible), ActiveCell): Set fRange = xMyRange(1)
For Each xMyCell In xMyRange                     ' find rows to be deleted
    ReDim Preserve xMyArray(xLoop)                 ' get unique rows(as string) for duplicate row check
    xz = Filter(xMyArray, CStr(xMyCell.Row))     ' check if cell row is already selected, if not add row to range to be deleted
    If UBound(xz) < 0 Then xMyArray(xLoop) = CStr(xMyCell.Row): Set fRange = Union(fRange, xMyCell): xLoop = xLoop + 1 'increment counter
Next
If MsgBox("The " & IIf(xLoop = 1, "selected row", xLoop & " selected rows") & " will be deleted", 305, "Confirm Delete . . .") = vbOK Then
    For Each xMyCell In fRange.Areas
        xMyCell.EntireRow.Delete                 ' delete range of all rows to be deleted
    Next
End If
ActiveCell.Select
Erase xMyArray
End Sub

 


Comment by: Jan Karel Pieterse (11/25/2012 7:11:20 PM)

Hi Jim,

Thanks!

 


Comment by: Carey (12/7/2012 11:12:13 AM)

This is a great article! How do I reference just a single cell? Like row 4 of column 'lastname'? Sorry if this is a stupid question but I'm kind of a newbie.

 


Comment by: Jan Karel Pieterse (12/7/2012 1:10:09 PM)

Hi Carey,

For example like this:

Sub test()
    With ActiveCell.ListObject
        MsgBox .ListColumns("lastname").DataBodyRange.Rows(4).Value
    End With
End Sub

 


Comment by: Carey (12/7/2012 6:52:54 PM)

Thanks, Jan! I completely missed the part where I could pass the column name to the ListColumns method. All of the examples above use the column number with the ListColumns method and the column name with the Range method so I thought that was a hard and fast rule.

 


Comment by: Lance Thomas (12/30/2012 7:03:22 AM)

Is it possible to auto-sort a table with three columns after the new data is entered in the third column?
Sub Macro10()
'
' Macro10 Macro
'

'
    ActiveWorkbook.Worksheets("Symbol List").ListObjects("Table4").Sort.SortFields. _
        Clear
    ActiveWorkbook.Worksheets("Symbol List").ListObjects("Table4").Sort.SortFields. _
        Add Key:=Range("Table4[[#All],[Symbol]]"), SortOn:=xlSortOnValues, Order _
        :=xlAscending, DataOption:=xlSortNormal
    With ActiveWorkbook.Worksheets("Symbol List").ListObjects("Table4").Sort
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With
End Sub


Symbol is Column 1; Description is Column 2; and Exchange is Column 3.

 


Comment by: Jan Karel Pieterse (1/2/2013 1:47:46 PM)

Hi Lance,

I would probably just tie your macro to a button placed just above your table, that is easiest.

 


Comment by: Lance (1/3/2013 2:53:13 AM)

Hello Jan,

I had played with it for a while and was able to get it working without tying it to a button:

Private Sub Worksheet_Change(ByVal Target As Range)
    ActiveWorkbook.Worksheets("Symbol List").ListObjects("Table4").Sort.SortFields. _
        Clear
    ActiveWorkbook.Worksheets("Symbol List").ListObjects("Table4").Sort.SortFields. _
        Add Key:=Range("Table4[[#All],[Symbol]]"), SortOn:=xlSortOnValues, Order _
        :=xlAscending, DataOption:=xlSortNormal
    If Not Intersect(Target, Range("Table4[[Exchange]]")) Is Nothing Then
        With ActiveWorkbook.Worksheets("Symbol List").ListObjects("Table4").Sort
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
    End If
End Sub


Thanks for the additional idea…

 


Comment by: Joe (1/4/2013 11:04:42 PM)

I want to insert a table via VBA into a data range of unknown size. I know where the range will start, but its size will vary depending on the amount of info collected. The number of columns will stay the same, but the number of rows will increase or decrease.

For example:
ActiveSheet.ListObjects.Add(xlSrcRange, _
Range("$A$3:$Q$[???]"), , xlYes).Name = _
        "Table1"

Where I don't know what [???] will be.

I tried to look for this answer, but I just can't sift through five years of responses! Thanks!

 


Comment by: Jan Karel Pieterse (1/5/2013 8:28:19 PM)

Hi Joe,

Instead of Range("$A$3:$Q$[???]"), you could use:

Range("$A$3").CurrentRegion

 


Comment by: Joe (1/7/2013 11:12:09 PM)

So easy and so effective. Thanks Jan!!

 


Comment by: Bambi (1/19/2013 8:55:20 AM)

it is not possible to insert a new table at parts of the existing table, e.g. with another makro, so how to remove the existing table?

 


Comment by: Jan Karel Pieterse (1/20/2013 7:00:59 PM)

Hi Bambi,

Can you please explain a little more, I don't understand what you mean?

 


Comment by: Kpooz (1/21/2013 4:04:55 PM)

I cant get this one to work, i need to be able to use the same macro for multiple tables on multiple worksheets.

wsx is a a stored integer adding 1 for each time the macro is repeated.
lastrow is a stored integer saying wich row is the last row containing something.
tbl is a listobject.


    ActiveSheet.ListObjects.Add(xlSrcRange, Range("A3", "L" & lastrow), , xlYes).Name = "Table" & wsx
    Set tbl = "Table" & wsx
    ActiveSheet.ListObjects(tbl).Sort.SortFields.Clear
     ActiveSheet.ListObjects(tbl).Sort.SortFields.Add Key _
        :=Range(tbl & "[[#All],[Adress]]"), SortOn:=xlSortOnValues, Order:= _
        xlAscending, DataOption:=xlSortNormal
    With ActiveSheet.ListObjects(tbl).Sort
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With

 


Comment by: Jan Karel Pieterse (1/22/2013 8:49:13 AM)

Hi Kpooz,

I'm not sure what exactly your macro is supposed to do.
How do the two variables you mention get their value?
If I read your code, none of the ranges are curreently formatted as table, correct?

 


Comment by: Kpooz (1/22/2013 11:28:12 AM)

Hi

This is how the variables get their values;

Dim ws As Worksheet
Dim wsx As Integer
Dim lastrow As Integer
Dim tbl As ListObject

wsx = 0

For Each ws In ThisWorkbook.Worksheets

If ws.Name = "Sheet2" Then
    wsx = wsx + 2
Else
    wsx = wsx + 1
End If

If wsx > ThisWorkbook.Worksheets.Count Then
    Exit For
End If

    Sheets(wsx).Select
    lastrow = Cells(Rows.Count, "A").End(xlUp).Row


And the macro is supposed to create a table named table + the active worksheet number (wsx). And add a ascending sorting. The problem is how to use a variable (tbl) to select a table and add sorting;
Set tbl = "Table" & wsx

And
(tbl & "[[#All],[Adress]]")


I dont know if this is possible, maybe by selecting a table using currentregion or something similar.

Thanks / Kpooz

 


Comment by: Jan Karel Pieterse (1/22/2013 2:04:40 PM)

Ah, now I get it.

Perhaps like so:


    Dim tbl As ListObject
    Set tbl = ActiveSheet.ListObjects.Add(xlSrcRange, Range("A3", "L" & lastrow), , xlYes)
    With tbl
    .Name = "Table" & wsx
        .Sort.SortFields.Clear
        .Sort.SortFields.Add Key:=.ListColumns("Address").Range, SortOn:=xlSortOnValues, Order:= _
                             xlAscending, DataOption:=xlSortNormal
        With .Sort
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
    End With

 


Comment by: Kpooz (1/22/2013 2:59:13 PM)

That did it!

Thanks alot!

 


Comment by: royce (1/28/2013 8:27:19 AM)

I was trying to find a way to query a Excel table using SQL statement.
Please can you help me with a sample example, how this can be acehived.

 


Comment by: Jan Karel Pieterse (1/28/2013 10:55:04 AM)

Hi Royce,

Have a look at this page:

http://erlandsendata.no/?p=2139

 


Comment by: Alan (2/12/2013 8:29:03 PM)

I am copying table rows (2010) from one worksheet and pasting in another worksheet in the same workbook. How can I return to the first page and remove that section from the existing row?

 


Comment by: Jan Karel Pieterse (2/13/2013 8:55:20 AM)

Hi Alan,

Can you please post the relevant bit of your code?

 


Comment by: Alan (2/13/2013 7:11:45 PM)


Sub DUE_to_YTD()
'
'
' Keyboard Shortcut: Ctrl+Shift+ D
'
If ActiveSheet.Name = "DUE" Then
strCell = ActiveCell.Address(ReferenceStyle:=xlA1)
Else
Exit Sub
End If
    Application.ScreenUpdating = False
    Range("A" & ActiveCell.Row).Select
    ActiveCell.Range("A1:I1").Select
    Selection.Cut
    Application.Goto Reference:="YTD_Totals"
    Application.Goto Reference:="R35000C1"
    Selection.End(xlUp).Select
    ActiveCell.Offset(1, 0).Range("A1").Select
    ActiveSheet.Paste
    Selection.FormatConditions.Delete
    Selection.Borders(xlDiagonalDown).LineStyle = xlNone
    Selection.Borders(xlDiagonalUp).LineStyle = xlNone
    Selection.Borders(xlEdgeLeft).LineStyle = xlNone
    Selection.Borders(xlEdgeTop).LineStyle = xlNone
    Selection.Borders(xlEdgeBottom).LineStyle = xlNone
    Selection.Borders(xlEdgeRight).LineStyle = xlNone
    Selection.Borders(xlInsideVertical).LineStyle = xlNone
    Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
    ActiveCell.Range("A1:I1").Select
    With Selection.Interior
        .Pattern = xlSolid
        .PatternThemeColor = xlThemeColorAccent1
        .Color = 13434879
        .TintAndShade = 0
        .PatternTintAndShade = 0.799981688894314
    End With
    With Selection.Interior
        .Pattern = xlNone
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
    Range("A2").Select
    ActiveSheet.Previous.Select
    Selection.ListObject.ListRows(5).Delete
    ActiveCell.Select
    ActiveWindow.ScrollRow = 2
    Application.ScreenUpdating = True
    ActiveCell.Select
End Sub

 


Comment by: Jan Karel Pieterse (2/14/2013 8:43:01 AM)

Hi Alan,

Before writing any code:
I think you are copying columns A:I from the current row to another worksheet. SO if you are on row 5, you copy A5:I5.
Am I correct in assuming you want to remove A5:I5 from the table?

 


Comment by: Alan (2/14/2013 9:22:02 PM)

Thanks Jan.

No, that is the problem. When recorded it identifies that section of row and I need something that is not so absolute but rather based on the row it lands on when returning from the other worksheet.

 


Comment by: Jan Karel Pieterse (2/15/2013 3:54:21 PM)

It is not clear to me which rows(s) need to be removed. What is the logic behind it?

 


Comment by: Alan (2/15/2013 7:17:37 PM)

Thanks. What happens is once a task from the table is complete, the section is moved to a worksheet to retain for history. Once that row is moved the macro needs to return to the first/current sheet and remove that section of cells. Does this make sense?

 


Comment by: Jan Karel Pieterse (2/18/2013 8:28:45 AM)

Hi Alan,

I reworked your code a bit (Selecting is not needed and it is faster not to). Please check whether this works on a copy of your file:

Sub DUE_to_YTD()
'
'
' Keyboard Shortcut: Ctrl+Shift+ D
'
' Variable to Remember the current selection
    Dim oSel As Range
    Set oSel = Selection
    If ActiveSheet.Name = "DUE" Then
        strCell = ActiveCell.Address(ReferenceStyle:=xlA1)
    Else
        Exit Sub
    End If
    Application.ScreenUpdating = False
    Range("A" & ActiveCell.Row).Resize(, 9).Cut
    With Worksheets("YTD")
        .Paste .Range("A" & .Rows.Count).End(xlUp).Offset(1)
        With .Range("A" & .Rows.Count).End(xlUp)
            .FormatConditions.Delete
            .Borders(xlDiagonalDown).LineStyle = xlNone
            .Borders(xlDiagonalUp).LineStyle = xlNone
            .Borders(xlEdgeLeft).LineStyle = xlNone
            .Borders(xlEdgeTop).LineStyle = xlNone
            .Borders(xlEdgeBottom).LineStyle = xlNone
            .Borders(xlEdgeRight).LineStyle = xlNone
            .Borders(xlInsideVertical).LineStyle = xlNone
            .Borders(xlInsideHorizontal).LineStyle = xlNone
        End With
        Application.ScreenUpdating = True
    End With
    Intersect(oSel.EntireRow, oSel.Parent.Range("A:I")).Delete xlUp
End Sub

 


Comment by: Kabir Ahmed (2/24/2013 8:30:50 AM)

This will be appreciated if you provide me answer to the following queries:
1) How I can know that few cells of Excel are at VBA default.
2)How I can remove those defaults.
3)I am new in VBA , can you guide me how I can learn that .

Thanking you.

 


Comment by: Jan Karel Pieterse (2/24/2013 9:18:00 PM)

Hi Kabir,

I kindly request you to ask your question at www.eileenslounge.com
There are lots of people there who can help you with this question.

 


Comment by: Wayne P (2/26/2013 6:32:07 PM)

Good article on tables, but I am wondering if you can comments on the memory usage of tables. I have a spreadsheet that is approx 44000 rows and 60 columns in a table. When the data is configured as a TABLE in Excel the memory requirements are huge....1.2GB. If I make one simple change of converting the table to a range the memory requirements drop by 500MB. My spreadsheet that was unusable because it was bumping into Excel's memory limit is now usable. Is this surprising to you? It is to me and I haven't read anything about the penalty you pay for using tables. I am now in the process of undoing my use of tables. Nice feature but apparently very expensive!

Thank You

 


Comment by: Jan Karel Pieterse (2/27/2013 6:40:31 AM)

Hi Wayne,

There must be something else wrong with that file. I just created a file with only one table of 60 cols * 40,000 rows.

A plain table gives me a file of 35,096 Kb.
FOrmatting the range as table gives a bit more: 35,097 Kb.

 


Comment by: Wayne P (2/28/2013 9:50:03 PM)

Jan,

It looks like you're referring to the file size which makes sense to me...my file size is very similar in both cases: range and table. What is different is the memory usage in task manager. I have tried this many times and always get the same result: the same data configured as a range uses SIGNIFICANTLY less memory than when configured as a table. I thought file corruption as well initially but my testing leads me to believe otherwise.

 


Comment by: Jan Karel Pieterse (3/1/2013 3:28:35 PM)

Hi Wayne,

I just tried, for me memory usage increased from 72 mb to 73 mb, which is more than the filesize increase, but nothing dramatic.

 


Comment by: Marv Carson (3/5/2013 7:04:26 PM)

When converting a range to a table using Excel 2010, two unwanted things occur by default.

1. The Column widths are re-sized greater than the preferred column widths of the original range.

2. Alternate row 'shaded banding' is applied when my preference to retain the 'No Fill' background format.

I know the steps to readjust both these, but prefer to avoid them by default to avoid the extra 'corrective steps.

 


Comment by: Hui... (3/7/2013 4:24:30 PM)

In Excel 2010 the Name and Address properties have been changed

Instead of: oLo.Range.Address

They are now: oLo.DataBodyRange.Address

 


Comment by: Jan Karel Pieterse (3/8/2013 1:22:00 PM)

Hi Hui,

Actually, Range.Address returns the entire range of the listobject, including the header row, whereas DataBodyRange is the listobject *without* the header row.

 


Comment by: sah (3/8/2013 6:03:34 PM)

I was wondering if there is a way to let the user add rows to a protected table and still get the formulas in the cells that's supposed to have formulas?

I have a table which is protected and users has access to certain "data entry" cells. One user should have the access to add "records". When the "insert row" option is allowed when protecting sheet, the user is allowed to insert a row but the row is blank (without formulas in cells that does calculation. Is there a way to fix this?

Thanks

 


Comment by: Jan Karel Pieterse (3/8/2013 8:28:17 PM)

Hi Sah,

I don't think so. The only way I think you can achieve this is by writing a macro that unprotects, adds a row and re-protects the sheet.

 


Comment by: Sah (3/8/2013 9:00:21 PM)

Thanks Jan, for your response. I am a novice when it comes to writing VBA codes. Is there anywhere i can get the code for doing what you suggested? Any help will be appreciated. Thanks

Sah

 


Comment by: Jan Karel Pieterse (3/9/2013 1:56:01 PM)

Hi Sah,

Something like this:

Sub Demo()
    ActiveSheet.Unprotect Password:="Foo"
    ActiveSheet.ListObjects(1).ListRows.Add
    ActiveSheet.Protect Password:="Foo"
End Sub

 


Comment by: Toon (3/11/2013 7:16:04 AM)

Thanks for this really useful page about Excel tables in VBA. I would like to submit this piece of code that I wrote to return a value from a table by looking up a value. It uses the column headings instead of column numbers.
The code in is my next post...

 


Comment by: Toon (3/11/2013 7:16:18 AM)


Option Explicit

Sub getRowByValue()
'vlookup functionality in a table by using column headings

    Dim rngColumn As Range
    Dim lo As ListObject
    Dim sh As Worksheet
    Dim strLookupValue As Integer
    Dim strColHeading As String
    Dim strReturnColHeading As String
    Dim strTableName As String
    Dim strFound As String

    strLookupValue = 12     'value to be searched for
    strColHeading = "test"    'column to be searched
    strReturnColHeading = "test2" 'column containing the return value
    strTableName = "Testtable" 'name of the table (set via Formulas - Name manager)

    On Error GoTo err_sheet_not_found
    Set sh = shTest     'VBA sheet name (set in VBA IDE)
    On Error GoTo err_table_not_found
    Set lo = sh.ListObjects(strTableName)
    On Error GoTo err_column_not_found
    Set rngColumn = lo.ListColumns(strColHeading).DataBodyRange
    On Error GoTo 0

    If WorksheetFunction.CountIf(rngColumn, strLookupValue) > 1 Then
        MsgBox "Duplicate values found: " & strLookupValue: End
    ElseIf WorksheetFunction.CountIf(rngColumn, strLookupValue) = 1 Then
        On Error GoTo err
        MsgBox lo.ListRows(WorksheetFunction.Match(strLookupValue, rngColumn)).Range.Cells(1, lo.ListColumns(strReturnColHeading).Index).Value
        On Error GoTo 0
    Else
        MsgBox "Value " & strLookupValue & " not found": GoTo normalend
    End If
    GoTo normalend

err_type_or_retcol:
    MsgBox "Value was found but had a different type (string as number or vice versa) or return column heading not found."

err_sheet_not_found:
    MsgBox "Sheet not found"
GoTo normalend

err_table_not_found:
    MsgBox "Table not found"
GoTo normalend

err_column_not_found:
    MsgBox "Column not found"
GoTo normalend

normalend:

End Sub

 


Comment by: Jan Karel Pieterse (3/11/2013 8:27:44 AM)

Hi Toon,

Thanks. One little critique: your code fails if the table is not sorted on the column you are looking up in. An alternative method:

Sub getRowByValue()
'vlookup functionality in a table by using column headings

    Dim rngColumn As Range
    Dim lo As ListObject
    Dim strLookupValue As Integer
    Dim strColHeading As String
    Dim strReturnColHeading As String
    Dim strTableName As String
    Dim oFound As Range

    strLookupValue = 12     'value to be searched for
    strColHeading = "test"    'column to be searched
    strReturnColHeading = "test2" 'column containing the return value
    strTableName = "Testtable" 'name of the table (set via Formulas - Name manager)

    On Error GoTo err_table_not_found
    Set lo = shTest.ListObjects(strTableName)
    On Error GoTo err_column_not_found
    Set rngColumn = lo.ListColumns(strColHeading).DataBodyRange
    On Error GoTo 0

    If WorksheetFunction.CountIf(rngColumn, strLookupValue) > 1 Then
        MsgBox "Duplicate values found: " & strLookupValue: End
    Else
        On Error Resume Next
        Set oFound = rngColumn.Find(strLookupValue, rngColumn.Cells(1, 1), xlValues, xlWhole, xlRowThenColumn, xlNext, False)
        If Not oFound Is Nothing Then
            MsgBox lo.ListColumns(strReturnColHeading).Range.Cells(oFound.Row + lo.Range.Cells(1, 1).Row - 1, 1).Value
        Else
            MsgBox "Value " & strLookupValue & " not found": GoTo normalend
        End If
    End If
    GoTo normalend

err_type_or_retcol:
    MsgBox "Value was found but had a different type (string as number or vice versa) or return column heading not found."

err_sheet_not_found:
    MsgBox "Sheet not found"
    GoTo normalend

err_table_not_found:
    MsgBox "Table not found"
    GoTo normalend

err_column_not_found:
    MsgBox "Column not found"
    GoTo normalend

normalend:

End Sub

 


Comment by: yan (3/12/2013 11:55:46 AM)

Hi,

Is there a vba code to insert 300 rows into the table at one go?

using the following VBA code takes eternity:

For i = 1 to 300    
Selection.ListObject.ListRows.Add AlwaysInsert:=True
next i


Thanks

 


Comment by: Jan Karel Pieterse (3/12/2013 1:00:29 PM)

Hi Yan,

This makes use of the fact that anything you enter beneath the table expands the table:

    With ActiveSheet
        With .Range("A" & .Rows.Count).End(xlUp).Offset(1).Resize(300)
            .Value = 1
            .ClearContents
        End With
    End With

 


Comment by: Yan (3/13/2013 3:45:46 AM)

That's very enlightening.

Thanks a lot! :)

 


Comment by: Mzweik (3/13/2013 5:41:09 PM)

Hi there

Is there a way to create a table and call it up on a dashboard display?

Thanks

 


Comment by: Jan Karel Pieterse (3/14/2013 8:59:52 AM)

Hi Mzweik,

I'm not sure what you need.
Perhaps you can ask your question at http://www.eileenslounge.com

 


Comment by: Bangu Numbi (3/25/2013 2:15:14 PM)

Hi,

I have to transform daily the data from my company system to excel table for other use. But the data is dynamic. From a VBA, instead to change manually the last line and and last column, I need to transform the "select current region" to a table.

Resume : I need Macro to tranform "select current region" to a table instead the range done manually. Your help will be appreciated.


Bangu Numbi

 


Comment by: Jan Karel Pieterse (3/25/2013 8:37:55 PM)

Hi Bangu,

You mean like this?

ActiveSheet.ListObjects.Add(xlSrcRange, Range("A1").CurrentRegion, , xlYes).Name = _
         "Table1"

 


Comment by: neil peters (3/25/2013 11:37:08 PM)

Hi - hope you can help further....
Have tables in excel 2010 worksheets - basically one table in each of multiple sheets that all update as you add a row, delete a row via userform. Problem I have is I can specify what listrow I want to delete using listrow(number) but I want to do is search for a value (via Textbox1.value in userform) in 1st column of table then delete the listrow that this value (which would be unique) is in. Tried many variations but can't seem to do? Can you give any advise
My current code (which deletes listrow) is

Private Sub CommandButton1_Click()
    Dim wrksht As Worksheet
    Dim strLookupValue As String
    Dim lo As ListObject
    strLookupValue = TextBox1.Value
    For Each wrksht In Sheets
    For Each lo In wrksht.ListObjects
    lo.ListRows(strLookupValue).Delete
    On Error Resume Next
    Next lo
    Next wrksht
    MsgBox "Record Deleted", vbOKOnly, "Delete Record"
    Unload Me
End Sub

 


Comment by: Peter Hodges (3/26/2013 12:50:25 AM)

I want to maintain a task list in Excel of all items in a directory (and SubDirectories). I would really only want the filename and path from the file list. In Excel I would add information about that file (like start date, end Date, Assigned To).
If I moved that file to a different directory or renamed the file, I would want the information I entered to be updated - but not loose my notes about the file!

I would expect there is a spreadsheet already designed to do something like this, but I just need to find it.

 


Comment by: glennpc@cox.net (3/26/2013 2:37:56 AM)

I have a data entry worksheet in a workbook, and a master worksheet in another workbook. The both workbooks contain tables on those worksheets: a data entry table in one workbook and a master table in the other workbook. The structures of the tables are NOT identical-- they have 9 columns in common, but the master table has 2 additional columns. Both tables are set up with dropdown lists for data validation. The goal is to copy data from various submitted data entry workbooks to the master table in the master workbook.

Originally, these were not tables, they were named ranges. I would manually copy and paste the data entry range (maybe 5 or 6 rows) onto the worksheet in the master workbook, right next to the master data range (copying only VALUEs, not the formatting). Then I wrote VBA code that looped and selectively copied the data values from the data entry range to the bottom of the master beginning with the first blank row. It left the two extra columns blank, only copying the data they had in common into the correct columns. It worked fine.

I changed the ranges to tables to take advantage of all the benefits of tables, but my VBA code now does not copy anything when I run it. In a nutshell, what am I doing wrong? Because I'm using tables, do I need to reference the cells differently in my VBA code to make this work?

All the examples I see always have you copying the whole table to another worksheet, or to another workbook, and all the tables have identical columns. I've not seen anything that does what I'm trying to do (copying some cells in a row over, but leaving others blank). Do I need to abandon tables all together and go back to ranges? My spreadsheets will lose a lot of nice features if I do.

Any advice?

 


Comment by: Jan Karel Pieterse (3/26/2013 8:53:10 AM)

Hi Neil,

You could use the Find method to locate the row in question:

Private Sub CommandButton1_Click()
    Dim wrksht As Worksheet
    Dim strLookupValue As String
    Dim lo As ListObject
    Dim oFound As Range
    strLookupValue = textbox1.Value
    
    For Each wrksht In Worksheets
        For Each lo In wrksht.ListObjects
            Set oFound = lo.ListColumns(1).Range.Find(strLookupValue, lo.Range.Cells(1, 1), xlValues, xlWhole, , xlNext, False)
            If Not oFound Is Nothing Then
                Intersect(lo.DataBodyRange, oFound.EntireRow).Delete
            End If
        Next lo
    Next wrksht
    MsgBox "Record Deleted", vbOKOnly, "Delete Record"
    Unload Me
End Sub

 


Comment by: Jan Karel Pieterse (3/26/2013 8:55:51 AM)

Hi Glenn,

I don't think you have to abandon tables. But the addressing of an item in a table can be a bit challenging.

If you like you can send me your file by email so I can have a look.

 


Comment by: Neil Peters (3/27/2013 7:03:44 PM)

Many thanks for the code Jan - it worked a treat!

 


Comment by: Sammy (3/27/2013 11:08:39 PM)

Hi Jan,

Let me start by saying Thank You for this excellent post. Post like yours are a boon to novice VBA users like me.

I used a code from here to inser a row in my protected worksheet.
Private Sub CommandButton1_Click()
    ActiveSheet.Unprotect Password:="try"
    Selection.ListObject.ListRows.Add AlwaysInsert:=True
    ActiveSheet.Protect Password:="try", AllowFiltering:=True
End Sub

The problem is when the cursor is outside the table, it gives an error, moreover it removes the protection from file, leaving my data vulnerable. Can you help?

Also is there a way i can create a command button when clicked sorts a column in the protected table?

Thanks,

Sammy

 


Comment by: Jan Karel Pieterse (3/28/2013 7:26:44 AM)

Hi Sammy,

You're welcome of course.

If you replace

Selection

with

Activesheet.ListObjects(1)

or with

Activesheet.ListObjects("TheListObjectsName")

(TheListObjectsName can be seen if you click in the table and then activate the table tab on the ribbon. Far left side of the ribbon shows the name)

 


Comment by: Sammy (3/28/2013 3:31:44 PM)

Thanks, Jan. It works prefectly fine

 


Comment by: Rafael Stern (3/28/2013 10:13:15 PM)

Hi Jan,

First of all thanks for the excelent article. I appreciate if we can communicate by my e-mail above, as its easier for me and I imagine for you as well.

I was wondering if you can help me with two things:

1- do you have a list of methods or functions that can be used along the listobjects?

2- I have one sheet with a few tables, one under the other. How can i delete all the empty rows in each of the tables? The criteria would be the first column empty on each of the tables and they are not necessarily sorted.

Thanks in advanced.

 


Comment by: Jan Karel Pieterse (3/29/2013 11:52:01 AM)

No, I do not have such a list, but Excel VBA help should have one.

Deleting all data from all tables on the activesheet is as simple as:

Sub DeleteAllTableData()
    Dim oLo As ListObject
    For Each oLo In ActiveSheet.ListObjects
        If Not oLo.DataBodyRange Is Nothing Then
            oLo.DataBodyRange.Rows.Delete
        End If
    Next
End Sub

 


Comment by: Neil Peters (3/31/2013 12:42:14 PM)

Hi (again) - I'm trying to amend the code you kindly gave me to delete a row based on a selection from an inputbox. What I'm now trying to do is with that code (this bit works) is load a userform with row details - but the bit I can't get to work is save new amended details from userform into all listobjects in worksheets. Tried various options but can only get to work on the one sheet or not at all. I know where it's going wrong but can't find a solution. Wondered if you could point me in the right direction (I have looked everywhere!) The code that works for one worksheet is

Private Sub CommandButton1_Click()
    Dim wrksht As Worksheet
    Dim lo As ListObject
    Dim FilterCriteria As String
    Dim oFound As Range
    
    FilterCriteria = Me.TextBox6.Value
    
    For Each wrksht In Sheets
    For Each lo In wrksht.ListObjects
    On Error GoTo ErrorHandler
        Set oFound = lo.ListColumns(1).Range.Find(FilterCriteria, lo.Range.Cells(1, 1), xlValues, xlWhole, , xlNext, False)
            If Not oFound Is Nothing Then
                Intersect(lo.DataBodyRange, oFound.EntireRow).Select
            End If

                    oFound.Cells(1, 1).Value = UserForm3.TextBox6.Value
                    oFound.Cells(1, 2).Value = UserForm3.TextBox1.Value 'These work

'    lo.ListRows(oFound).Range.Cells(1, 2).Value = TextBox1.Value (this option will select a row but not right one)
    
    Next lo
    Next wrksht
    MsgBox "One record amended"
    Unload Me
End Sub


What I need I think is how to reference the row I'm in from selection of search inputbox and change that row the selection is in.
Any advice you can suggest.
Realise it's holidays so not expecting you to reply yet! Thanks

 


Comment by: Bangu Numbi (4/1/2013 3:05:10 PM)

Very thanks Peter. I am very sorry for delay feedback. It is working very well.

Regards,

Bangu Numbi

 


Comment by: Jan Karel Pieterse (4/2/2013 1:58:12 PM)

Hi Neil,

Exactly what needs to happen with the found row?

Doesn't this work:

With Intersect(lo.DataBodyRange, oFound.EntireRow)
.Cells(1, 1).Value = UserForm3.TextBox6.Value
.Cells(1, 2).Value = UserForm3.TextBox1.Value
End With

 


Comment by: Neil Peters (4/2/2013 3:57:18 PM)

Jan Karel - once again thank you!!! I'm still very much a VBA novice but your page and help has been invaluable! I had searched the internet and forums but there seems to be a lack of good listobject table vba information out there (except for yourself)! Cheers again Neil.

 


Comment by: Sjur Grønningsæter (4/5/2013 11:33:11 AM)

Is it possible to group a table with VBA so that the group expands with the table when adding new rows? Or use VBA to collapse a table so that only headers are visible?
(the auto outline (grouping) feature does not work with tables)

 


Comment by: Jan Karel Pieterse (4/5/2013 4:44:41 PM)

Hi Sjur,

Well, you could use simple code like this:

Sub HideTableBody()
    With ActiveSheet.ListObjects(1)
        If Not .DataBodyRange Is Nothing Then
            .DataBodyRange.EntireRow.Hidden = True
        End If
    End With
End Sub

 


Comment by: Sjur Grønningsæter (4/10/2013 8:52:40 AM)

Thx Jan! It worked. Can I target specific tables? How do I reverse it?

 


Comment by: Jan Karel Pieterse (4/10/2013 9:59:34 AM)

Hi Sjur,

Each table has a name which you can see in the table ribbon on the far left of the ribbon. You use that name -say it is Table1 in this case- like so:

ActiveSheet.ListObjects("Table1")


or if the worksheet as not the active sheet:

Worksheets("Sheet1").ListObjects("Table1")

 


Comment by: Jan Karel Pieterse (4/10/2013 10:00:25 AM)

You can reverse it by using very similar code and replacing True with False

 


Comment by: Francois (4/12/2013 5:39:24 PM)

Hi Jan,

My question is 2 fold,
1. i have a couple of tables sitting in multiple worksheets, each with a unique name lets say tableX, tableY and tableZ. I might not know in which sheet they are residing. is there a why to access the table directly instead of going through the sheets?

2. Assuming i know in which sheet i am working, my tables do not necessarily start in column A. but could for example start in column T. how do i retrieve the relative position of the column in the table. eg 3 columns, first start in T, if i look for the second column it should return 2, instead of 21.

thank in advance.

 


Comment by: Jan Karel Pieterse (4/15/2013 11:29:45 AM)

Hi Francois,

Yes, you can access a table by its name even though it is on a different sheet like this:

Dim oLo As ListObject
Set oLo = Range("TableName").ListObject

 


Comment by: Marcia SAcharny (4/19/2013 2:09:36 PM)

I am new at this, so forgive me if I am totally off track.

I tried to copy your codes to apply your macros to my spreadsheet. But some do nothing and on others I get errors.
So do you have a sample worksheet with the macros in so I can F8 and see how it works?

Thanks!

Marcia

 


Comment by: Jan Karel Pieterse (4/20/2013 9:13:36 PM)

Hi Marcia,

Which routines are not working for you?

 


Comment by: David V. (4/29/2013 12:52:21 PM)

Hello,

Is it possible to work with a table in another excel file that is closed or do I need to open it first using this method?

Tkank you,
David

 


Comment by: Jan Karel Pieterse (4/29/2013 2:10:38 PM)

Hi David,

Whether or not you can work with a table in a closed file depends on how you are trying to access the data in the table. Can you explain a bit more?

 


Comment by: David V. (4/30/2013 9:02:29 AM)

Hello

Im starting a larger project, which involves a lot of workbooks and tables. But i will try to explain it in a simplified version:
I have a main workbook where the vba code will be
and i have another workbook with a table1, this table will be constantly used by another person who will be putting data in it.
I need to access this table1 from the main workbook and pull some specific data from it into the main workbook.

So is there a way to do this? to refer to a table in another workbook which is not opened on my pc preferably.

Thank you,
David

 


Comment by: Jan Karel Pieterse (5/1/2013 1:38:57 PM)

Hi David,

I think your best bet is to create a range name that spans the entire table and then use Data, From other sources, From microsoft query to pull that named range into your working file.

Then either instruct the other user to save regularly, or write a macro that does it for him. ANd refresh the connection to the other workbook in your own regularly too.

 


Comment by: David V. (5/2/2013 9:45:22 AM)

I was considering that option too, so ADODB it is.
The auto save is already done with a macro.

Thanku you very much Jan

 


Comment by: Roy (5/6/2013 7:14:50 AM)

Hello,

I have created vba code to copy some worksheets from workbook 1 to workbook 2.

However, workbook 1 has a table defined with a name. When I copy the worksheets, everything is copied fine except the definition of the table which is referenced in many of the formulas that are copied.

Could you assist me with the vba code to detect table definitions in workbook 1 (if they exist) and re-create them in workbook 2?

I would prefer it to work without hard coding table names or how many tables to copy, so that the code would always work for any number of tables from zero to n.

Thanks for any help...

 


Comment by: Jan Karel Pieterse (5/6/2013 9:59:41 AM)

Hi Roy,

It is realtively easy to redefine all tables, using code like this:

Sub CopyTableDefs(oSource As Worksheet, oTarget As Worksheet)
    Dim oLo As ListObject
    Dim oLo2 As ListObject
    For Each oLo In oSource.ListObjects
        Set oLo2 = oTarget.ListObjects.Add(xlSrcRange, oTarget.Range(oLo.Range.Address), , xlYes)
        oLo2.Name = oLo.Name
    Next
End Sub


So if you copied data from Sheet1 to Sheet2, you call this sub like this:

CopyTableDefs worksheets("Sheet1"),worksheets("Sheet2")

 


Comment by: David V. (5/13/2013 4:46:53 PM)

Hello Jan,

I have used the ADODB and it works very well, but now Im back to the tables in office 2007.

I have a table that is connected to a access DB and Im trying to copy the values of that table into another sheet but im only getting blanks

I have tried:
ActiveSheet.Range("Table_summar.accdb").Select
Selection.Copy

or using cells

Dim sSHT As Worksheet
Set sSHT = ActiveWorkbook.Worksheets("data")
sSHT.Cells(ifor , 1).Value
'using this with a for to next cycle

or using range

Range("A2:D30").Select
Selection.Copy

but nothin works

 


Comment by: Jan Karel Pieterse (5/14/2013 10:34:08 AM)

Hi David,

After issuing Copy, of course you also have to paste somewhere. The code you posted does not include any paste command.

 


Comment by: David V. (5/14/2013 12:50:39 PM)

for the first one and the third one I have tried a pastespecial-values only:

Sheets("Cover").Select
Range("B10:D21").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False


for the second one i used the same for to next cycle as for getting the data:
all variables are string except the ifor which is integer

For ifor = 2 To 12
Set sSHT = ActiveWorkbook.Worksheets("data")
slinka = sSHT.Cells(ifor, 50).Value
smod = sSHT.Cells(ifor, 51).Value
ssn = sSHT.Cells(ifor, 52).Value
Set sSHT = ActiveWorkbook.Worksheets("Cover")
sSHT.Cells(9 + ifor, 2).Value = slinka
sSHT.Cells(9 + ifor, 3).Value = smod
sSHT.Cells(9 + ifor, 4).Value = ssn
Next

 


Comment by: Jan Karel Pieterse (5/14/2013 4:05:05 PM)

Hi David,

To copy the data from sheet Sheet1 to sheet Sheet2, you could use:

Worksheets("Sheet1").ListObjects(1).Range.Copy
Worksheets("Sheet2").Range("A1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False

 


Comment by: David V. (5/16/2013 9:35:42 AM)

Still not working only the headers were pasted not the data.

Worksheets("data").ListObjects(1).Range.Copy
    Worksheets("Cover").Range("B10").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False

 


Comment by: Jan Karel Pieterse (5/16/2013 10:10:00 AM)

Hi David,

Can you perhaps send your workbook by email? The code worked just fine in my testing.

 


Comment by: Juan Gallego (5/27/2013 10:14:54 PM)

I've got a table (not a sheet) named "TDatos", im trying to execute an SQL
code goes like this:
    rs.Open "SELECT distinct [Ciudad], Sum([Ventas]) as Total FROM [TDatos] WHERE [Ventas]>0 GROUP BY [Ciudad] ", Conexión, , , adCmdText

i've already done the right connection with excel: Connection.open..., but the Sql stops saying that couldent find the object "TDatos"
Thanks

 


Comment by: Jan Karel Pieterse (5/28/2013 8:39:54 AM)

Hi Juan,

Queries do not work with Table names directly. However, you can define a range name that simply points to the entire table and use that range name in the query.

 


Comment by: David V. (5/31/2013 9:16:44 AM)

Hello Jan,

I havent had time for this in the last two weeks, but today i finaly got to it and i have created a copy of the whole thing and started deleting stuff until i got to the line
Worksheets("data").Range("A2:BB50000").ClearContents
my table was somewhere in this range and it was deleted or somethin. and this is why it was not working. but im not sure why, because i have used a refresh for the table right before i have copied it.
Worksheets("data").ListObjects(1).QueryTable.Refresh BackgroundQuery:=True

anyways this Worksheets("data").ListObjects(1).Range.Copy
is not working properly it copies the headers too and i dont want that.
So i have used:
Worksheets("data").Range("Table_summar.accdb").Copy
instead of that.

And finaly everything is working :)

Thak you for your support
bb

 


Comment by: Jan Karel Pieterse (5/31/2013 12:01:56 PM)

Hi David,

You could probably also have used the DataBodyRange property instead of the Range property

 


Comment by: Tony Lawson (6/1/2013 4:55:59 PM)

Hi
I am trying to use your suggestion
"If you need to do something with a newly inserted row, you can set an object variable to the new row"
I would like to do this without the need to select the Table Row. Can you please look at my code below and suggest a way of doing this.


Dim MySheet As Worksheet 'MY WORKSHEET
Dim MyNewRow As ListRow 'NEW ROW IN TABLE

    Set MySheet = Sheet1 'SET MY WORKSHEET
        Set MyNewRow = Selection.ListObject.ListRows.Add 'FAILS HERE

            With MySheet.ListObjects("MY_TABLE_NAME_HERE")
                    .ListRows.Add 'ADD ANOTHER ROW TO THE TABLE

            End With

MyNewRow.Range.Cells(1, 1).Value = "Value For New cell"



Many thanks

 


Comment by: Tony Lawson (6/1/2013 5:39:53 PM)

Hi
I don't wish to waste your time so I wanted to let you know I have a solution to my previous request.


Dim MySheet As Worksheet 'MY WORKSHEET

    Set MySheet = Sheet1 'SET MY WORKSHEET

            With MySheet.ListObjects("MY_TABLE_NAME_HERE") 'MY TABLE
                
                With .ListRows.Add 'ADD NEW ROW TO TABLE
                    .Range(1) = "Value_for_New_Cell" 'FIRST CELL OF NEW ROW
                    .Range(2) = "Value_for_next_New_Cell" 'SECOND CELL OF NEW ROW

                End With

            End With

 


Comment by: Jan Karel Pieterse (6/2/2013 8:31:24 PM)

HI Tony,

Great stuff, I just wait for a bit and people answer their own questions. :-)

Thanks for posting your solution.

 


Comment by: Varsha (6/5/2013 7:46:05 AM)

I want to run the sql query on excel table. Please help.

 


Comment by: Jan Karel Pieterse (6/5/2013 8:04:12 AM)

Hi Varsha,

Unfortunately, MSQuery (nor ODBC) does not recognize Excel 2007-2013 tables natively.

Your best alternative is to name the range the table spans using Formulas, Define name.

 


Comment by: ganesan (7/12/2013 1:05:46 PM)

dear sir,

how to excel vba protect sheet with password. if password is disable then automatical delete protect sheet.

please help.

regards,
Ganesan

 


Comment by: Jan Karel Pieterse (7/13/2013 7:09:28 PM)

Hi ganesan,

I kindly ask you to go here to get an answer to your questions:
www.eileenslounge.com

 


Comment by: Anvidc (8/16/2013 10:52:15 AM)

Hi,
There is another easy way to get data from table:

a = [TableName[ColumnsName]].Cells(NoRowInSideTable)

To Update Table Data:

[TableName[ColumnsName]].Cells(NoRowInSideTable) = YourValue



 


Comment by: Jan Karel Pieterse (8/16/2013 3:39:53 PM)

Hi Anvidc,

Thanks! I am no fan of using the [] syntaxis, as it requires VBA to evaluate the statement before it returns the object. Direct object name referencing as in

Worksheets("Sheet1").ListObjects("ListObjectName").ListColumns("FieldName")


is faster.

 


Comment by: Dan (8/21/2013 4:23:34 PM)

Thanks for this, just saved me a lot of hassle!

 


Comment by: Yulia (8/30/2013 5:22:10 PM)

Please help! How to I auto-refresh an Excel auto-filter when data is changed?

I have my table in "monthly data" tab, sheet1 tab is an autofilter based on criteria. I change the value of one cell in "monthly data" tab and want to see the auto update in sheet1.

I have a recurrent process, where a lot of data would change in the "monthly data" tab, so this auto-refresh would help greatly!

 


Comment by: Jan Karel Pieterse (9/1/2013 8:15:11 PM)

Hi Yulia,

One way would be by right-clicking the sheet tab and selecting View code. Then paste this code:

Private Sub Worksheet_Activate()
    Me.ListObjects(1).AutoFilter.ApplyFilter
End Sub

Make sure you save the file as an Excel workbook with macro's.

 


Comment by: Yulia (9/3/2013 7:08:11 PM)

Hi Jan Karel,
Thank you for your reply.
I pasted the code, then selected "Close and Return to Excel", saved file as .xlsm, re-opened it and nothing changed. Is there something I need to do to "run" it?
I sent you an invite via LinkedIn, maybe we can talk there.

 


Comment by: Jan Karel Pieterse (9/4/2013 8:13:21 PM)

Hi Yulia,

The code only runs when you activate the sheet in question. So go to a different worksheet and then acativate the one with the code again.

 


Comment by: Rajiv (9/30/2013 10:03:45 AM)

It is very good detail


thanks alot

 


Comment by: Rick (11/8/2013 11:03:39 AM)

ooking for a bit of help please?

I have a spreadsheet that basically allows users to input a number of data fields into it, names, numbers etc. It runs on a dynamic list object table that automatically populates todays date into Column A, and then allows the user to input 7 other cells B-J. It then runs through a series of calculations to check for duplicate values throughout the spreadsheet and formats the cells accordingly using colour. It also adds three other cells to RAG the entry to inform the user if they need to double check the entry or not. It performs the calculations through the worksheet change events.

The worksheet i set to autofilter to the last 10days worth of entries.

I have one major issue in that if the user deletes the prepopulated date in column A then the code bugs out, and hides the row. Assuming because the autofilter fails?

I have done some reading to see about protecting the column / cells but it doesn't seem that straight forward and im going round in circles...

I guess i'm left with two options unless someone can come up with something to help, educate users (not easy!) or look at protecting the cells somehow, using some sort of data validation / object box for data entry? Any help / suggestions would be greatly appreciated? The nature of the workbook doesn't allow me to upload it, but i have attached the code but changed the named ranges etc... please go easy, i'm a VBA newbie ;-)

Thanks - code in the next post because its too long ;-/

 


Comment by: balwant randev (11/10/2013 1:19:48 PM)

I want to change the value in a cell if the cell value is 9.I am increasing it to 10 by adding a 0 on the fourth place using vba. the code I am trying is listed below but it gives an error. please help
ActiveCell.Offset(0, 0) = "SUBSTITUTE(ActiveCell.Offset(0, 0),LEFT(ActiveCell.Offset(0, 0),3),LEFT(ActiveCell.Offset(0, 0),3), & "0",1))

 


Comment by: Jan Karel Pieterse (11/11/2013 7:18:51 AM)

Hi balwant,

If I read your question properly, this should do the same as your code:

ActiveCell.Value=Replace(ActiveCell.Value,LEFT(ActiveCell.Value,3),LEFT(ActiveCell.Value,3) & "0", 1))


 


Comment by: balwant randev (11/12/2013 6:42:17 AM)

thanks I will try the same

 


Comment by: balwant (11/14/2013 1:29:05 PM)

Hi Jan
I tried the code
ActiveCell.Value=Replace(ActiveCell.Value,LEFT(ActiveCell.Value,3),LEFT(ActiveCell.Value,3) & "0", 1))
but I still get syntax error end of statement expected.
I have column which has 9 or 10 characters. I am trying to convert the 9 characters to 10 characters by adding a digit in the fourth place.
many thanks in anticipation

 


Comment by: Jan Karel Pieterse (11/14/2013 3:09:25 PM)

Hi Balwant,

Sorry, I did not test my code. I expect removing the

, 1

at the end fixes it.

 


Comment by: balwant (11/15/2013 2:44:22 PM)

Thanks Jan
I removed ,1) and it works
I will use it with activecell.offset(1,0).select
to make the rest of the column work.
thank you again
balwant

 


Comment by: Brent (11/18/2013 7:14:04 PM)

The line

oNewRow .Range.Cells(1,1).Value="Value For New cell"

should not have a space after oNewRow.

 


Comment by: Jan Karel Pieterse (11/19/2013 7:10:25 AM)

Hi Brent,

Thanks!

 


Comment by: andy (1/21/2014 9:17:43 PM)

Hi Jan,
after deleting row in ListObject that contains only one row (the only remaining row),using the code line like:
oListObject.ListRows(iRowNumber).Delete

it deletes only data, but row still figures (List must contain at least one row); it's OK, but then                     ListObject.DataBodyRange lost reference.
In moment when empty ListObject is created, situation seems the same (there is one empty row), but ListObject.DataBodyRange can be referenced.
What's wrong?
Best Regards
Andy

 


Comment by: Jan Karel Pieterse (1/22/2014 8:45:28 AM)

Hi Andy,

I just tried with Excel 2010 and whether he listbox is newly created (with only a header row), or all rows have been deleted makes no difference. In both cases DataBodyRange errors out.
Best to test for Listbox.ListRows.Count > 0 before addressing the DataBodyRange.

 


Comment by: Brady (2/6/2014 6:21:40 PM)

Is there any way to hide a table row without hiding a worksheet row?

 


Comment by: Jan Karel Pieterse (2/6/2014 7:27:51 PM)

Hi Brady,

No I don't think you can do that.

 


Comment by: edrees yousif (2/8/2014 5:56:54 PM)

thanks alot .
these information more important to me

 


Comment by: Eddie (2/12/2014 12:21:22 PM)

Jan, Great article thanks.
I'm constrained to working in Excel 2003. I have a listobject that I write to an array. The data is updated and then I write it back to the list object. Net result is the the number of rows may grow.

'write listobject data + formulas to array
arrCollatedInitiatives = ActiveWorkbook.Sheets("Initiatives").ListObjects("tblInitiatives").DataBodyRange.Formula

'do stuff

'write array back to listobject
Range("tblInitiatives").Resize(UBound(arrCollatedInitiatives, 1), UBound(arrCollatedInitiatives, 2)).Value = arrCollatedInitiatives

This works in Excel 2013 where the range name is the same as the listobject... but it does not work in Excel 2003

If this I need something like...

ActiveWorkbook.Sheets("Initiatives").ListObjects("tblInitiatives").Resize Range("tblInitiatives").Resize(UBound(arrCollatedInitiatives, 1), UBound(arrCollatedInitiatives, 2)).Value = arrCollatedInitiatives

but I can't make it work! Help!

 


Comment by: Jan Karel Pieterse (2/12/2014 2:42:42 PM)

Hi Eddie,

Since your reading the databodyrange, you should be writing back to it as well:


ActiveWorkbook.Sheets("Initiatives").ListObjects("tblInitiatives").DataBodyRange.Resize(UBound(arrCollatedInitiatives, 1), UBound(arrCollatedInitiatives, 2)).Value = arrCollatedInitiatives

 


Comment by: Eddie (2/12/2014 6:39:58 PM)

Legend! Thanks - just couldn't get the syntax right.

 


Comment by: Christi (2/14/2014 10:10:12 PM)

Thanks for the great write-up. I've been doing a lot of VBA work with tables and this has been extremely helpful. Is there a way to pull the name of a selected table column? For example, if I've selected a cell in column I'd love to get back the address of the cell using the column name (i.e. @City) instead of "A12".

Thanks!

 


Comment by: Jan Karel Pieterse (2/17/2014 6:18:08 AM)

Hi Christi,

This should do:

Intersect(Activecell.entirecolumn,Activecell.ListObject.HeaderRowRange).Value

 


Comment by: John Mamuscia (2/28/2014 1:45:17 PM)

How would I delete columns from a table (ListObject) in Excel 2010?

 


Comment by: Jan Karel Pieterse (2/28/2014 2:07:11 PM)

Hi John,

I'd say:

ActiveSheet.ListObjects("Table1").ListColumns("Column1").Delete

 


Comment by: John Mamuscia (2/28/2014 6:21:54 PM)

Thanks....that works!

 


Comment by: mike fleuette (3/10/2014 10:38:32 PM)

I think what I am trying to do is very close to what you have here - but I am just not able to make it work.

In Excel 2010, I have a listobject ("Table_QUery_from_xxx") populated by a query against a SQL server database; it returns 50+ columns.

What I am looking for is:
a) how to identify which columns in the table have an AutoFilter applied, and
b) how to color the column heading (or the cell above it)

If you also have a way to populate the filter criteria to the cell above the column header, that would be great, but just highlighting the header is good enough for now.

I have seen many examples of how to do this with standard Excel, but not for ListObjects...

Any help is greatly appreciated!

Thank you -

 


Comment by: Jan Karel Pieterse (3/11/2014 7:07:59 AM)

Hi Mike,

Indeed, one of the examples is this one:
http://www.ozgrid.com/VBA/autofilter-criteria.htm

I modified it a bit to:
Option Explicit

Function AutoFilter_Criteria(Header As Range) As String
    Dim strCri1 As String, strCri2 As String
    Application.Volatile
    With Header.ListObject.AutoFilter
        With .Filters(Header.Column - .Range.Column + 1)
            If Not .On Then Exit Function
            strCri1 = .Criteria1
            If .Operator = xlAnd Then
                strCri2 = " AND " & .Criteria2
            ElseIf .Operator = xlOr Then
                strCri2 = " OR " & .Criteria2
            End If
        End With
    End With
    AutoFilter_Criteria = UCase(Header.Cells(1, 1)) & ": " & strCri1 & strCri2
End Function

Sub ShowAutofilters()
    Dim oCell As Range
    Dim sCrit As String
    For Each oCell In ActiveSheet.ListObjects(1).HeaderRowRange
        sCrit = AutoFilter_Criteria(oCell)
        oCell.Offset(-1).Value = sCrit
    Next
End Sub
    

 


Comment by: mike fleuette (3/11/2014 10:19:26 PM)

Thank you so much - that is exactly the information I was seeking!

Quick question - how does VBA account for multiple criteria? In Excel 2007+, you can have multiple filter criteria (e.g. =A, B, or C)

Is there a trick to capturing that criteria? I notice that it pops-up when I hover over an autofilter arrow on the header line...)

Again, thank you!

 


Comment by: Maree (3/12/2014 8:39:07 AM)

Hi Jan

This would seem a very general question but what would be most likely cause of a macro written in Excel 2003 using the List functionality not running over in Excel 2013 if left unmodified?

 


Comment by: Jan Karel Pieterse (3/12/2014 9:32:51 AM)

Hi Mike,

The code I gave is basically for Excel 2003. Excel 2007 and up have more elaborate filter capabilities, the code would need a rewrite to cater for those.

 


Comment by: Jan Karel Pieterse (3/12/2014 9:33:41 AM)

Hi Maree,

Without seeing the code that is impossible to answer I'm afraid.

 


Comment by: mike fleuette (3/12/2014 2:31:21 PM)

Jan - thank you for your help. Is there a good online reference for ListObject(s) and its attributes and methods? Specifically, I am looking for one that describes how multiple criteria are stored and what flags/attributes indicate what about the criteria...

Again, thank you -

 


Comment by: Jan Karel Pieterse (3/12/2014 5:25:25 PM)

Hi Mike,

I wouldn't really know. But the macro recorder does help when you're trying to figure out stuff like this :-)

 


Comment by: Maree (3/13/2014 12:43:04 AM)

Hi Jan

What this is doing is that it is copying rows from a Pivot Table into a table (ListObject). This is dynamic so the number of rows can vary (the columns do not). There is another procedure which will clear out any surplus lines. I can't quite see where this is going wrong.

Private Function Macro _Try_To_Match_A_Row_In_Destn_Table()
    
    activeProcedureName = " Macro _Try_To_Match_A_Row_In_Destn_Table "
    
    On Error Resume Next
    
    'note that there appears to be a functionality difference in lists between Excel 2003 and 2007, in that the range in 2003 includes the insert row whereas presumably in 2007 it does not.
    matchResult = Application.Evaluate("MATCH(" & subProjectDescription & "," & destnListObject.ListColumns(4).Range.Address(, , , True) & ", 0)")
        
    If IsError(matchResult) Then
            On Error GoTo 0
             aRowMatchWasFoundForSubProjectDescription = False
        
        Call Macro_Insert_Data_From_Source_Row_At_End_Of_DestnTable()
    Else
        On Error GoTo 0
        aRowMatchWasFoundForSubProjectDescription = True
        
    End If
End Function

 


Comment by: Maree (3/13/2014 12:43:33 AM)

Hi Jan

Part 2 of 2 (continued from above)
Private Function Macro_Insert_Data_From_Source_Row_At_End_Of_DestnTable()
    
    activeProcedureName = " Macro_Insert_Data_From_Source_Row_At_End_Of_DestnTable()"
                
    destnListObject.Parent.Parent.Activate
    destnListObject.Parent.Activate
    destnListObject.Range.Activate
        
    matchResult = destnListObject.InsertRowRange.Row - destnListObject.Range.Row + 1
    
    
    destnListObjectRowCountB4InsertingARow = destnListObject.ListRows.Count
    If destnListObjectRowCountB4InsertingARow = 0 Then
        GoTo ThereIsNotADummyRowAlreadyAtTheEndOfTheTable
    ElseIf IsError(destnListObject.ListRows(destnListObjectRowCountB4InsertingARow).Range.Cells(1).Value) Then
        GoTo ThereIsNotADummyRowAlreadyAtTheEndOfTheTable
    ElseIf destnListObject.ListRows(destnListObjectRowCountB4InsertingARow).Range.Cells(1).Value <> "dummy value" Then
        GoTo ThereIsNotADummyRowAlreadyAtTheEndOfTheTable
    End If
    
    If False Then
ThereIsNotADummyRowAlreadyAtTheEndOfTheTable:
        Set destnCell = Nothing: Set destnCell = destnListObject.InsertRowRange.Cells(1)
                destnCell.Value = "dummy value"
        If destnListObject.ListRows.Count < destnListObjectRowCountB4InsertingARow + 1 Then
            MsgBox "There was a problem adding a row to the destination table.", vbOKOnly
            Call Macro_Stop
        End If
    End If
    
    If IsEmpty(aRowMatchWasFoundForSubProjectDescription) Then
        aRowMatchWasFoundForSubProjectDescription = False
    End If
    
    Exit Function

End Function

 


Comment by: Jan Karel Pieterse (3/13/2014 6:52:32 AM)

Hi Maree,

For Excel 2007 and up there is no such thing as an InsertRowRange for a listobject, so you have to act accordingly:

Private Function Macro_Insert_Data_From_Source_Row_At_End_Of_DestnTable()
    Dim bNoDummyRow As Boolean
    activeProcedureName = " Macro_Insert_Data_From_Source_Row_At_End_Of_DestnTable()"
    Set destnListObject = ActiveSheet.ListObjects(1)
    destnListObject.Parent.Parent.Activate
    destnListObject.Parent.Activate
    destnListObject.Range.Activate
    If Val(Application.Version) = 11 Then
        matchResult = destnListObject.InsertRowRange.Row - destnListObject.Range.Row + 1
    Else
        matchResult = destnListObject.Range.Cells(destnListObject.Range.Rows.Count, 1).Offset(1).Row
    End If


    destnListObjectRowCountB4InsertingARow = destnListObject.ListRows.Count
    If destnListObjectRowCountB4InsertingARow = 0 Then
        bNoDummyRow = True
    ElseIf IsError(destnListObject.ListRows(destnListObjectRowCountB4InsertingARow).Range.Cells(1).Value) Then
        bNoDummyRow = True
    ElseIf destnListObject.ListRows(destnListObjectRowCountB4InsertingARow).Range.Cells(1).Value <> "dummy value" Then
        bNoDummyRow = True
    End If

    If bNoDummyRow Then
        Set destnCell = Nothing
        If Val(Application.Version) = 11 Then
            Set destnCell = destnListObject.InsertRowRange.Cells(1)
        Else
            Set destnCell = destnListObject.Range.Cells(destnListObject.Range.Rows.Count, 1).Offset(1)
        End If
        destnCell.Value = "dummy value"
        If destnListObject.ListRows.Count < destnListObjectRowCountB4InsertingARow + 1 Then
            MsgBox "There was a problem adding a row to the destination table.", vbOKOnly
            'Call Macro_Stop
        End If
    End If

    If IsEmpty(aRowMatchWasFoundForSubProjectDescription) Then
        aRowMatchWasFoundForSubProjectDescription = False
    End If
End Function

 


Comment by: Maree (3/14/2014 4:35:09 AM)

Hi Jan
Thank you for your response. I am trying to read a table range of cells from one table to another. Transitioning over from Excel 2003 to 2007 there is an error however which prevents this from happening for me.

preexistWksh.Evaluate("OFFSET(" & ActiveSheet.Evaluate("TopLeftCornerOfTheListOfReportData").Address(referenceStyle:=IIf(ReferenceStyleA1, xlA1, xlR1C1)) & ",1,0,COUNTA(" _
                & ActiveSheet.Evaluate("TopLeftCornerOfTheListOfReportData").Address(referenceStyle:=IIf(ReferenceStyleA1, xlA1, xlR1C1)) & ":INDEX(" _
                & nameInReportOfResultsOutputSheet & "!" _
                & RangeReference _
                & ",65536,1))-1,MATCH(""" & cHeadernameOfColumnOnSourceAndDestSheetsToUpdateWithDateTimeRowWasLastProcessed _
                & """," & ActiveSheet.Evaluate("TopLeftCornerOfTheListOfReportData").Address(referenceStyle:=IIf(ReferenceStyleA1, xlA1, xlR1C1)) & ":INDEX(" _
                & nameInReportOfResultsOutputSheet & "!" _
                & RangeReference _
                & ",ROW(TopLeftCornerOfTheListOfReportData),256),0))" _
            ).Select
            
            If Err.Number <> 0 Then
                MsgBox "Could not identify the range of cells containing data on worksheet '" & nameInReportOfResultsOutputSheet & "' in the workbook which contains the previous report..", vbCritical
                Call Macro_Stop
            End If

 


Comment by: Jan Karel Pieterse (3/14/2014 11:59:33 AM)

Hi Maree,

Rather than trying to figure out what your macro is doing: can you perhaps decribe what it is supposed to do?

 


Comment by: Maree (3/17/2014 1:01:35 AM)

Hi Jan

The macro is updating a report between Month A and Month B.

Some code is already in place to populate Month B and this code here is to select the full range from the report of Month A. You will see that this is an offset (sans one row, the title row) formula that should be capturing all rows and all applicable columns.

When this range is selected, Month B's report is updated with certain fields from the report of Month A (more code). I can't get to this point however.

 


Comment by: Jan Karel Pieterse (3/17/2014 6:48:10 AM)

Hi Maree,

If the range you are about to copy is a listobject, the code can be greatly simplified I expect. To select just the data of a listobject all you need is:

Worksheets("TheSheetToCopy").ListObject("ListObjectName").DataBodyRange


If it isn't a listobject, it depends whether there is more on the sheet. If all information is needed, you simply use:

With Worksheets("TheSheetToCopy")
    .UsedRange.Offset(1).Resize(.usedrange.rows.count-1)
End With


That's it.

 


Comment by: John Mamuscia (3/24/2014 11:41:09 PM)

JKP, thanks for the tutorial on using tables. I am using Excel 2010 and have a table defined. I then apply an autofilter to it and now want to loop through the visible rows and utilize the column names to get their values. I have been unable to find anything in web searches and was hoping you could explain how to do this. Thus far in my code I am able to get the autofilter to work and get the number of rows left visible, but how do I then loop through those visible rows and use the column names that are defined in the table? Thanks for any leads or ideas.

 


Comment by: Jan Karel Pieterse (3/25/2014 7:09:55 AM)

Hi John,

You can use the specialcells method of the range object:

    Dim oCell As Range
    For Each oCell In ActiveSheet.ListObjects(1).ListColumns(1).DataBodyRange.SpecialCells(xlCellTypeVisible)
        MsgBox Intersect(oCell.EntireRow, ActiveSheet.ListObjects(1).ListColumns("a").DataBodyRange).Value
    Next

 


Comment by: John Mamuscia (3/25/2014 3:55:58 PM)

Thank you, that works!

 


Comment by: Scott Marshburn (3/30/2014 11:24:13 PM)

How would one go about finding the next empty row in a table in excel 2013

 


Comment by: Jan Karel Pieterse (3/31/2014 6:56:46 AM)

Hi Scott,

This is irrespective whether you are in a true table or on a normal range. Suppose you have a variable oCell pointing to a cell. This line of code pust the next empty cell (downwards) into that variable:

If Not IsEmpty(oCell.Offset(1).Value) Then
Set oCell = oCell.End(xlDown).Offset(1)
Else
Set oCell = oCell.Offset(1)
End If

 


Comment by: Zack Barresse (4/21/2014 8:51:49 PM)

Remember, Jan Karel's code will bring you to either the next empty cell, or the last cell of the table, or the total row if it is showing. If you're setting a Range object, I'd recommend setting the ShowTotals property to False, then adding your rows, then turning it back on. Otherwise you're just changing the total cell.

 


Comment by: Jason Gross (4/24/2014 4:09:43 PM)

How can we select a single cell, or get the value. This does not seem to work.
Range("Table1[[5],[Column2]]").Select
Range("Table1[[5],[Column2]]").Value
Thanks,
Jason

 


Comment by: Jan Karel Pieterse (4/28/2014 10:10:42 AM)

Hi Jason,

Like so:

ActiveSheet.ListObjects("Table1").ListColumns("Column1").databodyrange.Rows(5).Value

 


Comment by: Zack Barresse (4/28/2014 8:20:35 PM)

You can get it many ways. Most common is the DataBodyRange object, which you can use like the Cells object, as it returns a Range object. An example of this is something like...

    ActiveSheet.ListObjects("Table1").DataBodyRange(1, 1)

You won't get intellisense from the above though, just like the Cells object.

As far as your specific request, Jason, there's really no need to select anything. If you want to work with an entire column, you can use the ListColumns object. This (as well as the ListRows object) is a little different from the DataBodyRange, in that it doesn't return a Range object. To access that you must specify it. Also note this method will include the header and total rows if they're showing. Here is an example...

    ActiveSheet.ListObjects(1).Range.Select

If you *only* want the body, specify it like so...

    ActiveSheet.ListObjects(1).DataBodyRange.Select

These examples are selecting the ranges, but like I said, you don't need to select it to work with it.

 


Comment by: Jon DeBas (5/11/2014 6:09:29 AM)

Hi Jan,
A great article.
Simple question which nobody seems to be addressing. I'm selecting only some rows in a Table trying to sort only these rows (e.g. rows 11 thru 75 in a 200 row table), but when I hit Sort Excel always overrides my selection by selecting all the rows in the table instead. The same thing happens in VBA. I'm using Excel 2007.
Am I missing something
Thanks,
Jon

 


Comment by: Jan Karel Pieterse (5/11/2014 8:26:06 PM)

Hi Jon,

I don't think you can sort only part of a table. Perhaps an easy workaround is to copy those rows elsewhere, sort them and then copy them back into the table.

 


Comment by: PONS Patrice (5/12/2014 12:15:52 PM)

Hi Jan
Sorry for my english.

I have a table with 100000 rows and i wanna delete many rows with criteria about a date in column 3.
That table is a MSQUERY extract and format date is AAAAMMJJ (ex 20140423).
I just wanna have datas from now to 90 days past.
Very difficult challenge for me.
I can apply filters manually but can't in vba.
Thanks for your support

 


Comment by: Jan Karel Pieterse (5/12/2014 1:58:56 PM)

Hi Patrice,

Your English is fine :-)

Can't you apply a filter to the query, instead of doing this afterwards in Excel? That would make more sense to me.

 


Comment by: PONS Patrice (5/12/2014 3:28:09 PM)

Hi Jan

Thank you for your answer
I try to filter my query in vba and it works.
The problem was date format.

Best Regards :)

 


Comment by: Rudi (6/5/2014 9:25:05 AM)

Hi Jan Karel,

TX for an awesome website. I use the info on your site quite frequently for reference purposes. I have one question. In this article about using the ListObject, you have some great references to selecting parts of a table. Is there a chance that you can include a reference to selecting the last row and the last column of a ListObject too.

Above you have this...

With oSh.ListObjects("Table1")
     'Select just row 4 (header row doesn't count!)
     .ListRows(4).Range.Select
End With


I tried to select the last row like this (If memory serves correctly, but it debugged)

     .ListRows(.ListRows.Count).Range.Select


How does one select the last row and last column of a table.
TX

 


Comment by: Jan Karel Pieterse (6/5/2014 10:27:49 AM)

Hi Rudi,

I suppose this should work (it did on my system):

With ActiveSheet.ListObjects("Table1")
'Select last row
.ListRows(.listrows.count).Range.Select
End With

    With ActiveSheet.ListObjects("Table1")
        'Select last cell of table
        Intersect(.ListRows(.ListRows.Count).Range, .ListColumns(.ListColumns.Count).Range).Select
    End With

 


Comment by: Rudi (6/5/2014 12:26:08 PM)

TX for the speedy reply.

I must have had something else wrong in the macro that I recall...
Anyways, TX for your examples. I'll be sure to try them again.

Cheers

 


Comment by: Cody (7/22/2014 4:12:44 PM)

Hi,

I am working with Tables in VBA and had a question.

What I am trying to do is autofill a table range with the upper left corner fixed and the bottom right corner variable. Variable only in terms of more or less columns, rows are fixed with my method.

In my code I set the first cell equal to a formula
Next line I select the cell
Next line I attempt to auto fill

Here is a code I know works but is not variable:


Range("C15").Select
ActiveCell.FormulaR1C1 = "=Inputs!R3C5-Table1[@1]*R1C29"
Range("C15").Select
Selection.AutoFill Destination:=Range("Table3[[1]:[14]]"), Type:= _
        xlFillDefault



Here is the code I am trying to change it into:


Dim num as integer
num = 14                 '''Could be any input number'''

Range("C15").Select
ActiveCell.FormulaR1C1 = "=Inputs!R3C5-Table1[@1]*R1C29"
Range("C15").Select
Selection.AutoFill Destination:=Range(Table3[[1]:[num]]), Type:= _
        xlFillDefault



I took away the "" within the range because it would not treat num as an integer and said invalid object.

Any suggestions on how to make this work, or an alternate approach?

Thanks in advance!!

 


Comment by: Ted Pettit (7/25/2014 5:50:22 PM)

Let's say you have a table (we'll call it Table1) with the following columns:
|Date|Time|Area|Technician|Activity|Completed|Delayed|Canceled|Reason|Current Status|
But you only want to perform some VBA function on the columns labeled Completed, Delayed, and Canceled, use this syntax:
Range("Table1[Completed]:Table1[Canceled]")
To include an additional column that is not adjacent i.e. the "Current Status" column to the previous selection, use this syntax:
Range("Table1[Completed]:Table1[Canceled],Table1[Current Status]")

 


Comment by: Eugenio (7/29/2014 4:49:34 AM)

Please,
Using a unique cell, how do i get its index row in a table (not the row number into the sheet) and how do i get a cell value by this index and a column name?
Thank you very much.

 


Comment by: BobJordanB (8/3/2014 6:01:56 AM)

Tables seem to be just what I want but cannot quite see how to do it.

I want to create a table of operations in Excel with half a dozen columns describing the parts of each operation.
In my vba I want to process each of the rows in turn using the column values as 'instructions'.

to be specific the table (here Named as Table) defines a sequence of parameter changes ( a start, an end, an increment and a sheet location as columns) (and a sequence of these in the rows) which in turn control a chart display. At each parameter change I save the modified chart as a png and then combine the pngs (in an AVI) to become a movie.
But cannot see a tidy way to refer to the columns by name.

Here is some pseudocode that uses a constructed table access command


For Each thisRow in Table.Rows
For myParam = Table.thisRow.[pStart] to Table.thisRow.[pEnd] step Table.thisRow.[pinc]
     Range(Table.thisRow.Locn) = myParam
     Calculate
     Export Chart
    Next myParam
Next thisRow


But cannot seem to find a way to tidily refer to the row elements using their column names.

Is their a way of referring to a row column intersection using something like:

    Table,thisrow,columnName OR Table(thisrow,[columnName]) etc.?

I could use Offsets to get to the row/column but this will require me to name each column separately which seems to be unnecessary as the naming has already been done

You can for example refer to the 'Thisrow' or @ row but that is for formulae in the table itself.

Is this possible?

The code works in a non-table format but I believe it can be made more readable

Any thoughts appreciated

Bob J.

 


Comment by: Bob Jordan (8/7/2014 1:02:33 PM)

I tried to post a question on accessing the rows of a table but it seems to have got lost

meantime I have solved this problem and would like to share it with you.

How to work through the values in the rows of a table in vba

Turns out there is a nice construct.

row 3 of column ID of table Table1 is: Range("Table1[ID]")(3)

Rows go from 1 to Range("Table1").Rows.Count

If you have a single row table (for parameters etc you can skip the Row number part ie Range("Params[Colour]") gives you the first item below the heading.

This is very readable and conforms to the usual rules. you can append .text, .formula etc

You might like to add this to your help page.I searched hard to find this and it seems unknown. Please help others like me.

Bob JordanB

 


Comment by: Jan Karel Pieterse (8/11/2014 7:14:47 PM)

Hi Bob,

Thanks for sharing!

 


Comment by: Jan Karel Pieterse (8/12/2014 11:12:33 AM)

Hi Cody,

I expect this is a better approach:

Range("C15").resize(num).FormulaR1C1 = "=Inputs!R3C5-Table1[@1]*R1C29"

 


Comment by: Prateek Chauhan (8/22/2014 9:54:22 AM)

why do my links are not being copyied to a table of a worksheet, from another table.... though it can be copied to a cell that is not in table in the same sheet. i.e only value is getting in a cell of a table not the link through vba( link := true, has been used while paste).
Please do help on urjent basis.
thankyou

 


Comment by: Adam (8/27/2014 5:17:21 PM)

Hello,

This is great article - thank you! Unfortunately I did not find any PASTE tips. Could you explain how to paste into existing table, into specific column?

What I try to do is deleting data part of table and pasting new data into the table. Part of my table is data, another part is formulas calculating the data.

The code for deleting is working:

    
With Sheet1.ListObjects("Tabela1").Range
        Set Rng = .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
        Rng.Delete
    End With


Copying is working too.

Then I try to paste with code:
With Sheet1.ListObjects("Tabela1")
        .ListColumns("[DataColumn]").PasteSpecial Paste:=xlPasteValues
     End With


Unfortunately it shows 'Subscript out of range' :[

Could you advice where the problem is?

 


Comment by: Jan Karel Pieterse (8/27/2014 5:27:49 PM)

Hi Adam,

Perhaps it should be:

.ListColumns("DataColumn").PasteSpecial Paste:=xlPasteValues


so without square brackets.

 


Comment by: Adam (8/27/2014 9:50:06 PM)

Thanks. In fact the name of column is "Data Column" (with space between words). That's why there are square brackets.
Still I do not have an idea why it does not work.

 


Comment by: Adam (8/27/2014 9:55:18 PM)

Is it possible the problem is because I copy 5 columns and in the code I mention only one (as a 'start point' for pasting)?

 


Comment by: Jan Karel Pieterse (8/28/2014 10:15:05 AM)

Hi Adam,

What if you rewrite that to:
    With Sheet1.ListObjects("Tabela1")
        .ListColumns("Data Column").DataBodyRange.Cells(1, 1).PasteSpecial Paste:=xlPasteValues
    End With

 


Comment by: Adam (8/28/2014 10:50:22 AM)

Thank you. I ended up with pasting into table as no luck with this solution. I will try to paste 'normally' without a table.
The solution that worked for me (with unaccepted, poor efficiency) is: (deleting, copying, pasting)

With Sheet3.ListObjects("Tabela1")
    If .ListRows.Count > 0 Then
        .DataBodyRange.Delete
    End If
End With

    With Sheet1
        LR = .Range("B" & Rows.Count).End(xlUp).Row
        .Range("B5:M5" & LR).Copy
    End With

With Sheet3.ListObjects("Tabela1")
    .Range.Resize(1, 1).Offset(1).PasteSpecial Paste:=xlPasteValues
End With

Unfortunately it takes 15 minutes for 2K rows. When I do it manually it takes 30 seconds. The problem is the columns that include formulas are spread into 50K rows after pasting (I do not know why) and then 2K rows of pasted data are added. The table that should be 2K rows big is 52K rows big after pasting. 50K of rows are empty but include formulas, which makes the file slow and inefficient.

 


Comment by: Jan Karel Pieterse (8/28/2014 11:31:45 AM)

Hi Adam,

Perhaps the copy operation copies more than you are expecting? STep through the code up until the Copy command, execute the copy step and go to Excel to see which area is surrounded by the marching ants marquee.

 


Comment by: Adam (8/28/2014 12:16:16 PM)

You are right Master!
This last "5" in .Range("B5:M5" & LR).Copy
made the range so big.
Corrected - works.
Thank you verrry much!

 


Comment by: Alberto Viveros (8/28/2014 7:32:30 PM)

Hi, I have an Excel file that contains 105,000 records, and the user adds manually more data daily; but some of the new data have incomplete fields, and I need to create a macro to update the missing fields automatically when the user saves the file. For example, some of the missing data are the material group and the customer class, but I can read the values from the existing records in the same file. So I am thinking in create a macro that converts all the spreadsheet in a table, and in some way updates the missing fields from the existing records that contain information. For example, the table contains in some record the material "ABC" with the Category "Finish Products", and the user adds new records with material "ABC" with the Category empty. How can I update the new records from the existing records using tables?. If I design a macro to update one by one record, it will be very slow. In SQL I would use something like this:

Update n
SET n.Category = o.Category
From Table n
INNER JOIN Table o ON
n.Material = o.Material And o.Category <> ''
Where n.Category = ''

Is it possible to update in mass something like this in Excel Tables?

I appreciate you help, thanks.

 


Comment by: Jan Karel Pieterse (8/30/2014 11:49:10 AM)

Hi Alberto,

In Excel you would select the blank cells and enter a VLOOKUP formula in them to get the missing information and after that copy, past sepcial values to "fix" them. This is not hard to code.

 


Comment by: Alberto Viveros (9/2/2014 3:12:03 PM)

Thank you Jan, at the end I included in the macro a VLOOKUP formula for all the cells that had incomplete data, and it worked well. The code is simpler and the macro works faster. Thank you very much.

 


Comment by: Alonso (10/22/2014 2:31:12 PM)

Hi Jan,
Your page looks great.
I'm trying to insert 3 new columns to an existing Table (Table1).
I named the first new column as [NEWCOLUMN1] and has a formula "= (RIGHT(TABLE1[ACCOUNT ],3))" ACCOUNT already exist into Table1. When I add it, it works perfectly well.
The Second new Column named as [NEWCOLUMN2] has a formula =""
The Third new Column named as [NEWCOLUMN3] has a formula
which refers to NEWCOLUMN2 and NEWCOLUMN1
.Formula = "=(IF(TABLE1[NEWCOLUMN2]="""",TABLA1[NEWCOLUMN1],TABLA1[NEWCOLUMN2]))".
When I add the columns though VBA the table calculates perfectly well the result in the first step but It occurs something very strange. When I change an ACCOUNT data NEWCOLUMNS1 refresh perfectly well the new result but NEWCOLUMNS3 as it is referred to newColumns added it seems they do not recognize it and there is no refresh. It only works if you press F2 into the cell, then it recalculate.
I thought the problem was to resize the table after adding columns but even in such case it doesn't works.
Finnaly I tried to create the formula after adding and resizing table but It does not refresh anyway.
Where can be the problem?
Thank you in advance for the support

 


Comment by: K. Robert Rhodes (10/22/2014 5:24:46 PM)

I'm wondering when and whether we *must* use the Listobject Methods and Properties when dealing with Excel Tables versus the usual range-based programming we have developed over the years.

So far it looks like they are interchangeable, as long as you don't need the specific methods and properties unique to the ListObject. For example, ActiveCell.EntireRow.Delete seems to work fine when the ActiveCell is inside a ListObject's range. I.e., the table size (including changes to visible formats regarding banding) seems to properly update.

But I have seen no documentation from Microsoft that indicates when it is "safe" to do such things, or if treating ranges within a table as if they were simply ranges can get us into trouble or perhaps corrupt the ListObject.

If any of that made sense, I'm wondering if anyone has any thoughts on the matter.

 


Comment by: Jan Karel Pieterse (10/23/2014 7:05:26 AM)

Hi Robert,

Valid question of course. As far as I can tell, you are not obliged to use the ListObject when working with ranges inside a table, if you don't want to.

It is just that the ListObject gives you things like named columns and you do not need to know the starting address of a listobject to work with it. It sort of makes it unnecesary to use named ranges when addressing specific areas of an Excel model from VBA if you want to have the flexibility of changing the design of the Excel model without wrecking code like this:

sSomeValue = Worksheets("Sheet1").Range("B25").Value

 


Comment by: Jan Karel Pieterse (10/23/2014 7:10:36 AM)

Hi Alonso,

It looks like your formulas are all addressing entire table columns and not working with the row in question, perhaps that is the problem? Try adjusting the formulas so they point to the table row in question by adding @:

"= (RIGHT(TABLE1[@ACCOUNT ],3))"

 


Comment by: Alonso (10/23/2014 12:55:38 PM)

Hi Jan
I also did a second test as follows
Sub Test2()
Dim Table As ListObject
Dim LC As ListColumn
Dim col As Integer
Dim i As Integer
' I have a table named Table1 with a column named ACCOUNT

' I want to add 3 Columns
For i = 1 To 3
         'Refer the tables
            Set Table = ActiveSheet.ListObjects("Table1")
         'Add a column to Table1
            Set LC = Table.ListColumns.Add

Select Case i 'Set the header and write the formulas
        Case 1
        LC.Name = "NCOL1"
        LC.DataBodyRange.Formula = "=(RIGHT(TABLE1[@ACCOUNT],3))"
        Case 2
        LC.Name = "NCOL2"
        LC.DataBodyRange.Formula = ""
        Case 3
        LC.Name = "NCOL3"
        LC.DataBodyRange.Formula = "=(IF(TABLE1[@NCOL2]="""",TABLE1[@NCOL1],TABLE1[@NCOL2]))"
End Select

Next i

'With this test you can see the same result. NCOL1 gives a result which refresh when you change column Account but NCOL 3 Does not refresh
End Sub


None of them Works.
Is there any kind of refresh for List Object which I didn't consider or any extra code that I can include to refresh automatically results from table once I change any data inside?

 


Comment by: Jan Karel Pieterse (10/23/2014 4:59:52 PM)

Hi Alonso,

Weird. Seems like a bug.
If you hit control+alt+shift+F9, then the formula starts to behave itself and updates on changes as expected. In VBA you could add an
Application.CalculateFullRebuild

at the end to make it work.

 


Comment by: Diana G (12/11/2014 5:26:53 AM)

I am so glad I found this page! I have been hunting high and low for my exact scenario and this is the first page that is not years old. I am no VB expert, but I am trying to write a macro using VB that will create a table, HOWEVER, the table is one of 3 on the same sheet AND it will vary in size each time it is created.

The table will always reside in A and B.
The rows may span anywhere from 5 to 85 down.

So the entire range will vary each time the macro is run.
The other table macros work perfect - their size is absolute, but the columns A & B will always have different results.

I have tried the {Dim lastRow As Long}
I have tried the {Set DynamicRange = Range("A2").CurrentRegion}

Neither are working.
Every time, the range table will be named Table3.

My code looks like:

Range("A1").Select
    ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$1:$B1"), , xlYes).Name = _
        "Table3"

I am beginning to believe you cannot use a Macro or VBA to insert a table if the range varies each application.

Any guidance would be greatly appreciated.
This is the only code I am missing to complete my project.

 


Comment by: Jan Karel Pieterse (12/11/2014 7:04:26 AM)

Hi Diana,

So how would we know what range of cells must be converted to a table? How would you select the cells using your keyboard? (e.g. select A1 and press control+shift+down, shift right, or select the last row on column A and press control+Up)

 


Comment by: Diana G (12/11/2014 6:10:51 PM)

Thank you for responding Jan.
I apologize, I know very little about VBA - I am not a programmer.

I think I understand your inference with the (select A1 and press control+shift+down, shift right, or select the last row on column A and press control+Up) scenario.

I suspect you are telling me that code can be written for these instructions. Unfortunately I have no idea what those are.

I did find this code last night and it was working. However, when I run it, it always wants to rename my table from Table3 to Table3_1 Then I changed everything in my code to reference Table3_1 and now when I run it changes the table name to Table3_2. I am at a loss. Perhaps someone can tell me where my code is getting these instructions and how to fix?

Here is my entire code for this particular action:


{Sub EICAddTable3Sheet2()

    Dim FinalRowNew As Integer

    FinalRowNew = Range("A" & Rows.Count).End(xlUp).Row

    Range("A1:B" & FinalRowNew).Select

    ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$1:$B$" & FinalRowNew), , xlYes).Name = _
    "Table3"
        
    Range("Table3[#All]").Select
    ActiveSheet.ListObjects("Table3").TableStyle = "TableStyleMedium17"

End Sub

 


Comment by: Jan Karel Pieterse (12/12/2014 6:40:47 AM)

Hi Diana,

I intended that as a question to find out how to propose the right code :-)

About the name: I suspect there already is a table named Table3 in your workbook, table names must be unique across the entire workbook.

 


Comment by: Jim K (12/16/2014 6:19:06 AM)

Hi Jan,

Excellent page! Very helpful indeed.
I have a question however that isn't dealt with yet. I have a table that has different formats for different columns. I want to insert columns at column position 30 that copies the format from the column that is already there, which becomes column 31, but also automatically set the totalrow to calculation type=1.(that is to sum the data content). I have been trying a few things but the code does not appear to execute ( being ignored). Can you make any suggestions?
Many thanks in advance

Jim

 


Comment by: Jan Karel Pieterse (12/16/2014 5:22:34 PM)

Hi Jim,

What does the macro recorder give you and what happens if you run the recorded macro?

 


Comment by: Jim K (12/17/2014 5:52:16 AM)

when I do the macro recording I get for the subtotal
<VB>ActiveSheet.ListObjects("Table3").ListColumns("Column2").TotalsCalculation = _
        xlTotalsCalculationSum</VB>
But when I run this code, at the end of the column insert the column gets inserted but the subtotal not
(By the way the same applies to the copy of the table header format. VBA ignores it)

Jim

 


Comment by: Jan Karel Pieterse (12/17/2014 9:05:11 AM)

Hi Jim,

I suspect this is because the newly inserted column's name is different from the one your code recorded?

 


Comment by: Jim K (12/17/2014 12:18:29 PM)

No, that is not it.
The newly inserted column's name is Column2
I have a hidden column to the left of it which name is Column1, all other columns have more specific names.

 


Comment by: Jan Karel Pieterse (12/17/2014 12:48:00 PM)

Hi Jim,

The code in itself runs just fine if I try it on a listobject named Table3 on any worksheet.

Is the totalrow set to show for that table?

 


Comment by: Jim K (12/20/2014 1:29:38 PM)

Hi Jan,

Thank you for your help. I've got it working now.
My insert routine, did not insert a table column but a sheet column. Once that part was fixed, the code for the total worked fine. The only thing I still need to do is color the header cell the same as the neighbouring cell in position 31

Cheers,
Jim

 


Comment by: Tom-S (12/20/2014 10:45:39 PM)

Hi Jan,

The following is a snip from an Excel VBA module. On the "Data Ranges" sheet are several Excel Tables and I want to go through a subset of them, where the first 2 steps are to clear out the data and then resize the Tables so they have header row plus 1 blank data row.

The code seemed to be running ok until I tried it again recently in Excel 2013. The data clear out works ok but at the last line of code shown Excel crashes and shuts down. Any idea why it crashes and how to fix this?


Option Explicit

Dim LobjA(1 To 5) As ListObject
Dim w As String, x As String, z As Integer

Sub db_update()

w = Application.GetOpenFilename

Workbooks.Open (w)

x = Right(w, Len(w) - InStrRev(w, "\", , vbTextCompare))

Set LobjA(1) = Workbooks(x).Sheets("Data Ranges").ListObjects("Table1")
Set LobjA(2) = Workbooks(x).Sheets("Data Ranges").ListObjects("Table4")
Set LobjA(3) = Workbooks(x).Sheets("Data Ranges").ListObjects("Table6")
Set LobjA(4) = Workbooks(x).Sheets("Data Ranges").ListObjects("Table7")
Set LobjA(5) = Workbooks(x).Sheets("Data Ranges").ListObjects("Table8")


For z = 1 To 5

    LobjA(z).DataBodyRange.Value = ""

    LobjA(z).Resize LobjA(z).Range.Resize(2)


Regards, Tom

 


Comment by: Jerry Paladino (12/21/2014 4:46:11 PM)

Hi Jan,

When creating a Table in VBA with something like...

ActiveSheet.ListObjects.Add(xlSrcRange, Range("$B$1:$D$16"), , xlYes).Name = "Table1"


The table becomes a Defined Name in the Name Manager. Is it possible to make this Defined Name hidden to prevent the end user from seeing its contents and location.

Thank You,
Jerry

 


Comment by: Jim K (12/21/2014 9:45:43 PM)

Hi Jan

Below code works in Excel 2013 but not in Excel 2010
Any suggestions

Sub insCol()
Dim oSh As Worksheet
    Set oSh = ActiveSheet
    oSh.ListObjects("Table3").ListColumns(3).Range.Select
    Selection.ListObject.ListColumns.Add Position:=3
    oSh.ListObjects("Table3").HeaderRowRange(3) = InputBox("Enter the month and year for the header of this new column", "inserting new month column") & " No of Sessions"
    oSh.ListObjects("Table3").ListColumns(3).TotalsCalculation = xlTotalsCalculationSum
End Sub

 


Comment by: Jan Karel Pieterse (12/22/2014 11:05:51 AM)

Hi Jim,

Your code works fine for me on my Excel 2010. Are you sure:

- The activesheet contains the listobject
- The listobject has the correct name
- The listobject has the totalrow showing?

 


Comment by: Jan Karel Pieterse (12/22/2014 11:07:28 AM)

Hi Jerry,

I'm afraid table names cannot be hidden.

 


Comment by: Jan Karel Pieterse (12/22/2014 11:13:21 AM)

Hi Tom,

Rather than putting an empty string in the databodyrange (which does not actually empty the cells!) I would clear them:
LobjA(z).DataBodyRange.Clear

Other than that, I suspect a problem with the workbook in question, the code seems alright to me.

 


Comment by: Jim K (12/23/2014 2:34:37 AM)

Hi Jan,

I checked that the active sheet contains the listobject
The listobject has the correctname and the totalrow is showing
I have noticed that the code works in a spreadsheet with less rows but the same number of columns
The funny thing is that the column gets inserted in the right position however it stretches way beyond the table
There is some activity prior to the insert and then the code just exits. Putting a trace and using a variable to store the new column, this variable never gets "filled"

 


Comment by: Jan Karel Pieterse (12/23/2014 11:33:09 AM)

Hi Jim,

What if you copy the table and paste-special values to another workbook and then format that as a table and rename the table accordingly? Does the code run without a problem then?

 


Comment by: Jim K (12/24/2014 5:15:42 AM)

Hi Jan

Just discovered that the problem was a UDF that I used to conditionally format all cells with a formula in it. Once I removed this UDF, the code ran without problems

Have a great Christmas and all the best for 2015

Jim

 


Comment by: Jan Karel Pieterse (12/24/2014 10:00:29 AM)

Hi Jim,

Thanks for letting us know!

 


Comment by: Chad (1/9/2015 9:13:09 PM)

I am trying to build an excel document that pulls information based of the following:
I have multiple "kits" that are made up of number of parts with descriptions, part numbers and quantities which are stored in a table form and fall under a specific kit name.
I would like to select a kit by name from a Listbox and the information pertaining to that kit is placed inside a specified table location.
I have been working on this for a number of days without success.
Thank you for any help you may be able to give.

 


Comment by: Jan Karel Pieterse (1/9/2015 10:19:41 PM)

Hi Chad,

Sounds like you would need a pivot table for that which you filter for the kit name.

 


Comment by: John (1/23/2015 8:16:17 PM)

I have a macro i run to place the contents of the cell into a comment on the cell. Macro was included in the cell menu. I have read your other menuing articles and I can add the menu to the cell menu .. as long as it is not in a table.. Suggestions?

 


Comment by: Jan Karel Pieterse (1/27/2015 7:26:09 AM)

Hi John,

The right-click menu you need is called "List" I expect.

 


Comment by: Jeff Weir (3/11/2015 6:36:09 AM)

Hi Jan Karel. Good idea in your RemoveFormattingOfTable() to create a copy of the normal style with its Number checkbox to false. I didn't know you could do that (the number false thing).

But in regards to the macro approach, I don't see the need to to apply .TableStyle = "TableStyleLight1" at all - after all, a TableStyle will already be applied.

And rather than add the NormalNoNum style simply to delete it again, it strikes me that because this stlye is so handy, you may as well just add it and leave it there for future use. In fact, if NormalNoNum is available to the user, then the only advantage of the macro is to apply it to the whole table. But a user could just as easily select the whole table and apply NormalNoNum themselves.

What are your thougts? ALso, I don't mean this to sound critical...I learnt something valueable from this macro.

Regards

Jeff

 


Comment by: Jan Karel Pieterse (3/11/2015 9:37:29 AM)

Hi Jeff,

Good point, there really is little need to get rid of that style. And setting the tablestyle isn't needed in that code either because the table will already have a style, which the macro rudely overrides :-)

And -of course- you can also uncheck other boxes for that style if there are certain parts of the formatting you wish to keep.

 


Comment by: Jeff Weir (3/11/2015 10:33:13 AM)

Cool, thanks for the reply. I just added in a subsection in my book about making a 'Keep Number Format Only' cell style, and also showing how to save it to a Template file (.XLTX or .XLTM) stored in the XLSTART folder, so that this cell style is available for all new workbooks. (I get readers to do the same with an amended TableStyle too).

Thanks for the inspiration, Jan Karel. I wish I had known about the ability to turn off that Numbers option years ago.

 


Comment by: Leanne (4/2/2015 3:02:14 AM)

My "Dashboard" worksheet displays drop down boxes to allow viewers to customize what PROJECT AREA is displayed.
Excel 2013 performance has dropped significantly from Excel 2010 eg click dropdown box to choose different view, takes 20-55secs to run code & display new graphs 2010 was instant.
Have optimized the code eg Events, Calculation, Screen updating etc at start of code and enable again at end.
Excel’s INQUIRE tool says a number of Errors in my formulas: Max(#Ref)
but look at formula in spreadsheet it looks correct: Max(tbl_Performance[DirectMhrs])
Wherever I refer to table lists INQUIRE says there’s a #Ref error.
I'm wondering whether this is the reason the performance has dropped. Does Excel 2013 have issues with working with table list references?

 


Comment by: Jan Karel Pieterse (4/2/2015 7:15:32 AM)

Hi Leanne,

I have not heard about problems with table references in 2013. That 2013 is slower than previous versions is a known "issue". Excel 2013 is particularly slow when (un)protecting sheets. Does your code do a lot of that?

 


Comment by: LJ (4/5/2015 8:10:16 PM)

Whenever I try to add a new row to a table and add data to it, I get the header row first. How do I have the new row come after the header row?


Set newRow = lstAllTrans.ListRows.Add(Position:=lstAllTrans.ListRows.Count + 1, AlwaysInsert:=True)

'The first time this is a header row
lstAllTrans.Range(newRow.Index, lstAllTrans.ListColumns("Amount").Index).Value

I've also tried:
Set newRow = lstAllTrans.ListRows.Add( AlwaysInsert:=True)

 


Comment by: Leanne (4/6/2015 1:09:25 PM)

Hi Jan
I tried removing the protection code but performance still same so, I've put it back in at the moment. It only runs once.
Are there Excel settings maybe that I need to check? Its only been put onto my laptop recently as IT are doing testing to see how it performs before upgrading everyone.
My Supervisor is considering asking that our laptops in our section aren't upgraded due to the performance issues.

 


Comment by: Jan Karel Pieterse (4/7/2015 10:45:21 AM)

Hi Leanne,

Without seeing the workbook it is hard to advise. You might consider sending it? My email address is at the bottom of this page.

 


Comment by: Jan Karel Pieterse (4/7/2015 10:46:18 AM)

Hi LJ,

How is that object variable lstAllTrans defined?

 


Comment by: Ken Witchel (8/31/2015 6:53:17 PM)

I would like to loop through the tables on the active sheet (more than 20 tables, all the same structure). I was considering using one of the following to snippets.


    For Each tbl In ActiveSheet.ListObjects
        Range("tblIncome[Mth2]").Copy
        Range("tblIncome[Mth3]").PasteSpecial
    Next tbl


OR

    For Each tbl In ActiveSheet.ListObjects
        ActiveSheet.ListObjects("Table1").ListColumns(3).DataBodyRange.Copy
        ActiveSheet.ListObjects("Table1").ListColumns(4).DataBodyRange.Paste
    Next tbl


How do I make it generic without having to write the actual table names?

Your help would be most appreciated.

Ken

 


Comment by: Jan Karel Pieterse (9/1/2015 8:52:21 AM)

Hi Ken,

That is realtively easy:

For Each tbl In ActiveSheet.ListObjects
tbl.ListColumns(3).DataBodyRange.Copy
tbl.ListColumns(4).DataBodyRange.Paste
Next tbl

 


Comment by: Ab (9/10/2015 1:40:41 PM)

Hi Jan,

In my Vba i have made some tables. In Names from Excel 2010 I see Table1 than {"XXX"etc.} and =Bestanden!$H$2:$H$14 and underneathe Range/Bereik I see Werkmap but i have no range called that way. How can I remove this Table1 with vba?

Thanks for your help :-)

Regards Ab

 


Comment by: Rob (9/10/2015 3:48:26 PM)

    ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=3, etc

JK, is it possible to change hardcoded Field:=3 to e.g. Field:=Range("Table1[City]")

If I currently have an NAW table Field3 is ok but If I insert column Pcode before Woonplaats I need to update VBA code. Not very efficient.
PC, Windows 7 Office 2010.
Thx!

 


Comment by: Jan Karel Pieterse (9/11/2015 11:43:58 AM)

Hi Rob,

The way to do that is to calculate the right column number from the name of the columns table, so you need something like:

lColNum = Range("Table1[City]").Cells(1,1).Column - Range("Table1").Cells(1,1).Column + 1
ActiveSheet.ListObjects("Table1").Range.AutoFilter Field:=lColNum, etc

 


Comment by: Jan Karel Pieterse (9/11/2015 11:46:19 AM)

Hi Ab,

You can only remove table names from Name Manager by converting the tables back to ranges.

 


Comment by: Elizabeth (9/16/2015 1:47:19 AM)

Is there a way I can extract values from a table? I am currently trying to list which columns in the table are filtered.

Here is my code:


Function CheckFilters(r As Range)
Dim r As Range

fstate = ""
c = ""

If Worksheets("Summary").ListObjects("SummaryTable").ShowAutoFilter Then
    c = Worksheets("Summary").Cells(1, Columns.Count).End(xlToLeft).Column
    c = c - 1


    'go through each column and check for filters
    For i = 1 To c Step 1
     If Worksheets("Summary").ListObjects("SummaryTable").FilterMode(i).On Then
     'If aws1.AutoFilter.Filters(i).On Then
            fstate = fstate & r(i).Value & ", "
     End If
    Next i

    'removes the last comma
    fstate = Left(fstate, Len(fstate) - 2)
Else
    fstate = "NO ACTIVE FILTERS"
End If

'CheckFilters = fstate
MsgBox fstate
End Function


The part that is messing me up is

If Worksheets("Summary").ListObjects("SummaryTable").FilterMode(i).On

Thank you in advance for your assistance.

Elizabeth

 


Comment by: Jan Karel Pieterse (9/16/2015 10:53:17 AM)

Hi Elizabeth,

You can display the columns that are filtered like so:

Sub ShowFilteredColumns()
    Dim oLo As ListObject
    Dim oF As Filter
    Dim lCol As Long
    Set oLo = ActiveSheet.ListObjects(1)
    For Each oF In oLo.AutoFilter.Filters
        lCol = lCol + 1
        If oF.On Then
            MsgBox "Column '" & oLo.ListColumns(lCol).Name & "' is filtered"
        End If
    Next
End Sub

 


Comment by: Erin Rinen (9/16/2015 5:23:40 PM)

Hi,

I am trying to list the criteria used in AutoFilter in a table. There are many tutorials on how to do this with a range but not with a table. Could you help out with that?
Here is what I have so far based off of tutorials for ranges:


Sub AutoFilter_Criteria2()
Dim str1 As String
Dim str2 As String

Dim f As Filter

Application.Volatile

For Each f In Worksheets("Sheet1").ListObjects("Table1").HeaderRowRange(1).AutoFilters.Filters

    'With .Filters(Header.Column - .Range.Column + 1)
        'If Not .On Then Exit Sub
         ' str1 = .Criteria1
        If .Operator = xlAnd Then
            str2 = " AND " & .Criteria2
        ElseIf .Operator = xlOr Then
            str2 = " OR " & .Criteria2
        End If
' End With
End With
End Sub

 


Comment by: gindia (9/17/2015 5:35:25 PM)

Hi, thanks for sharing all the details about tables, that was really eye-opening...!

I applied some of this stuff to my vba project successfully, and I really like the tables concept, it seems to keep the code easier to read than without it.

Unfortunately I'm stuck with one item: I am trying to apply a simple loop through the table rows to check whether column N holds a specific string. If yes: delete row, if not: continue the loop.

I keep getting an error message called 'compile error: type mismatch'... any hints are really appreciated because I've spent hours on this now without getting a real brainwave...

Please find below my piece of work so far:


Sub hire_sheet()

Dim hirelist As ListObject
Dim hiresheet As Worksheet

Set hiresheet = Worksheets("hires")
Set hirelist = hiresheet.ListObjects(1)
    
hiresheet.Activate
    
finalrow = hirelist.ListRows.Count

    ' delete all action reasons 'EIL' in column N

    I = 1
        Do While I <= finalrow
         If hiresheet.Range("N" & I).Value Is "EIL" Then
                hirelist.ListRows(I).Delete
                I = I - 1
                finalrow = finalrow - 1
            End If
            I = I + 1
        Loop

End Sub

 


Comment by: Jan Karel Pieterse (9/18/2015 11:19:26 AM)

Hi Gindia,

This code should work better:
Sub hire_sheet()

    Dim hirelist As ListObject
    Dim hiresheet As Worksheet
    Dim finalrow As Long
    Dim i As Long
    Set hiresheet = Worksheets("hires")
    Set hirelist = hiresheet.ListObjects(1)

    hiresheet.Activate

    finalrow = hirelist.ListRows.Count

    ' delete all action reasons 'EIL' in column N

    For i = finalrow To 0 Step -1
        If hirelist.ListRows.Count > 0 Then
            If hirelist.ListColumns("a").DataBodyRange.Cells(i).Value = "EIL" Then
                hirelist.ListRows(i).Delete
            End If
        End If
    Next
End Sub

NOte that you'll have to replace the "a" with the column name in your listobject

 


Comment by: Jan Karel Pieterse (9/18/2015 11:26:46 AM)

Hi Erin,

Try this:

Sub AutoFilter_Criteria2()
    Dim str1 As String
    Dim oLo As ListObject
    Dim f As Filter
    
    Set oLo = ActiveSheet.ListObjects(1)
    For Each f In oLo.AutoFilter.Filters
        With f
            If .On Then
                'If Not .On Then Exit Sub
                str1 = .Criteria1
                If .Operator = xlAnd Then
                    str1 = str1 & " AND " & .Criteria2
                ElseIf .Operator = xlOr Then
                    str1 = str1 & " OR " & .Criteria2
                End If
            End If
        End With
    Next
    MsgBox str1
End Sub

 


Comment by: gindia (9/19/2015 11:05:09 AM)

Hi Jan,
thanks so much for your help, your code worked like a charm!!
interesting how you changed it, I wouldn't have thought of this... one day I really need to attend a VBA class instead of all this autodidactic muddling through ;-)

you saved my weekend!!
gindia

 


Comment by: Jan Karel Pieterse (9/19/2015 4:06:08 PM)

Hi Gindia,

You're welcome.
NB: I'm planning an advanced VBA class, see the survey here:
http://1drv.ms/1nzY7ZF

 


Comment by: Poul Madsen (excelent) (10/21/2015 9:00:27 PM)

Hi Jan
Im trying to update my table from another sheet in VBA
Im using folowing code :

Sheets("PeriodeAnalyse").ListObjects("Tabel4610").Range.AutoFilter Field:=3, Criteria1:="<>0", Operator:=xlFilterValues

It wont Work

change sheet with : Sheets("PeriodeAnalyse").Activate dosent help either

What to do ?

Regards Poul

 


Comment by: Jan Karel Pieterse (10/22/2015 12:00:21 PM)

Hi Poul,

The syntax appears correct to me. What error do you get?

 


Comment by: Poul Madsen (excelent) (10/22/2015 10:43:45 PM)

Hi Jan

uff im embarrassed. i forgot a "exit sub" the code vorking fine now
ill try finding a Deep hole to jump in :-(

sry. for ur time Waste

p.m

 


Comment by: vikas (11/14/2015 7:14:54 PM)

hi please guide for VBA code to find how many rows and columns given into table data, table name will be given by the user.

 


Comment by: Jan Karel Pieterse (11/16/2015 3:37:52 PM)

Hi Vikas,

Option Explicit

Public Function GetTable(sName As String, Optional oWb As Workbook) As ListObject
    Dim oSh As Worksheet
    Dim oLo As ListObject
    If oWb Is Nothing Then Set oWb = ActiveWorkbook
    For Each oSh In oWb.Worksheets
        For Each oLo In oSh.ListObjects
            If LCase(oLo.Name) = LCase(sName) Then
                Set GetTable = oLo
                Exit Function
            End If
        Next
    Next
End Function

Sub Demo()
    Dim oLo As ListObject
    Set oLo = GetTable("Table1")
    If Not oLo Is Nothing Then
        MsgBox "ListObject 'Table1' has " & oLo.ListRows.Count & " rows and " & vbNewLine & oLo.ListColumns.Count & " columns"
    End If
End Sub

 


Comment by: Damian (11/26/2015 8:41:02 AM)

Hi Jan,
I'm trying to loop through rows of a filtered table, and trap the error if there are no rows in the filter.
Sub mcr_FilteredData()
Dim oFilteredRange As Range
Dim oCell As Range
Dim str_AcctCode As String
str_AcctCode = "6-1790"

    'Selection.AutoFilter
    ActiveSheet.ListObjects("t_Actuals").Range.AutoFilter Field:=2, Criteria1:= _
        str_AcctCode & Chr(13) & ""
    Range("t_Actuals[[#Headers],[FY-FM]]").Select
    'ActiveSheet.ListObjects("t_Actuals").Range.AutoFilter Field:=16, Criteria1 _
    '    :=Array("15-07", "15-08"), Operator:=xlFilterValues
    ActiveSheet.ListObjects("t_Actuals").Range.AutoFilter Field:=16, Criteria1:= _
        ">=1507", Operator:=xlAnd, Criteria2:="<=1606"
    Set oFilteredRange = ActiveSheet.ListObjects("t_Actuals").DataBodyRange
    If oFilteredRange.SpecialCells(xlCellTypeVisible) Is Nothing Then
        Exit Sub
    End If
    
    For Each oCell In oFilteredRange.SpecialCells(xlCellTypeVisible).Rows
        Debug.Print Cells(oCell.Row, 6).value
    Next
End Sub

Your help would be much appreciated.
Regards
Damian

 


Comment by: Jan Karel Pieterse (11/26/2015 9:32:39 AM)

Hi Damian,

I think this should work:

On Error Resume Next
Set oFilteredRange = ActiveSheet.ListObjects("t_Actuals").DataBodyRange.SpecialCells(xlCellTypeVisible)

If oFilteredRange Is Nothing Then
    Exit Sub
End If
On Error Goto 0

 


Comment by: Damian (11/26/2015 11:08:56 AM)

Hi Jan,
Your tip worked a treat. Thank You.
Regards
Damian

 


Comment by: Dave (12/9/2015 1:49:25 PM)

I have an excel sheet with thousands of records. In column A it has a unique code (like item code) and column B shows a quantity for that code. (kind of stock taking).

Very often I need to update the quantity for a few items. usually i get an external list of codes (these values are existing in Column A) and I need to either increase or decrease the quantity of that code (usually its either -1 or +1)

What VB code can i use that:
1) when I open the sheet it asks me if i want to update. (or alternatively I can have a button that I click myself to activate the macro)
2) If i want to update, it prompts me to input the codes (ideally allowing a copy and paste) and selecting if I want to increase or decrease the quantity for that code. (its ok to update all the matching codes with same +1 or -1). (i never add and subtract in same session). So there could also be two buttons, one for adding and one subtracting, this is fine

as an example.
Column A has Codes AA, BB, CC, DD, EE. Column B Values are 10, 20, 30, 40 and 50 respectively.

Now I want to update CC and EE with a +1. The VB should ask me to paste which values need updating (in this case CC, EE) and it should make the values in column B as 10, 20, 31,40,51.

If you can help me it will save me hours per day! Many thanks
Dave

 


Comment by: Jan Karel Pieterse (12/9/2015 4:45:50 PM)

Hi Dave,

What about a manual method.

1. Enter a 1 in any cell
2. Filter the table so only the ones that need an update are visible
3. Copy the cell with the 1
4. Select the numbers in your filtered table
5. Press control+alt+v to open the paste sepcial dialog
6. Select "Values" and "Subtract" or "Add" and click OK.

 


Comment by: Tarpan (12/13/2015 7:31:52 PM)

Hello Jan, I have following questions regarding table using VBA, your comments would be helpful. Thanks.
1. How to determine the empty row in table to paste the data.
2. If there is not enough rows in table to paste the data, how to make that happen with VBA or In this situations VBA will automatically add the rows and paste the data?

 


Comment by: Jan Karel Pieterse (12/14/2015 9:03:39 AM)

Hi Tarpan,

This should find the first empty row starting from the top of the table:

    With ActiveSheet.ListObjects("Table1")
        If .ListRows.Count = 0 Then
            .HeaderRowRange.Columns(1).Offset(1).Select
        Else
            .HeaderRowRange.Columns(1).End(xlDown).Offset(1).Select
        End If
    End With

 


Comment by: gindia (12/18/2015 2:37:06 PM)

Hi all,

I´m currently struggeling with a piece of vba code and I am really running out of ideas, but maybe you can help.

As a part of my code, I want excel to write a formula into a column of an excel table. Pretty simple, and it´s running perfectly fine on my excel 2013, but whenever it´s run on excel 2007, it returns an error message at this piece of code:

Set psdata = ActiveSheet.ListObjects("data")
x = psdata.ListColumns.Count
...
psdata.ListColumns(x).DataBodyRange.Cells.formula = _
"=IF(ISNUMBER(SEARCH(""regional"",[@[scope]])),""regionally relevant"","""")"

So the code keeps getting stuck at inserting the formula, but I have no idea why - I always thought that excel 2007, 10 and 13 are pretty similar, and only previous versions will struggle with listobject commands(?)

Glad about any ideas from your end...

 


Comment by: Jan Karel Pieterse (12/18/2015 3:01:56 PM)

Hi Gundula,

The syntax for referencing "this row" is different in Excel 2007. In 2010 and up it is:


[@[scope]]


in 2007 it is:

[[#This Row];[scope]]

 


Comment by: gindia (1/5/2016 9:31:15 AM)

hi Jan,
thanks for highlighting the differences about 2010 and 2007 to me, that's extremely helpful!!
have a great week

 


Comment by: Jan Karel Pieterse (1/5/2016 9:56:20 AM)

Hi Gundula,

You're welcome!

 


Comment by: Ali Khan (1/9/2016 9:09:34 PM)

Hi,

Can u help me to provide with vba code to insert table in worksheet based on the available data which can be dynamic.

Similarly if the table is already available in the sheet then it should be deleted and new table be inserted on the data available in sheet

Thanks a lot in advance.

Regards,

 


Comment by: Jan Karel Pieterse (1/11/2016 1:22:45 PM)

Hi Ali,

If there already is a table on a sheet, then what data would be available for the new table?

 


Comment by: Jeff Carnahan (1/12/2016 2:50:36 PM)

Great post! I have two question; 1) how do I delete all the rows in a table without using a loop? and 2) how does excel 'remember' formulas I have entered in some columns after deleting all the rows? eg. I deleted all the rows in a table, then I add some data (rows) back, and the formulas magically reappear in the columns where they were. But it only does it for some columns. Thank you!

 


Comment by: Jan Karel Pieterse (1/12/2016 3:05:54 PM)

Hi Jeff,

1:


Sub Example()
    Dim oLo as ListObject
    Set oLo = ActiveSheet.ListObjects(1)
    oLo.DatabodyRange.Delete
End Sub


2:
Excel stores the formula internally. Odd enough, there is no userinterface to get at that stored formula. The only way is to make sure there is a row in the table and then one can edit the formula. If the same formula is in all rows that will replace the "default".

 


Comment by: Stayce (1/13/2016 6:52:40 PM)

I've developed a code to insert a user-specified number of lines utilizing a message box. I would like to use
Selection.ListObject.ListRows.Add AlwaysInsert:=True
to add the lines at the bottom of the table but I also need it to add the number of lines entered by the user, so combining it with
Selection.ListObject.ListRows.Add (11)
. Is there a simple way to do this?

Thank you!

 


Comment by: Jan Karel Pieterse (1/13/2016 9:30:16 PM)

Hi Stayce,

Seems you can only add one row at the time so you'd need to loop as many times as entered:

    Dim lRows as long
    Dim lCt as long
    lRows=INputbox("How many Rows")
    For lCt=1 to lRows
        Selection.ListObject.ListRows.Add
    Next
End Sub

 


Comment by: Dr. Demento (1/22/2016 8:23:50 PM)

Jan, great stuff!! I really enjoy your site!!

I've developed a function to create pivot tables where the user provides source, destination, & pvt tbl name. However, I'd like to be able to specify the style for each table so they have something to distinguish them. I was hoping that there was a TableStyle index analogous to ColorIndex (pre-defined styles that I could assign using a For Next loop (i.e., a numerical assignment for each TableStyle)). If there is, what is the syntax to assign a style to each table?

Much appreciated.

 


Comment by: Jan Karel Pieterse (1/22/2016 9:18:12 PM)

Hi,

The syntax is something like this:

ActiveSheet.PivotTables("PivotTable1").TableStyle2 = "PivotStyleMedium2"

and the stylenames you see here are derived from the staylename you see when you hover your mouse over them when you manuallly change the PT style (just remove the spaces from the names).

 


Comment by: DaveM (2/2/2016 5:48:04 AM)

I'm trying to work with tables that are not in the activesheet. If I have my_table on Sheet1 and Sheet1 is the activesheet then this code works.

Dim oLo As ListObject
Set oLo = Range("my_table").ListObject

oLo.ListColumns(1).DataBodyRange.Select


However if I run the code (in xl2013) and Sheet2 is active I get a runtime error. Just wondering what the correct method is?

 


Comment by: Jan Karel Pieterse (2/2/2016 3:54:39 PM)

Hi Dave,

In that case you need to tell VBA what sheet it needs:

Dim oLo As ListObject
Set oLo = Worksheets("Sheet1").Range("my_table").ListObject
'The next line may fail because you cannot select cells if they are on a different sheet
oLo.ListColumns(1).DataBodyRange.Select
'To ensure this works, use Goto instead:
Application.Goto oLo.ListColumns(1).DataBodyRange

 


Comment by: Bryan (2/9/2016 4:34:47 AM)

I want to control the size of a table with a formula, like an offset formula or an aggregate formula. It seems the table feature doesn't remember the formula i put into the size box (oddly enough it calculates the formula correctly so it works once and quits) so i want to try and control it with VBA is there a code to set the number of rows

 


Comment by: Jan Karel Pieterse (2/9/2016 11:07:09 AM)

HI Bryan,

I'm not sure I understand what you need?
You can resize a table using VBA:

ActiveCell.ListObject.Resize Range("A1:D100")

 


Comment by: Dino (2/17/2016 12:02:47 PM)

Hello,

I was trying to get the a value from same row of the active cell in the table but from another column "name".

Is this possible?
e.g if my active cell in the table was d:4 and I wanted to return the value from the same row but from a:4 (lets say the column name was called "Colour"), what would the VBA look like for this?

Kind Regards

 


Comment by: Jan Karel Pieterse (2/17/2016 2:00:50 PM)

Hi Dino,

Here is one way:
MsgBox Intersect(ActiveCell.ListObject.ListColumns("Colour").Range, ActiveCell.Entirerow).Value

 


Comment by: damian (2/18/2016 11:41:12 PM)

Hi Jan,
I want to run a sql type command in VBA over an excel table like
Select [name] from table where [country]='Australia'
I have got this to work OK:
With sheets("Sheet1").ListObjects("t_Employees")
    For i = 1 To .DataBodyRange.Rows.Count
        if .ListColumns("Type").DataBodyRange.Cells(i, 1).value="Australia"
            do something
        end if
    next i
end with
But it is slow, specially if there are a large number of records in the table.
Using filters doesn't give me reliable results.
Regards
Damian



 


Comment by: Jan Karel Pieterse (2/19/2016 11:55:48 AM)

Hi Damian,

You say filtering does not produce reliable results. Can you elaborate? It should work as expected

 


Comment by: Damian (2/20/2016 4:12:32 AM)

Hi Jan,
I used .DataBodyRange.SpecialCells(xlCellTypeVisible), but when I changed the filter using VBA
for the next loop (ie all employees In USA, it didn't reset it correctly.

Regards
Damian

 


Comment by: Jan Karel Pieterse (2/20/2016 3:01:04 PM)

Hi Damian,

Without seeing your code this is really hard to comment on :-)

 


Comment by: AD (2/23/2016 8:40:53 AM)

HI

Thanks for this post, very useful

Is it possible to make us an introduction to the use of the table as the data source for a ListBox in UserForm for example.

Thanks in advance

 


Comment by: Jan Karel Pieterse (2/24/2016 8:30:43 AM)

Hi AD,

Sure. To add one column to the listbox:

Listbox1.List = Worksheets("Sheet1").ListObjects("Table1").ListColumns("Column1").DataBodyRange.Value

 


Comment by: RENZO (3/1/2016 12:53:29 PM)

there is a way to do something like that, I have a table with 2 columns Item and Quantity:

Item Quantity
Item1 4
Item2 3

I need to copy each Item (and entire related row) and paste in another sheet for many times as quantity field:

Item1
Item1
Item1
Item1
Item2
Item2
Item2

Thank you

 


Comment by: Jeff Carnahan (3/4/2016 5:11:42 PM)

I have a table where I refresh the data daily. First, I delete all the rows using the code below that was provided in this forum previously (thanks again!). I then paste the new data into a blank row just below the table and then resize the table to include the new rows. I would like to automate the resizing of the table. I realize I could paste the data directly into the table by pasting my new data starting from the first row of the table but this causes problems; 1) because I am pasting 200K to 500K rows of data, this causes Excel to get stuck/freeze regularly, and 2) this is partly because Excel automatically tries to populate/copy down some of, but not all, the columns that contain formulas. When I paste the data just below the table and then manually resize it, Excel doesn’t freeze and it doesn’t try to copy down the formulas. What I would like is a script that looks at the new data below the table, gets the last row number, and then uses that number to resize the table. All suggestions welcome!

Sub DeleteTableRows()
    Dim oLo As ListObject
    Set oLo = ActiveSheet.ListObjects(1)
    oLo.DataBodyRange.Delete
End Sub

 


Comment by: Jan Karel Pieterse (3/4/2016 8:51:43 PM)

Hi Jeff,

The last row in for example column A can be determined as follows:


Dim lLastRow as long
lLastRow = Cells(1, ActiveSheet.Rows.Count).End(xlUp).Offset(1).Row

 


Comment by: Warren Hall (4/7/2016 7:24:45 PM)

Thank you for the wonderful, clear, and concise write-up on Tables. It is most helpful.

 


Comment by: AlexBY (4/28/2016 6:17:35 PM)

Hi Jan,

Thank you for this article.
Could you confirm that after applying the filter to the table
by
....
oSh.Range("Table1[[#All],[Column2]]").AutoFilter _
field:=1, _
Criteria1:="Otis", _
VisibleDropDown:=True

....

I will get exactly the data I want (visible part of the iceberg)?
by
....
'select entire data section of table
oSh.Range("Table1").Select
....

or do I try to achieve in a wrong way?

thank in advance.

 


Comment by: Jan Karel Pieterse (4/29/2016 11:51:00 AM)

Hi Alex,

The best way to ensure your code is right is by testing. One thing to look out for is whether it makes a difference if the table is already filtered on another column of the table.

 


Comment by: Jake (5/13/2016 10:25:34 PM)

Thank you so much! This is the best breakdown I have found yet on VBA for tables in Excel. I really really appreciate it, my company too!

 


Comment by: randolf.Kaempfer@messefrankfurt.com (5/30/2016 6:13:27 PM)

Hello,

I try to pick out of the table "tab.Ref.Kontakte" an email-address. But something is wrong. To record the code it is easy, but it only works as formual in a cell. It try to translate in VBA-Code, but i did something wrong.
1. To set the "rng", what is here the best code
2. In Column 11 there is my match-Name. I read out the row and in column 8 in the same table there is the email-address I wanted.

I search for an idea in the WWW, but the function of tables is not very often listen.

Set wbk = ActiveWorkbook
'Set shtContact = wbk.Sheets("Ref-Kontakt")
'Set tblContact = shtContact.ListObjects("tab.Ref.Kontakte")
Set tblContact = wbk.Sheets("Ref-Kontakt").ListObjects("tab.Ref.Kontakte")
Set rng = tblContact.ListColumns.Item(11).Range.Address

blnPersonsSelect = False


' Ermittlung, ob überhaut ein Eintrag aktivert ist.
For n = 0 To Me.lst_PersonInCharge.ListCount - 1
If Me.lst_PersonInCharge.Selected(n) = True Then
     blnPersonsSelect = True
     i = i + 1                                             ' Anzahl der Empfänger für das Array z. B.
     ReDim arrAddressee(i, 0)                             ' Array set to Addressee
     strAddressee = Me.lst_PersonInCharge.List(n)
     strEmailAddress = wsf.Index(tblContact, wsf.Match(strAddressee, rng, 0), 8)
                         'INDEX(tab.Ref.Kontakte,MATCH(""Miller, Manfred"",tab.Ref.Kontakte[NameAufgabe],0),8)
     arrAddressee(i, 0) = strEmailAddress
End If

 


Comment by: Jan Karel Pieterse (6/7/2016 1:48:22 PM)

Hi Randolf,

I haven't studied your code entirely, but there is one problem I see:

Set rng = tblContact.ListColumns.Item(11).Range.Address


You are trying to store a string property into a range object. The proper syntax would be:

Set rng = tblContact.ListColumns(11).DataBodyRange


It might be better to use the column name, rather than the index number (11) here.

 


Comment by: Agni (6/10/2016 9:00:59 AM)

How to create a table without a default auto filter and header.

 


Comment by: Jan Karel Pieterse (6/11/2016 4:08:30 PM)

Hi Agni,

After creating, turn off headers and filters in the table settings ribbon?

 


Comment by: Jordan Lambert (6/27/2016 10:43:00 AM)

Hi Jan,

Many thanks for this article.

I'm trying to have filters on tables auto-refresh when new data is entered? Tried a few 'solutions' without any success.

Any help would be much appreciated.

Thank you in advance.

 


Comment by: Jan Karel Pieterse (6/27/2016 5:41:14 PM)

Hi Jordan,

I would probably add a change event to the worksheet in question and have it refresh the filter of the table.
The syntax for reapplying a listobjects filter is:
ActiveSheet.ListObjects("Table1").AutoFilter.ApplyFilter

 


Comment by: SACHIN (7/17/2016 11:29:23 AM)

How to convert DD:H:MM format in To H:MM format
For Ex. 02:06:15(02 days, 06 houres, 15 min.)convert in Hours format

 


Comment by: Jan Karel Pieterse (7/17/2016 4:43:26 PM)

Hi,

I would make sure there are some empty columns next to your data and use Data, Text to columns to split the data into columns by the : .

 


Comment by: envirodat (8/3/2016 12:42:17 AM)

This was very helpful! Thanks for the great reference.

 


Comment by: Marc van Ginhoven (8/10/2016 9:29:42 AM)

How can I use VBA to select the following in a table

- Column 11 - 18
- Not the header
- Not the 1st data row
- The 2nd data row untill the end of the table.

I already have code that works it's clunky.

The selection is needed to copy an insane amount of formulas and paste their values in the same table. The selection saves the formulas in the 1st data row so that they are saved and used in future table updates.

This greatly improves the pivottable sheet.



 


Comment by: Jan Karel Pieterse (8/10/2016 10:44:25 AM)

Hi Marc,

This can be done using the structured formula syntax:

    Dim oRng As Range
    Set oRng = Range("table1[[col 11]:[col 18]]")
    Set oRng = oRng.Offset(1).Resize(oRng.Rows.Count - 1)
    oRng.Select


Alternative method:

    Dim oLo As ListObject
    Dim oRng As Range
    Set oLo = ActiveSheet.ListObjects(1)
    Set oRng = oLo.ListColumns(11).DataBodyRange.Resize(, 8)
    Set oRng = oRng.Offset(1).Resize(oRng.Rows.Count - 1)
    oRng.Select

 


Comment by: JohnBen (9/26/2016 11:12:57 AM)

Thanks but how to copy all value from the table and copy to another table?

:)

 


Comment by: Jan Karel Pieterse (9/26/2016 6:00:27 PM)

Hi JohnBen,

Copying the content of a table is simple:

Suppose you want to copy from Sheet1, Table1 to Sheet2, Table2:

Sub Demo()
Worksheets("Sheet2").ListObjects("Table2").DataBodyRange.Delete
Worksheets("Sheet2").ListObjects("Table2").ListRows.Add
Worksheets("Sheet1").ListObjects("Table1").DataBodyRange.Copy
Worksheets("Sheet2").Paste Worksheets("Sheet2").ListObjects("Table2").DataBodyRange.Cells(1,1)
End Sub

 


Comment by: ggv (10/11/2016 8:47:35 AM)

How do I enter formula in a table from vba? Things that work on a plain spreadsheet do not work in tables. I.e. this doesn't work for me in vba:

Range("B3").Formula = "=C3+D3"

But I can enter this formula manually and it works.


 


Comment by: Jan Karel Pieterse (10/11/2016 9:30:47 AM)

Hi ggv,

That routine does work and enters the formula into a cell, regardless whether that cell is inside a table or not.

 


Comment by: Robin (10/25/2016 8:17:22 PM)

I am trying to compare differences between 2 cells ( Via a key- unique identifier) between 2 tables in 2 sheets. The sheet can have multiple columns

The formula works well (below)

=SUM(SUMIFS(Table1[Col1],Table1[Key],A4))-(SUMIFS(Table2[Col1],Table2[Key],A4))

A4 is the key(unique identifier connecting both tables)

For Col1, Cell B4 =formula is =SUM(SUMIFS(Table1[Col1],Table1[Key],A4))-(SUMIFS(Table2[Col1],Table2[Key],A4))

For Col2, cell C4 =formula is =SUM(SUMIFS(Table1[Col2],Table1[Key],A4))-(SUMIFS(Table2[Col2],Table2[Key],A4))


For Col3, cell C4 =formula is =SUM(SUMIFS(Table1[Col3],Table1[Key],A4))-(SUMIFS(Table2[Col3],Table2[Key],A4))

Formula works fine if I copy this manually but is there any way I can update the formula through VBA /Macro , I tried auto fill but then I am unable to keep Table1[Key] as fixed.
Do excel have something static e.g $A$2 like Table1[$Key]

Any thoughts ?

 


Comment by: Jan Karel Pieterse (10/26/2016 9:34:28 PM)

Hi Robin,

There is a way to make a table reference absolute, but it is counter intuitive:

=[[Key]:[Key]]

 


Comment by: Robin (10/27/2016 7:30:40 PM)

You are so awesome !! I want to hug you and cry !Thank you Jan. Let me know if you need anything from Toronto :)

 


Comment by: Jan Karel Pieterse (10/28/2016 12:12:35 PM)

Hi Robin,

<blush> thanks!

 


Comment by: Simon (11/15/2016 1:54:07 AM)

I just found an Excel bug working with tables and vba that drove me crazy for ages.
My issue was that I had the first two columns formatted as Australian date format - but when the workbook was saved using vba: Activeworkbook.SaveAs or Save, then closed, when reopened the table would lose that formatting when a new line was autocreated (for the new line - the date would be a random custom format)
It ONLY happened using vba. It NEVER happened when saving manually. And once the table was corrupted, the only way to fix it was to convert all tables to Ranges, and then re-create them. Don't ask me how many hours it took me to find the source of this problem.
An additional problem was copying and pasting the table (once corrupted) into a new workbook using vba and then saving the workbook would crash Excel every time.
A 'fix' for now that I am about to implement, is to use VBA to convert tables to range before the user saves, then recreate them in the next stage. Hope this helps someone

 


Comment by: Jan Karel Pieterse (11/15/2016 7:51:09 AM)

Hi Simon,

That is odd. Can you perhaps email a copy of your file?

 


Comment by: Ian H (11/15/2016 12:32:46 PM)

Hi, Great piece of work, I've been playing with this for hours!! Wondering if you can advise on a project I'm doing.

Basically I want to take data from table 1 on sheet 1 & table 2 on sheet 2 (Both columns are called "Names"), put all the data from the 2 tables into (Minus blanks) into table 3 on sheet 3 (Column "Names").

I can do it from 1 table but not the 2nd

Thanks in advance

 


Comment by: Ian H (11/16/2016 9:03:11 PM)


Hi Jan, I managed to do what I wanted using "bits" of other code ...... But only partially with listobjects..... I would appreciate if you show me how to change this.

Sub Do_Sheets()

Dim oSh3 As Worksheet
Set oSh3 = Sheet3
Set wsSummary = Worksheets("Sheet3")


Application.EnableEvents = False


wsSummary.Select

With oSh3.ListObjects("Table3")
oSh3.Range("Table3[Name]").Select

    Selection.ClearContents


sheetlist = Array("Sheet1", "Sheet2")
For i = LBound(sheetlist) To UBound(sheetlist)
Worksheets(sheetlist(i)).Activate



'Code Goes here

Application.EnableEvents = False

'Select ranges
Range("A1").Select
Selection.CurrentRegion.Select

' Selects the current data area without the top row.
Selection.Offset(1, 0).Resize(Selection.Rows.Count - 1).Select




' Selects the visible cells of the selection.
' This is useful if data is filtered or contains hidden rows.
Selection.SpecialCells(xlVisible).Copy
wsSummary.Activate
Range("A1").Select

Do Until ActiveCell.Value = ""
ActiveCell.Offset(1, 0).Select


Loop
ActiveCell.PasteSpecial xlPasteAll



Range("A1").Select

Application.CutCopyMode = False

Application.EnableEvents = True


Next

End With



End Sub

 


Comment by: Jan Karel Pieterse (11/17/2016 11:50:51 AM)

Hi Ian,

Something like this?

Sub CopyTheNames()
    Worksheets("Sheet1").ListObjects("Table1").ListColumns("Names").DataBodyRange.Copy
    With Worksheets("Sheet3")
        If Not Worksheets("Sheet3").ListObjects("Table3").InsertRowRange Is Nothing Then
            .Paste .ListObjects("Table3").InsertRowRange
        Else
            .Paste .Range("A" & .Rows.Count).End(xlUp).Offset(1)
        End If
    End With
    Worksheets("Sheet2").ListObjects("Table2").ListColumns("Names").DataBodyRange.Copy
    With Worksheets("Sheet3")
        .Paste .Range("A" & .Rows.Count).End(xlUp).Offset(1)
    End With
End Sub

 


Comment by: Ian H (11/21/2016 4:49:06 PM)

Hi Jan, Thanks for you reply. Unfortunately your code pastes blanks making the table much bigger each time the code is run. But I can use some of it I think.

Thanks again

 


Comment by: Pascal (11/22/2016 3:22:46 PM)

Hi Robin I ahve the following problem, I want to edit a table by first searching for a certain sample ID. I then want to edit that row of the table with other data like the 5000 as seen below. The address converter does not work properly, because it does not convert the adress to a listrow, but just a row, so that the 5000 appears in the wronr row. Could you please help me. I have been working on this for hours!

'Search
Set ref = Sheets("Tests Results").ListObjects("Test_results").ListColumns("#") 'reference to sheet, tablecolumn1
Set rgFound = Range("A4:A1000000").Find(SampleID.Value)        'Search for a SampleID WATCH OUT! This is static!
MsgBox "Row is " & rgFound.Address
Debug.Print rgFound.Address
'END Search


'ADRESS CONVERTER
Dim address1 As String, myrow As Long

address1 = rgFound.Address(0, 0)
myrow = Range(address1).Row
MsgBox "MyRow is " & myrow
'END ADRESS CONVERTER
'x = Rows(ActiveCell.Row).Select

Set Obj = Worksheets("Tests Results").ListObjects("Test_results")
Obj.ListColumns("Test Lab").DataBodyRange(myrow) = 5000

 


Comment by: Jan Karel Pieterse (11/22/2016 7:25:26 PM)

Hi Pascal,

your variable myrow will contain the current row number, which is NOT the same as the Nth row of the databodyrange of the table.
If for instance your table starts on row 10, the databodyrange starts at row 11.
The way around that is by using the object variable rgFound you already have.

rgFound.Value = 5000


will set the value of the found cell to 5000

If you want to change a value of another column of the listobject, you can use the INtersect function:

Intersect(rgFound.EntireRow, Worksheets("Tests Results").ListObjects("Test_results").ListColumns("Test Lab").DataBodyRange).Value = "FooBar"

 


Comment by: Pascal (11/23/2016 9:37:39 AM)

Wow very helpful thanks!

 


Comment by: ALEJANDRO HERNANDEZ NARANJO (12/6/2016 3:29:00 AM)

please

I can't run this code:

Function CrearQueryTable(Conexion, Query, Hoja, Destino, Nombre, CommandType)
Sheets(Hoja).Select
With ActiveSheet.ListObjects.Add(SourceType:=0, Source:=Conexion, Destination:=Destino).QueryTable
        .CommandType = xlCmdSql
        .CommandText = Query
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .BackgroundQuery = True
        .RefreshStyle = xlInsertDeleteCells
        .SavePassword = False
        
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .PreserveColumnInfo = True
        .ListObject.Name = Nombre
        .Refresh BackgroundQuery:=False
    End With
End Function

anybody can help me

Im so desperate, im not a developer

 


Comment by: Paul John (12/6/2016 10:01:59 AM)

Ian H

Try this (a mod of Jan's code)...

Sub CopyTheNames()

With Worksheets("Sheet1").ListObjects("Table1")

    .Range.AutoFilter Field:=1, Criteria1:="<>"

    .ListColumns("Names").DataBodyRange.SpecialCells(xlCellTypeVisible).Copy

End With



With Worksheets("Sheet3")

    If Not Worksheets("Sheet3").ListObjects("Table3").InsertRowRange Is Nothing Then

     .Paste .ListObjects("Table3").InsertRowRange

    Else

     .Paste .Range("A" & .Rows.Count).End(xlUp).Offset(1)

    End If

End With

With Worksheets("Sheet2").ListObjects("Table2")

    .Range.AutoFilter Field:=1, Criteria1:="<>"

    .ListColumns("Names").DataBodyRange.SpecialCells(xlCellTypeVisible).Copy

End With

With Worksheets("Sheet3")

    .Paste .Range("A" & .Rows.Count).End(xlUp).Offset(1)

End With

Worksheets("Sheet1").ListObjects("Table1").Range.AutoFilter

Worksheets("Sheet2").ListObjects("Table2").Range.AutoFilter

End Sub

 


Comment by: Jeff (12/31/2016 4:03:43 PM)

Greetings Jan! I have successfully fount the code to add a new column and name it but I cannot get it to insert the formula without cheating like this:

        With ActiveSheet.ListObjects("Table1")
        .ListColumns.Add.Name = "LEN"
    End With
    Range("Table1[LEN]").Formula = "=LEN([@[Outstanding Docs]])"

What I am trying to achieve is something like this:

        With ActiveSheet.ListObjects("Table1")
        .ListColumns.Add.Name = "LEN"
        .ListColumns("[LEN]").Formula =LEN([@[Outstanding Docs]])" '<< this fails
    End With

but I can't find the proper proper syntax.

Many thanks and have a Happy New Year!

 


Comment by: Jan Karel Pieterse (12/31/2016 7:15:29 PM)

Hi Jeff,

I think the correct syntax is:

.ListColumns("LEN").Formula ="LEN([@[Outstanding Docs]])"

 


Comment by: Jeff (12/31/2016 10:36:34 PM)

.ListColumns("LEN").Formula ="LEN([@[Outstanding Docs]])" was one of the first things I tried. Unfortunately it generates a "Object doesn't support this property or method" error.

 


Comment by: Jan Karel Pieterse (1/1/2017 9:20:56 PM)

Hi Jeff,

Apologies, it should've been

.ListColumns("LEN").databodyrange.Formula ="LEN([@[Outstanding Docs]])"

 


Comment by: zainul ulum (1/27/2017 2:42:19 AM)

briefly clear explanation

 


Comment by: Milos (2/20/2017 2:23:16 PM)

Hi.
What I wanna do is to select a row in a table and filter it contents based on the second third and fourth coloumn value.
I can't figure it out how to get the right code.
For any help or hint I would be deeply grateful.

 


Comment by: Jan Karel Pieterse (2/27/2017 10:03:54 AM)

Hi Milos,

Have you tried recording a macro while setting up the filter?

 


Comment by: Milos (2/28/2017 9:19:50 PM)

Hi Jan,
Yes I have. And when I chandged it into a code it did not work. I got empty rows as a result.

In the meantime I found out that the date was the culprit. Dates are tricky. Now it works.

Namely, for the date part of filtering I must use two criteria instead of one. The code is sth like this:


Var1 = Selection.Value
ActiveCell.Offset(0, 1).Select
Var2 = Selection.Value
ActiveCell.Offset(0, 3).Select
dDate = Selection.Value
dDate = DateSerial(Year(dDate), Month(dDate), Day(dDate))
lDate = dDate

ActiveSheet.ListObjects("clients").Range.AutoFilter Field:=1, Criteria1:=Var1
ActiveSheet.ListObjects("clients").Range.AutoFilter Field:=2, Criteria1:=Var2
ActiveSheet.ListObjects("clients").Range.AutoFilter Field:=5, Criteria1:=">=" & lDate, _
                                                Operator:=xlAnd, Criteria2:="<" & lDate + 1

 


Comment by: Jan Karel Pieterse (3/1/2017 10:03:16 AM)

Hi Milos,

Great that you got it sorted!

 


Comment by: Ray (3/7/2017 10:48:38 PM)

Great article on explaining tables and styles, but how do I access the data in the table?

For example, I want to read the set of values in Column 2 and based on the value, perform an action. Is it any easier to access and manipulate the cell contents if I turn the data into a table?

 


Comment by: Jan Karel Pieterse (3/8/2017 9:46:16 AM)

Hi Ray,

It is easier becaus it is simple to always work with all rows/columns of the table, no need to use End(xlDown) and hope for the best (or start from row 1,000,000 and do end(xlUp)). To work with all cells of the column called "Column_X":
Dim oCell As Range
For Each oCell in Worksheets("Sheet1").ListObjects("Table1").ListColumns("Column_X").DataBodyRange

The only snag is that the table might be empty, causing a runtime error. To avoid that you first count the number of ListRows:
If Worksheets("Sheet1").ListObjects("Table1").ListRows.Count>0 Then
'Remainder of Code
End If

 


Comment by: Namrata Lohia (3/16/2017 12:01:41 PM)

hi, i have to write a macro code for creating a table with user defined number of rows and columns.

 


Comment by: John Dunsmuir (5/20/2017 5:44:19 PM)

Is there a method or event to detect when a user has deleted the last row of a table? I'm currently using worksheet_change event and the intersect method but when deleting a row the event target is outside the table range and does not intersect. A workaround may be to track the table size but I'm looking for something less clunky.
Thanks

 


Comment by: Jan Karel Pieterse (5/22/2017 9:52:33 AM)

Hi John,

This seems to work:
Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Target.Offset(-1).ListObject Is Nothing Or _
     Not Target.ListObject Is Nothing Then
        If Application.CommandBars("Standard").FindControl(ID:=128, recursive:=True).List(1) = "Delete Row" Then
            MsgBox "Deleted a row in a table"
        End If
    End If
End Sub

 


Comment by: akis tzortzis (5/29/2017 4:58:19 PM)

After you have added a totals row, how do you then access individual columns' totals (from VBA) ?

 


Comment by: Jan Karel Pieterse (5/29/2017 5:42:32 PM)

Hi Akis,

This gets you the entire row with totals:

ActiveSheet.ListObjects("Table1").TotalsRowRange


Or, to get the total cell's value of a specific column:

ActiveSheet.ListObjects("Table1").ListColumns("ColumnCaption").Total.Value

 


Comment by: Fadas (6/10/2017 7:57:59 AM)

hi
first sorry me for awful english
i have a table in excel, and I want change validation massage of for example cells in column 2 & 3
when may table have one data row it work, but when it have tow or three data row it dosnt work
i have a code like this

If tbl.ListRows.Count = 1 And ActiveWorkbook.Worksheets(SH_NUM).CodeName = Sh.Cells(Z, Col) And Sh.Cells(Z, 3) = tbl.HeaderRowRange(1, I).Address Then
If Sh.Cells(Z, 6) = "VALT" Then
tbl.DataBodyRange.Cells(1, I).Validation.ErrorTitle = Sh.Cells(Z, Col + 3)
Else
If Sh.Cells(Z, 6) = "VALM" Then
tbl.DataBodyRange.Cells(1, I).Validation.ErrorMessage = Sh.Cells(Z, Col + 3)
End If
End If
End If

 


Comment by: Fadas (6/10/2017 8:01:43 AM)

sorry me
code is this:


If ActiveWorkbook.Worksheets(SH_NUM).CodeName = Sh.Cells(Z, Col) And Sh.Cells(Z, 3) = tbl.HeaderRowRange(1, I).Address Then
If Sh.Cells(Z, 6) = "VALT" Then
tbl.DataBodyRange.Cells(1, I).Validation.ErrorTitle = Sh.Cells(Z, Col + 3)
Else
If Sh.Cells(Z, 6) = "VALM" Then
tbl.DataBodyRange.Cells(1, I).Validation.ErrorMessage = Sh.Cells(Z, Col + 3)
End If
End If
End If



it dosnt work, why?

 


Comment by: Jan Karel Pieterse (6/11/2017 7:25:37 PM)

Hi Fadas,

If you record a macro changing the validation of a cell which already has an existing validation rule you will see why your code fails; you have to delete the validation rule and add it back again.

 


Comment by: Gajendra kumar (6/20/2017 6:56:46 AM)

in microsoft excel 2007 created database table record in only field
how can make disable field cell

 


Comment by: Jan Karel Pieterse (6/20/2017 10:02:56 AM)

Hi Gajendra,

I'm afraid I don't understand your question, can you please try to rephrase it?

 


Comment by: Jonathan (6/21/2017 9:41:27 PM)

I want to set a table range to a dynamic Named Range

Table is "Data_Table"
Work Sheet is "Data"
Named Range is "ALL_Data" = Data!$D$2:INDIRECT("K" & Data!$M$4)

I want the table to constantly resize

Please Help....

 


Comment by: Jan Karel Pieterse (6/22/2017 9:49:47 AM)

Hi Jonathan,

If you define your range name and simply point it to the entire table everything is handled by Excel, no need for dynamic range names anymore.

 


Comment by: Jonathan (6/22/2017 1:48:34 PM)

The data in the table is created by formula
I have 1000 rows but most are blank
using =IFERROR (***,****,"")

I need the table to resize to contain the non blank entries.

I was hoping to use VBA to change the table range using the result of a count

Any Ideas....

 


Comment by: Jan Karel Pieterse (6/22/2017 2:00:03 PM)

Hi Jonathan,

In that case I'm afraid I am not sure I follow your intentions.

Perhaps better to ask your question at www.eileenslounge.com where you can attach a sample workbook to your question to clarify things.

 


Comment by: Paul (6/27/2017 2:50:27 AM)

Hi Jan Karel

I have a macro which converts a range into a table, then adds a column to it. I am also trying to insert a formula into the new column, but keep getting an error message.

I'm hoping you could help me understand why please.

The error is "Runtime error 91. Object Variable or With block variable not set".

Note - this seems to occur when my new table has no data rows in it; it seems to run OK when I have data rows in the table.

If I go into Debug, I can put the formula in the new column's cell without an issue.

I've checked the formula parameter names, and they are all OK.

My code is:


Sub Make_Actions_table()
'---------------------
Dim colSrce     As ListColumn

'NB - the following variables have been declared at Project level

Set shtSrce = Sheet31
Set rngSrce = shtSrce.Range("A1").CurrentRegion
Set tblSrce = shtSrce.ListObjects.Add(xlSrcRange, rngSrce, , xlYes)

tblSrce.Name = "ActionsData"

Set colSrce = tblSrce.ListColumns.Add
colSrce.Name = "Overdue"

colSrce.DataBodyRange.FormulaR1C1 = _
    "=IF(AND(dteReportMonth > [@ActionNextDue], [@ActionLastClosed]="""")," & _
     """Y"", ""N"")"
end sub


Many thanks, Paul

 


Comment by: Jan Karel Pieterse (6/27/2017 10:13:35 AM)

Hi Paul,

You cannot add a formula to a table without any data, so the trick is to temporarily add a row. I also declared the variables in your code which did not have a Dim statement and removed the sheet variable and used Sheet31 instead.

Sub Make_Actions_table()
'---------------------
    Dim colSrce As ListColumn
    Dim tblSrce As ListObject
    Dim rngSrce As Range
    
    Dim bAddRow As Boolean
    'NB - the following variables have been declared at Project level

    Set rngSrce = Sheet31.Range("A1").CurrentRegion
    Set tblSrce = Sheet31.ListObjects.Add(xlSrcRange, rngSrce, , xlYes)

    tblSrce.Name = "ActionsData"

    Set colSrce = tblSrce.ListColumns.Add
    colSrce.Name = "Overdue"
    If tblSrce.ListRows.Count = 0 Then
        bAddRow = True
        tblSrce.ListRows.Add
    End If
    colSrce.DataBodyRange.FormulaR1C1 = _
    "=IF(AND(dteReportMonth > [@ActionNextDue], [@ActionLastClosed]="""")," & _
                                        """Y"", ""N"")"
    If bAddRow Then
        tblSrce.DataBodyRange.Delete
    End If
End Sub

 


Comment by: karen (8/17/2017 12:19:06 AM)

Quote requests come in and I record them in a table.
Based on the status cell, I need the rows to move to the appropriate table on a different sheet
I am not great at VBA - know just enough to be dangerous.
I've been able to move an entire row to the correct sheet but it pastes the data BELOW the actual table instead of inserting a new table row and pasting the data.
To keep it simple here are my columns
Date, Name, ID, Status
Here are my sheet/table names:
Quote, FollowUp, Awarded, Lost
This can get very large very quick so I'd prefer a simple code that didn't eat up resources.
Any help is GREATLY appreciated.

 


Comment by: Jan Karel Pieterse (8/17/2017 11:55:18 AM)

Hi Karen,

Instead of moving quotes to a new table each time their status changes, why not use one table and add a status column to it which you update?

 


Comment by: karen (8/17/2017 8:29:47 PM)

I need separate tables for different departments to work with. There would be thousands of projects in one table and we need to have them separate

 


Comment by: Jan Karel Pieterse (8/18/2017 3:01:49 PM)

What about adding a slicer on the new status column and one on the dept column, that way people can easily filter. An alternative is to create pivot tables from the main table and simply refresh them. That way you can keep input on one sheet and use the PTs as display per dept/status.

 


Comment by: Karen (8/18/2017 10:33:45 PM)

I don't understand. Is there a problem with moving table rows around? It sounds like there isn't a way to do it because you keep trying to suggest other things. Is that the case?

 


Comment by: Jan Karel Pieterse (8/21/2017 7:00:10 AM)

Hi Karen,

No of course not, I was just suggesting to reconsider your design as it might make things easier in a lot of aspects.

This routine copies the current row to the appropriate sheet:

Sub MoveQuote(oCell As Range)
    Dim oSourceLo As ListObject
    Dim oTargetLo As ListObject
    Set oSourceLo = Worksheets("Quote").ListObjects("Quote")
    Set oTargetLo = Worksheets(oCell.Value).ListObjects(oCell.Value)
    With oTargetLo.ListRows.Add
        Intersect(oSourceLo.DataBodyRange, oCell.EntireRow).Copy
        .Range.Cells(1, 1).PasteSpecial xlPasteValuesAndNumberFormats
    End With
End Sub


And if you add this to the worksheet module of sheet "Quote" it works automatically:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Intersect(Target, Me.ListObjects("Quote").ListColumns("Status").Range) Is Nothing Then Exit Sub
    MoveQuote Target.Cells(1, 1)
End Sub

Mind you, this copies a line as a new line everytime the status column is changed. There is no check if that quote was copied before, not to the same status sheet, nor to another one. You end up with that quote on every status tab which you have chosen to enter in the Status column. To avoid that you also need code that removes the line from all status sheets before copying.

 


Comment by: Tim (9/22/2017 7:24:23 AM)

Hi Karen
This has been very helpful, however it still lacks one element that I have failed to track down anywhere....
How does one COPY the formulae from one ListColumn DataBodyRange to another ListColumn DataBodyRange in the same Table.
I am trying to copy the formula from the first column into a newly added column. I can copy the first column....
eg

Dim oSh As Worksheet
Set oSh = ActiveSheet
Dim oLc As ListColumn
Set oLc = ActiveSheet.ListObjects("Table1").ListColumns.Add
ActiveSheet.ListObjects("Table1").ListColumns(1).DataBodyRange.Copy


But how do I paste the copied formulae into the newly added column?
Any suggestions would be extremely welcome.

 


Comment by: Jan Karel Pieterse (9/22/2017 3:48:20 PM)

Hi Tim,

YOu only have to copy the first cell of the column to the first cell of the other. In fact, no need to use Copy at all, just set the formula. This "copies" the formula from column 2 to the last one:

    Set oLo = ActiveCell.ListObject
    oLo.ListColumns(oLo.ListColumns.Count).DataBodyRange.Cells(1, 1).Formula = oLo.ListColumns(2).DataBodyRange.Cells(1, 1).Formula

 


Comment by: JAZIA (10/3/2017 3:12:44 PM)

I have a template
1. the template has a vlookup that uses the data table from another sheet called "datadealer" the table called "DealerDataTab"
2. I wrote a code on open workbook to make a table called "DealerDataTab" on "datadealer" sheet
3. as long as I used the data table on open workbook it looks like excel supposed the "DealerDataTab" table is already there and automatically created a data range with the name "DealerDataTab_1",
4. I don't want excel to suppose that the data table is already created when it reads the "DealerDataTab" in the formula.
5. how to do that?

 


Comment by: Jan Karel Pieterse (10/3/2017 4:52:12 PM)

Hi Jazia,

I'm not sure I understand your problem. Can you share a part of the code?

 


Comment by: JAZIA (10/3/2017 5:10:53 PM)

Thank you Jan
the following code should create the "DealerDataTab" data table, as long as I used the same data table name in my template formula if I open the workbook Excel supposed that data table is already there so it creates the same data range with _1 I don't want excel to suppose that the data range is already there because it's used in the formula, I want it instead to create the data table based on my code then I want it to make the calculations on template:

Sub MKTableDData()

Dim ws As Worksheet
Dim ob As ListObject
Dim Lrow1 As Long

    Range("A531:C531").Select
    ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A$531:$C$531"), , xlNo).Name = "DealerDataTab"
    Stop
Lrow1 = Sheets("DealerData").Cells(Rows.Count, "C").End(xlUp).Row
Set ws = ActiveWorkbook.Worksheets("DealerData")
Set ob = ws.ListObjects("DealerDataTab")

ob.Resize ob.Range.Resize(Lrow1)
ActiveSheet.ListObjects("DealerDataTab").Resize Range("$A$531:Lrow1")

End Sub

 


Comment by: Jan Karel Pieterse (10/4/2017 11:18:12 AM)

Hi Jazia,

So am I correct that you would like the code to:

- Check if the listObject is already there
- If not, create it
- If it is there, use it?

To test if it is already there:

Dim oLo as ListObject
On Error Resume Next
Set oLo = ActiveSheet.ListObjects("DealerDataTab")
On Error Goto 0
If oLo Is Nothing Then
    'Table wasn't there yet, create it
Else
    'Table is already present, use the oLo variable to manipulate it
End If

 


Comment by: JAZIA (10/4/2017 2:25:39 PM)

Excel supposed the table is there because I am using it in a formula at the template, so actually as long as I used the table name in the template excel supposed it is there, I am not sure if there is anyway to make excel create the table with the same name that used in the template formula

 


Comment by: Jan Karel Pieterse (10/4/2017 3:26:55 PM)

No, creating a table with a name already present in a workbook is not allowed. You could replace the content of the table however.

 


Comment by: JAZIA (10/4/2017 7:02:24 PM)

Thank you for helping,
it looks like I didn't explain it correctly, I know that I will never be able to create two data tables with same name, the question is: is there anyway to execute the vba code before reading the sheets formulas by Excel?

 


Comment by: Jan Karel Pieterse (10/5/2017 7:35:12 AM)

Hi Jazia,

No that isn't possible. And adding a new table and removing the existing one will wreck your formulas. You will have to update the existing table.

 


Comment by: JAZIA (10/5/2017 2:41:50 PM)

Thank you for your help, I will try that.

 


Comment by: Jake Burns (11/9/2017 1:54:13 AM)

Hey there, this page is so helpful! I have looked at it so many times, over and over again. Thank you for sharing so much knowledge! Jake

 


Comment by: bahmani.851402302@gmail.com (11/17/2017 6:47:26 PM)

hi this is nima. I have a question
How can delete all rows of tables,without deleteing headers and resize table to first row.thanks alot

 


Comment by: Jan Karel Pieterse (11/17/2017 8:51:51 PM)

Hi Nima,

Worksheets("Sheet1").ListObjects("Table1").DataBodyRange.Delete

 


Comment by: Mario Diaz (12/7/2017 4:29:54 PM)

Hi, Thanks for sharing your knowledge, is there a way in VB to look for a Raw within a table, using the data? Like a select statement in SQL.

 


Comment by: Jan Karel Pieterse (12/7/2017 10:42:50 PM)

Hi Mario,

You can use the MATCH worksjheetfunction from within VBA to find the matching row number:
Dim lRow As Long
lRow = Application.WorksheetFunction.Match("WhatYouWantToFind", ActiveSheet.ListObjects(1).ListColumns("ColumnA").DataBodyRange, 0)

 


Comment by: Damian (12/8/2017 1:22:55 AM)

Hi Jan,
I'm refreshing a table from sql server and have the following set
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Application.AutoCorrect.AutoFillFormulasInLists = False

When the table is refreshed with the sql data I'm getting a warning running slicer operation. There are approx 21,000 row in the table, with 8 slicers attached.
I only want the slicers refreshed at the end of the load process,once all the data is loaded. Any thoughts?
Regards
Damian

 


Comment by: Jan Karel Pieterse (12/12/2017 2:48:31 PM)

Hi Damian,

Perhaps removing the filter prior to reefreshing helps?

 


Have a question, comment or suggestion? Then please use this form.

If your question is not directly related to this web page, but rather a more general "How do I do this" Excel question, then I advise you to ask your question here: www.eileenslounge.com.

Please enter your name (required):

Your e-mail address (optional but if you want me to respond it helps!; will not be shown, nor be used to send you unsolicited information):

Your request or comment:

To post VBA code in your comment, use [VB] tags, like this: [VB]Code goes here[/VB].