So im currently working a table in excel that I have named Table1 with three columns (Column 1, Column 2 and Column 3). Ive been trying to count the used rows or populated rows inside the table using VBA but have had no luck.
Example 1:
UsedRows= Sheets ("Sheet1").ListObjects.("Table1[#Column 1]").UsedRange.ListRows.Count
Example 2 (This One Returns only all available rows)
UsedRows= Sheets ("Sheet1").ListObjects.("Table1[#Column 1]").ListRows.Count
I either want the populated or unpolulated row amount. Either of the two will work just fine. Remember this is a Table so End(xlUp) and End(xlDown) work a little bit different. Ive tried those too but I still get either the total rows available or the cells that are modified which is way more than what I have available.
Thanks for the help in adavanced whoever posts.
Sounds like you can use CountA, like this perhaps:
Dim myColumn As ListColumn
Set myColumn = Sheets("Sheet1").ListObjects("Table1").ListColumns("Column 1")
Dim UsedRows As Long
UsedRows = Application.CountA(myColumn.DataBodyRange)
Debug.Print UsedRows
If you don't have blank cells in other rows. The 3 doesn't need to be hard-coded, this is just the number of columns in your table.
Sub x()
Dim r As Range
Set r = ActiveSheet.ListObjects(1).DataBodyRange
With WorksheetFunction
MsgBox .CountBlank(r) / 3 'empty rows
MsgBox (r.Rows.Count - .CountBlank(r) / 3) 'non-empty rows
End With
End Sub
Related
I have a problem with a vba macro that i can't seem to find the answer to anywhere. Feels like i've tried everyting so i'll put the question out there to see if anyone here can help me :)
My macro loops through 50 woorkbooks that all have a "Firstpage" where the data from all the other data worksheets are summarized. In that Firstpage i have a table called "Tabell_1". The table has a header row (B4:F4) and then one row for each data worksheet in the workbook and the a sum row. We have decided to add a new column (column D) to the table to add in data from a specific cell in all the other worksheets (B4).
I now loop through the data worksheets to copy the value in B4 and then i want to paste that value to the first empty row in the table on the "Firstpage" (starting from the cell under the header). The method to find the last row that i use in other parts of the macro doesn't work, it gives me the first row after the sum row and then pastes the values under the table.
The picture shows the table that i'm working with for one of the workbooks.
enter image description here
Hej Johanna!
Assuming that you are using listobjects to manage the data I would just do this..
Sub Test2()
Dim lo As ListObject
Dim lr As ListRow
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set lo = ws.ListObjects("Tabell_1")
Count = 1
For Each lr In lo.ListRows
If lo.ListColumns("Test2").DataBodyRange(lr.Index) = "" Then
lo.ListColumns("Test2").DataBodyRange(lr.Index) = Count
Count = Count + 1
End If
Next lr
End Sub
This is will fill the first empty row in column Test2.
Hopefully you can use this example :)
I am working with tables in Excel (ListObject). I apply filter via VBA on a table which work fine. I would like to read specific row (or row, col) from filtered table. I tried with SpecialCells which return a range of cells. But I would like to iterate as rows like listobject.listrows(N) where n is number of row. I didn't find any example. Of course I can iterate cell by cell and locate the the row via formula. But I wonder if exist a better way.
For instance: I would like filter a table with several criteria and update certain columns with a particular value.
I hope I am clear with my question.
thanks.
You can loop rows like this
Option Explicit
Sub test()
Dim rng As Range
With ActiveSheet.ListObjects(1).DataBodyRange
For Each rng In .SpecialCells(xlCellTypeVisible).Rows
Debug.Print rng.Address
Next rng
End With
End Sub
I want to write a formula like =SUM(tab2!A:A) but instead use the column title of A which is say "count". How can I modify this to look more like: =SUM(tab2!"count")?
The reason I want to do this is because I copy and paste a spreadsheet from another source in tab2 and the column referring to "count" may be in a different column. I want the formula to give me the correct calculation as soon as I paste the new spreadsheet by automatically finding the column to sum up by title name.
I must be missing something because this seems like a very basic question and I can't find the answer anywhere...
Thanks for your help!
I like the idea of naming ranges proposed by #Doug, but if the issue is that you are dumping your data in [and you don't know in advance which column is going to be where] and would need to rename your range every time, there are other options - I suggest using OFFSET. OFFSET allows you to dynamically create a range, starting at a particular point and moving down/up / right/left for as many rows and columns as you determine.
In your case, you will need to combine that with a method for searching the columns to see which one says "Count". I am assuming that your column headings are always in row 1. If they aren't [or if they aren't always in row 2, or any row you know in advance]... you can get around that but then I'd recommend you try to make your data more uniform instead of creating unnecessary Excel workarounds.
In total your formula would look like this:
=SUM(OFFSET(A1,,MATCH("Count",1:1,0)-1,ROWS(A:A),1))
What this does is first determine which column the word "Count" is found in, in row 1. Then it subtracts 1 from that number - this now equals the number of columns to the right that it is, from column A. It uses offset to create a reference to that column, for all rows, and sums those rows together.
Check out the name manager for naming ranges :)
You didn't say whether you would consider a macro solution. If so, this may work.
If the sheet you are pasting into is Sheet2 and the sheet you want the result in is Sheet1, then this macro, if placed in the Worksheet_Activate event of Sheet1 will give you the result as soon as you click on the Sheet1 tab afetr pasting your data into Sheet2:
Private Sub Worksheet_Activate()
Dim r As Range
Dim rCol As Range
Dim rFound As Range
Dim ws As Worksheet
Dim lTotal As Long
Set ws = Sheet2
Set r = ws.Cells
Set rFound = r.Find("count")
If Not rFound Is Nothing Then
Set rCol = rFound.EntireColumn
lTotal = Application.WorksheetFunction.Sum(rCol)
End If
Cells(1, 1) = lTotal
End Sub
It does assume there is only one cell with the word "count" in it on Sheet2.
Currently I have a medical spread-sheet with a list of clients that we have serviced. We have 8 different clinical categories which are denoted by different acronyms - HV,SV,CV,WV,CC,OV,TS and GS.
A client can receive multiple therapies i.e. HV,SV,CV - in the background we have a counter mechanism which would increment each of these records by 1.The formula used for this counter is:
=(LEN('Parent Sheet'!F25)-LEN(SUBSTITUTE('Parent Sheet'!F25,'Parent Sheet'!$P$4,"")))/LEN('Parent Sheet'!$P$4)
At the bottom of the sheet we then have a sum which ads up all the treatments that occurred for that week.
Now the tricky part about this is that we have almost a year's worth of data in this sheet but the summing formulas are set as: SUM(COLUMN 6: COLUMN 53) but due to a need to increase the entries beyond this limit, we have to adjust the sum formula. We have 300 SUM Formulas adding up each of the 8 Criteria items and assigning them to the HV,SV,SC,WV etc. counters.
Would we have to adjust this manually one by one or is there a easier way of doing this?
Thank you very much!
To me, I think you should change the sheet layout a little, create a User Defined Function (UDF) and alter the formulas in your Sum rows for efficient row/column adding (to make use of Excel's formula fill). The only issue is that you need to save this as a Macro-Enabled file.
What you need to change in the formulas is to utilize $ to restrict changes in column and rows when the formula fill takes place.
To illustrate in an example, consider:
Assuming the first data starts at row 6, and no more than row 15 (you can use the idea of another data gap on the top). Alter the Sum row titles to begin with the abbreviation then create a UDF like below:
Option Explicit
' The oRngType refers to a cell where the abbreviation is stored
' The oRngCount refers to cells that the abbreviation is to be counted
' Say "HV" is stored in $C16, and the cells to count for HV is D$6:D$15,
' then the sum of HV for that date (D16) is calculated by formula
' `=CountType($C16, D$6:D$15)`
Function CountType(ByRef oRngType As Range, ByRef oRngCount) As Long
Dim oRngVal As Variant, oVal As Variant, oTmp As Variant, sLookFor As String, count As Long
sLookFor = Left(oRngType.Value, 2)
oRngVal = oRngCount.Value ' Load all the values onto memory
count = 0
For Each oVal In oRngVal
If Not IsEmpty(oVal) Then
For Each oTmp In Split(oVal, ",")
If InStr(1, oTmp, sLookFor, vbTextCompare) > 0 Then count = count + 1
Next
End If
Next
CountType = count
End Function
Formulas in the sheet:
Columns to sum are fixed to rows 6 to 15 and Type to lookup is fixed to Column C
D16 | =CountType($C16,D$6:D$15)
D17 | =CountType($C17,D$6:D$15)
...
E16 | =CountType($C16,E$6:E$15)
E17 | =CountType($C17,E$6:E$15)
The way I created the UDF is to lookup and count appearances of a cell value (first argument) within a range of cells (second argument). So you can use it to count a type of treatment for a big range of cells (column G).
Now if you add many columns after F, you just need to use the AutoFill and the appropriate rows and columns will be there.
You can also create another VBA Sub to add rows and columns and formulas for you, but that's a different question.
It's isn't a great idea to have 300 sum formulas.
Name your data range and include that inside the SUM formula. So each time the NAMED data range expands, the sum gets calculated based on that. Here's how to create a dynamic named rnage.
Sorry I just saw your comment. Following is a simple/crude VBA snippet.
Range("B3:F12") is rangeValue; Range("C18") is rngTotal.
Option Explicit
Sub SumAll()
Dim WS As Worksheet
Dim rngSum As Range
Dim rngData As Range
Dim rowCount As Integer
Dim colCount As Integer
Dim i As Integer
Dim varSum As Variant
'assuming that your said mechanism increases the data range by 1 row
Set WS = ThisWorkbook.Sheets("Sheet2")
Set rngData = WS.Range("valueRange")
Set rngSum = WS.Range("rngTotal")
colCount = rngData.Columns.Count
'to take the newly added row (by your internal mechanism) into consideration
rowCount = rngData.Rows.Count + 1
ReDim varSum(0 To colCount)
For i = 0 To UBound(varSum, 1)
varSum(i) = Application.Sum(rngData.Resize(rowCount, 1).Offset(, i))
Next i
'transpose variant array with totals to sheet range
rngSum.Resize(colCount, 1).Value = Application.Transpose(varSum)
'release objects in the memory
Set rngSum = Nothing
Set rngData = Nothing
Set WS = Nothing
Set varSum = Nothing
End Sub
Screen:
You can use named ranges as suggested by bonCodigo or you could use find and replace or you can insert the columns within the data range and Excel will update the formula for you automatically.
I realize that this is probably a duplicate, but I've been searching for an hour and I can't to get the syntax right.
I have a sheet with several tables. There is at least one empty column and one empty row between one table to the other.
I know the start row and start column of each table, and I know that each table has 3 columns. I don't know how many rows it has.
I want to write a sub that receives:
table start row
table start column
and copies the table into another sheet (let's say that the destination is sheet2 starting at A1).
I know I can do it with a loop, but I suspect there is a better syntax right?
(The main issue here is that I need to find the number of rows each table has)
Thanks.
Li
This sub will do the job:
Sub CopyTable(wsSource As Worksheet, lngTopRow As Long, intLeftCol As Integer, rngTarget As Range)
Dim rngSource As Range
Dim intCols As Integer, lngRows As Long
Set rngSource = wsSource.Cells(lngTopRow, intLeftCol)
intCols = rngSource.End(xlToRight).Column - intLeftCol + 1
lngRows = wsSource.Cells(wsSource.Rows.Count, intLeftCol).End(xlUp).Row - lngTopRow + 1
rngSource.Resize(lngRows, intCols).Copy rngTarget
End Sub
To copy a table starting in rows 1, column 5 of worksheet1 to Sheet2!A2, use the following call:
CopyTable Sheets("Sheet1"), 1, 5, Sheets("Sheet2").Range("A2")
This assumes that there's nothing below each table. If that is not the case, replace the 3rd instruction with
lngRows = rngSource.End(xlDown).Row - lngTopRow + 1
This will now assume, that the first column of your table has no gaps. If this is not true, try using rngSource.UsedRange.Row instead of rngSource.End(xlDown).Row!