In an Excel pivot table, when I select multiple items in a report filter, Excel just displays that I have selected multiple items.
Data
I can select multiple items:
However, once the selection is done, I don't see which elements I have selected.
I want to display which items are selected, e.g. when the report is printed. I found a way to do this using VBA and a user defined function.
Function GetVisibleItems(FieldName As String) As String
Dim PivotTable As PivotTable
Set PivotTable = ActiveSheet.PivotTables(1)
Dim PivotField As PivotField
Set PivotField = PivotTable.PivotFields(FieldName)
Dim PivotItem As PivotItem
Dim Result As String
For Each PivotItem In PivotField.PivotItems()
If PivotItem.Name <> "(blank)" Then
If PivotItem.Visible Then
If Len(Result) > 0 Then Result = Result & ", "
Result = Result & PivotItem.Name
End If
End If
Next
GetVisibleItems = Result
End Function
Is it possible to get the same result using just Excel formulae, not VBA?
Martin - This probably isn't as straight forward as you are looking for, but using workbook functions to build the string you are looking for ...
Below is a simple table of information ...
... and a pivot table created from it ...
In the pivot, you can see that Person 2 and Person 6 are filtered out.
Back at the table, a column was added using this formula (filled down) ...
=IF(ISERROR(GETPIVOTDATA("Grade",Sheet5!$A$3,$A$1,A2)),"",A2)
Note: Sheet5 contains the Pivot table. A3 is the top left corner of the pivot.
Providing this result ...
Where there are blanks instead of Person 2 and Person 6.
The string was generated using Chip Pearson's StringConcat UDF because it's more compact than all the typing needed with & or CONCATENATE ...
What I was looking for is provided by Slicers. A slicer shows the range that has been selected and is printable. Writing the list of visible Pivot Elements into a cell is possible, maybe even with a tricky Excel formula, but seems like over-engineering it.
The TEXTJOIN function can do this. Excel 2016 onwards.
The TEXTJOIN function combines the text from multiple ranges and/or strings, and includes a delimiter you specify between each text value that will be combined. If the delimiter is an empty text string, this function will effectively concatenate the ranges.
Related
I am trying to fill out a userform with data from an existing Pivot table.
If you see the included image you can see a selection of the pivot table.
In column “A” I have “week number” in Column “B” I have “Booking number”
I have managed to list all the “week number” (A) in a combobox by doing the following.
Dim pt As PivotTable
Set pt = ActiveSheet.PivotTables(1)
SendMailWindow.ComboBox_booking.Clear
pt.PivotSelect Name:="Uge nr.[All]", Mode:=xlLabelOnly, UseStandardName:=True
For Each c In Selection
If c <> "" Then
SendMailWindow.ComboBox_Uge.AddItem c.Value
End If
Next c
My problem now is that I want to have another combobox showing only the “Booking number” from column “B” there are within the select “weeknumber” that the user selects in the first Combobox.
In other words I want to filter Combobox no. 2 so that it only shows booking numbers from the selected week.
Hope one of you have an idea how to do this.
This would be much simpler if you changed the PivotTable Layout to Tablular (or made a copy of the PivotTable, and changed the copy's layout). Then you could simply use the type of syntax at https://peltiertech.com/referencing-pivot-table-ranges-in-vba/
In Jon's example, he does this:
Intersect(pt.PivotFields("Years").Pivotitems("2004").DataRange.EntireRow, pt.PivotFields("Order Date").DataRange).Select
In your case, that would translate to something like:
Intersect(pt.PivotFields("Week Number").Pivotitems(SomeVariable).DataRange.EntireRow, pt.PivotFields("Booking Number").DataRange).Select
I am currently experimenting using VBA and autofilter to query a dataset (as per Populate Excel Data Validation Drop-Down From Data Range Condition Using VBA )
However I am having trouble using VBA to refer to the auto filter results.
How can I collect results without needing to copy and paste? (for example to store a result as a variable)
How can I check how many results have been found, and trigger a msg box when the auto filter produces no results?
Thanks for your help
You may use the special parameters xlCellTypeVisible and SpecialCells.
Sub Test()
Dim SheetERP As Worksheet
Set SheetERP = Worksheets("MyDatas") 'Sheet with data
Dim myTabela As Excel.ListObject
Set myTabela = SheetERP.ListObjects("CodeData") 'Named Table range
Dim qtd As Integer 'To count filtered data rows (only visible)
qtd = SheetERP.ListObjects("CodeData").DataBodyRange.Columns(1).SpecialCells(xlCellTypeVisible).Count
'OR
qtd = myTabela.DataBodyRange.Columns(1).SpecialCells(xlCellTypeVisible).Count
MsgBox qtd
Dim TFiltro As Range
Set TFiltro = SheetERP.UsedRange.SpecialCells(xlCellTypeVisible)
'OR
Set TFiltro = myTabela.DataBodyRange.SpecialCells(xlCellTypeVisible)
'Do what you want with TFiltro
End Sub
The spreadsheet has multiple values in a cell.
What I'm trying to do is get that value found in a cell and paste it to another sheet and copy the other fields(columns) that belong to that value. How do I set the range in order copy the other fields(columns) up to the last column that has value? Thanks in advance.
For iRowGetProdCode = 0 To UBound(sSplitProdCode)
Sheets("Output").Cells(iRowCountOutput, 1).Value = sSplitProdCode(iRowGetProdCode)
iRowCountOutput = iRowCountOutput + 1
Next iRowGetProdCode
here is an idea how to discover an un-empty columns in the same row,
maybe you will find it useful and manipulate it for your needs:
Function LoopUntilLastColumn(ByVal Row As Integer)
Dim i As Integer
i = 1
Do While Cells(Row, i) <> ""
' do somthing
MsgBox (" I AM ALIVE COLUMN!")
i = i + 1
Loop
' you can also use the return value of the function.
LoopUntilLastColumn = i
End Function
I'm not exactly sure about what you're asking, but here are my three best guesses.
1.) Splitting delimited data from a single cell to columns
Without VBA: Use the "Text to Columns" function (Excel Ribbon:
Data|Data Tools).
With VBA: Use the split function MSDN (Related Post), then assign array values to target cells. Or parse your string manually with a loop.
2.) Finding the end of a continuous range
Without VBA: Use ctrl + arrow key
With VBA: Use the Range.End Property
3.) Looping through columns and rows
Used a nested loop:
For c = 1 to 5
For r = 1 to 20
Cells(r,c) = "Row = " & r & ", Column = " & C
Next
Next
Editing Suggestions (I don't have enough reputation to directly comment or edit)
This question as worded may be too specific for StackOverflow. Consider re-wording so that the problem can be understood in a general context and your question can be more useful to others.
Also, the wording is a little confusing. For example, use of the term "value" seems to change from referring to delimited data to referring to cell content in VBA. Likewise, it can be confusing to use "fields" or "columns" to describe the data if it's actually delimited text, so clarity on the data's state of existence would help.
It also seems to me that you've parsed the string on it's delimiter to an array, and that you're looping through this array to write the data in rows. I still can't see how exactly your question about setting a range fits in.
I want to get a list of column headers for each cell that contains a text value.
Eg.
A--------------B-------------C-------------BC (desired output)
1 Header1 Header2 Header3
2 M T Header1, Header3
3 T MT Header1, Header2
4 TMW Header2
In the final product I want to use two final columns with formulas listing headers from cells with values across 9 columns and a second with the other 40 odd columns.
I have the vague notion that I might need to use INDEX, MATCH and IF functions - but as a novice have no idea how to string them together coherently.
Here I will make use of VBA's Join function. VBA functions aren't directly available in Excel, so I wrap Join in a user-defined function that exposes the same functionality:
Function JoinXL(arr As Variant, Optional delimiter As String = " ")
JoinXL = Join(arr, delimiter)
End Function
The formula in D2 is:
=JoinXL(IF(NOT(ISBLANK(A2:C2)),$A$1:$C$1&", ",""),"")
entered as an array formula (using Ctrl-Shift-Enter). It is then copied down.
Explanation:
NOT(ISBLANK(A2:C2)) detects which cells have text in them; returns this array for row 2: {TRUE,FALSE,TRUE}
IF(NOT(ISBLANK(A2:C2)),$A$1:$C$1&", ","") converts those boolean values to row 1 contents followed by a comma delimiter; returns the array {"Header A, ","","Header C, "}.
JoinXL joins the contents of that array into a single string.
If you want to use worksheet functions, and not VBA, I suggest returning each column header in a separate cell. You can do this by entering a formula such as:
This formula must be array-entered:
BC: =IFERROR(INDEX($A$1:$C$1,1,SMALL((LEN($A2:$C2)>0)*COLUMN($A2:$C2),COUNTBLANK($A2:$C2)+COLUMNS($A:A))),"")
Adjust the range references A:C to reflect the columns actually used for your data. Be sure to use the same mixed address format as in above. Do NOT change the $A:A reference, however.
Then fill right until you get blanks; and fill down as far as required.
You can reverse the logic to get a list of the "other" headers.
To array-enter a formula, after entering
the formula into the cell or formula bar, hold down
ctrl-shift while hitting enter. If you did this
correctly, Excel will place braces {...} around the formula.
If you really need to have the results as comma-separated values in two different columns, I would suggest the following User Defined Function.
To enter this User Defined Function (UDF), alt-F11 opens the Visual Basic Editor.
Ensure your project is highlighted in the Project Explorer window.
Then, from the top menu, select Insert/Module and
paste the code below into the window that opens.
To use this User Defined Function (UDF), enter a formula like
=Headers($A2:$BA2,$A$1:$BA$1,True)
or, to get the headers that do NOT contain text:
=Headers($A2:$BA2,$A$1:$BA$1,FALSE)
in some cell.
=====================================================
Option Explicit
Function Headers(rData As Range, rHeaders As Range, Optional bTextPresent As Boolean = True) As String
Dim colHeaders As Collection
Dim vData, vHeaders
Const sDelimiter As String = ", "
Dim sRes() As String
Dim I As Long
vData = rData
vHeaders = rHeaders
Set colHeaders = New Collection
For I = 1 To UBound(vData, 2)
If (Len(vData(1, I)) > 0) = bTextPresent Then colHeaders.Add vHeaders(1, I)
Next I
ReDim sRes(1 To colHeaders.Count)
For I = 1 To colHeaders.Count
sRes(I) = colHeaders(I)
Next I
Headers = Join(sRes, sDelimiter)
End Function
==========================================
You should probably add some logic to the routine to ensure your range arguments are a single row, and that the two arguments are of the same size.
I am working in excel with a datasheet that is 1000 rows and 15 columns. Currently, in one of the columns, I have a lot of data mixed in with people names (see below for an example). I want to see how many times each person's name appears in the datasheet, so I can use it in a pivot table. There is no particular format or order to the way names appear. It is random. Is there a way to code in excel to search through that whole column and give me a count of the amount of times each person's name appears?
Column D
21421Adam14234
2323xxx Bob 66
23 asjdxx Jacob 665
43 Tim 5935539
2394Bob 88
After some trial and error, I can generate a list of names, one per row and place them in a different column for comparison sake, if that makes it easier.
I know you have got your answer but why not use COUNTIF with Wild Cards? You don't need VBA for this :)
See this example
=COUNTIF($A$1:$A$5,"*"&C1&"*")
SNAPSHOT
You don't have VBA tagged, but I don't know if there is a way to do this without it. I've built a custom function below. To implement it, take the following steps.
1) List desired names starting at column E1.
2) Insert this function into VBA Editor
A) Presss Alt + F11
B) Click Insert > Module from menu bar
C) Copy this code into Module
Option Explicit
Function findString(rngString As Range, rngSearch As Range) As Long
Dim cel As Range
Dim i As Integer
i = 0
For Each cel In rngSearch
If InStr(1, cel.Text, rngString.Value) > 0 Then
cel.offset(,-1) = rngString.Value 'places the name in cell to right of search range
i = i + 1
End If
Next
findString = i
End Function
3) In F1 type the following formula
=findstring(E1,$D$1:$D$5)
4) Run the formula down column F to get the count of each desired name.