Get value of pivotfields for a particular cell - vba

I have a pivot table from ssas connection. Several pivotfields are being used in the table. For this example let's say they are Size, Color, and Location. My goal is to write some vba where I pass the cell range and get the value of the corresponding pivotfields.
For example, If I pass the cell range for B6 I want to know that that cell is from location2 in color2 for size1. If I pass range B8 I get location1, Color3, Size1 etc.
Here is what I can do so far. I can get the value of the formula for that cell. Here is the result for B6: GETPIVOTDATA("[Measures].[myValues]",$A$1,"[d size].[size]","[d size].[size].&[Size1]","[d color].[color]","[d color].[color].&[Color2]","[d location].[location]","[d location].[location].&[location2]") with this code:
Function xxx(ByVal xyz As Range) As Variant
xxx = xyz.Formula
End Function
Sub blah()
MsgBox (xxx(ActiveWorkbook.Sheets("Sheet1").Range("D13")))
End Sub
I can also loop through the pivotfields and get their names, (but I don't know how to get their values) [Measures].[myValues], [d size].[size] etc... with this code:
With Worksheets("Sheet1").PivotTables(1)
For i = 1 To .PivotFields.Count
MsgBox .PivotFields(i).Name
Next
End With
My question is now, how do I get the value of those pivotfields for a particular cell. I would like to be able to send B6 and get back, or have access to: location2, Color2, Size1
Edit:
Getting closer... I can now loop through each field and get their names and values like this [d size].[size]&[Size1] etc, but now I want to be able to get just the value of Size1 or [Size1]:
Sub Test()
Dim iRange As Variant
iRange = ActiveCell.Address
FieldPicker (iRange)
End Sub
Function FieldPicker(targetCell As Variant) As Variant
With Range(targetCell).PivotCell
For i = 1 To .RowItems.Count
MsgBox .RowItems(i).SourceName
Next
End With
End Function

Adapted from RoryA's answer here: http://www.mrexcel.com/forum/excel-questions/332678-pivottable-problem.html
'Given a pivottable value cell and a category name, return the category value
'Note: you would need morte code to account for a "page" category
Function PivotCategoryValue(rngInput As Range, fldName As String) As String
Dim pc As PivotCell
Dim pf As PivotField, pi As PivotItem
Dim rv As String
On Error Resume Next
Set pc = rngInput.PivotCell
On Error GoTo err_handle
If pc Is Nothing Then
rv = "Not a pivot cell"
Else
Select Case pc.PivotCellType
Case xlPivotCellValue
If pc.RowItems.Count Then
For Each pi In pc.RowItems
If pi.Parent.Name = fldName Then
rv = pi.Value
GoTo done
End If
Next pi
End If
If pc.ColumnItems.Count Then
For Each pi In pc.ColumnItems
If pi.Parent.Name = fldName Then
rv = pi.Value
GoTo done
End If
Next pi
End If
Case Else
rv = "Not a pivot data cell"
End Select
End If
done:
PivotCategoryValue = rv
Exit Function
err_handle:
PivotCategoryValue = "Unknown error"
End Function

Related

# VALUE Error while executing UDF VBA Function on formatted cells

I wrote the following function to check if the prerequisites for my Excel row are satisified.
Public Function PREREQUISITESOK(prerequisites As Range) As String
Dim cw As Worksheet
Dim prerequisite_cell As Range
Dim prerequisite_cell_txt As String
Dim training_id_cell As Range
Dim no_groups_cell_to_compare As Range
Dim no_groups_cell_to_check As Range
Dim training_id_cell_txt As String
Dim training_id_cell_row_n As Integer
Dim n As Integer
Application.Volatile
PREREQUISITESOK = "OK"
Set cw = Sheets("4c.Trainings OSS")
Set training_id = cw.Range("$B$11:$B$34")
Set no_groups_cell_to_compare = cw.Range("J" & CStr(prerequisites.Row))
For Each prerequisite_cell In prerequisites.Cells
prerequisite_cell_txt = prerequisite_cell.Text
If prerequisite_cell_txt = "" Then
Exit For
Else
For Each training_id_cell In training_id.Cells
training_id_cell_txt = training_id_cell.Text
If training_id_cell_txt = prerequisite_cell_txt Then
training_id_cell_row_n = training_id_cell.Row
Set no_groups_cell_to_check = cw.Cells(training_id_cell_row_n, no_groups_cell_to_compare.Column)
If no_groups_cell_to_check.Value < no_groups_cell_to_compare.Value Then
PREREQUISITESOK = "NOT OK"
Exit Function 'It is enough for us that one prerequisite is not satisfied so we can exit the function
Else
PREREQUISITESOK = "OK"
End If
Exit For 'Training IDs are unique so if we find the right Training ID then we may exit the loop
End If
Next training_id_cell
End If
Next prerequisite_cell
End Function
Note that the prerequisites range is inline formatted.
The function that I wrote is supposed to return String value so I completely do not understand why am I getting #VALUE! error.
What is interesting that if I clear formatting from the prerequisites cells that are used as arguments of the function then #VALUE! error disappears.
Do you have any idea why this happens?

Simple cipher in VBA in Excel using a table for substitution

I want to write a simple cipher in Excel which would take a text from a cell, substitute each letter for a number from adjacent column and then put the output in another cell. Can't get VLOOKUP to work - it works as a formula, but somehow can't get it to work inside VBA code. Tried to do a simple procedure first that would do this for one character (adding a loop later would be easy), but it doesn't work. It compiles, but when I run it (press a button I assigned it to) I get "#N/A" in the result cell.
Sub Zakoduj()
Dim Literka As String
Dim Liczba As Variant
Dim ColumnToTake As Integer
ColumnToTake = 1 ' Liczby
On Error Resume Next
Err.Clear
Literka = Sheets("Sheet2").Range("B2").Value
Liczba = Application.VLookup(Literka, Sheets("Sheet1").Range("A5:B39"), ColumnToTake, False)
If Err.Number = 0 Then
Sheet2.Range("B6").Value = Liczba
Else
Sheet2.Range("B6").Value = Err.Number
End If
End Sub
The range contains number and characters as follows:
Kod Litera
16 A
73 B
12 C
40 D
70 E
etc. etc.
Couldn't find a tutorial that would explain how to do this...
Here is a modified version. Note that the values are in A1:B6 on sheet 1
Option Explicit
Sub Zakoduj()
Dim Literka As Integer
Dim Liczba As String
Dim ColumnToTake As Integer
ColumnToTake = 2 ' Liczby
Literka = Sheets("Sheet2").Range("B2").Value
Liczba = "Value not found" 'If value is not found
On Error Resume Next
Liczba = Application.WorksheetFunction.VLookup(Literka, Sheets("Sheet1").Range("A1:B6"), ColumnToTake, False)
On Error GoTo 0 'Always reset error handling after On Error Resume Next
Sheet2.Range("B6").Value = Liczba
End Sub

Change Part of text font in Excel cell using vba

Hi I am trying to create a function to calculate milliohms (mOhms)
my function is
Function mOhms(Current, Voltage)
mOhms = Format((Voltage / Current) * 1000, "00.00 m") & Chr(87)
End Function
with results being
40.00 mW
(if cell values are 24 and 1 respectivly)
How do i get the W as (Ω) ohms symbol
if i change the cell font style to Symbol m changes to micro (μ) symbol
i have tried paying with
With ActiveCell.Characters(Start:=Len(ActiveCell) - 1, Length:=1).Font
.FontStyle = "Symbol"
End With
Which results in "Circular reference error"s
Need some help to resolve this
Try using Unicode in place of the Chr(87)
Function mOhms(Current, Voltage)
mOhms = Format((Voltage / Current) * 1000, "00.00 m") & ChrW(&H2126)
End Function
should you want to stick with Characters object you have to:
use Name property, instead of FontStyle one
set its Start parameter to the last character of the range text, instead of the second to last one
so you may want to code like follows:
Sub main()
With Range("G1") '<--| change this to any valid Range reference
.Value = mOhms(24, 1) '<--| set the referenced range value
FormatOhm .Cells '<--| format the referenced range value last character
End With
End Sub
Function mOhms(Current, Voltage)
mOhms = Format((Voltage / Current) * 1000, "00.00 m") & Chr(87)
End Function
Sub FormatOhm(rng As Range)
With rng
.Characters(Start:=Len(.Value), Length:=1).Font.name = "Symbol"
End With
End Sub
a possible enhancement of which could be the handling of "W" character actual position in the string, should it not always be the last character
then you could add the following function:
Function GetCharacter(rng As Range, char As String) As Long
Dim i As Long
With rng
For i = 1 To .Characters.Count
If .Characters(i, 1).Text = char Then
GetCharacter = i
Exit For
End If
Next i
End With
End Function
that returns a Long with the passed character position inside the passed range value or 0 if no match occurred
in this case you'd have to slightly change FormatOhm() function to have it handle the actual character position:
Sub FormatOhm(rng As Range, iChar As Long)
If iChar = 0 Then Exit Sub '<--| exit if no character matching occurred
With rng
.Characters(Start:=iChar, Length:=1).Font.name = "Symbol"
End With
End Sub
and your "main" code would then get to:
Sub main()
With Range("G1") '<--| change this to any valid Range reference
.Value = mOhms(24, 1) '<--| set the referenced range value
FormatOhm .Cells, GetCharacter(.Cells, "W") '<--| format the referenced range value character corresponding to "W", if any
End With
End Sub
of course what above could be further both improved and made more robust, for instance handling char parameter length in GetCharacter() and correspondingly in FormatOhm()

Why is assigning the Value property of cell causing code to end aburptly?

Private Sub FillRow(programCell As Range, storedProgramCell As Range)
Dim counter As Integer
For counter = 3 To 9
Dim cellOffset As Integer
cellOffset = counter - 3
Dim currentStoredCell As Range
Set currentStoredCell = storedProgramCell.Offset(0, cellOffset)
Dim value As String
value = currentStoredCell.value
Dim currentTargetCell As Range
Set currentTargetCell = programCell.Offset(0, cellOffset)
MsgBox currentStoredCell.value 'Works correctly, prints correct value
currentTargetCell.value = value
Next counter
End Sub
The line:
currentTargetCell.value = value
causes the code to stop executing, with no error.
I added the expression to my watch list, then stepped through the routine. The expression was seen as a Boolean:
This makes me think the expression is being viewed as a comparison, and the program abruptly ends since the returned Boolean is not being stored or used anywhere. I wouldn't doubt if I were wrong though.
I'm new to VBA, struggling to debug my program, so please forgive me if this is a petty mistake. I couldn't find any sources online that explains this problem.
Replace your subroutine with following code:
Private Sub FillRow(Dst As Range, Src As Range)
Dim x As Integer
Dim v As Variant
Dim Srcx As Range
Dim Dstx As Range
Debug.Print "FillRow"
Debug.Print Src.Address
Debug.Print Dst.Address
Debug.Print "Loop"
For x = 0 To 6
Debug.Print x
Set Srcx = Src.Offset(0, x)
Debug.Print Srcx.Address
v = Srcx.Value
Debug.Print TypeName(v)
Set Dstx = Dst.Offset(0, x)
Debug.Print Dstx.Address
Dstx.Value = v
Next
Debug.Print "Completed"
End Sub
Run and post in your question Immediate window output.
Value is a reserved word, even if vba does not raise an error on this name, you should not use it. Name it something else. Also, try setting it as a variant.

Knowing the assigned name of a cell instead of the "A1" name

Context:
I have several lists in my sheet (1 column wide, 1-10 rows long). When I right click a cell in these lists, I can do several options, that all work well. I have given a name to the cell at the top of each of these lists (ex. Cell A1 has been given the name cell_1, B10 is names cell_2, etc).
I would like to know if the cell I am right clicking on is the one at the top of the list; is it named "cell_(number)"? If it is not, it checks the cell on top of that one. Does it have a name that starts with "cell_"? If not, check the one on top, etc. Until I can figure out the user clicked on an element of WHICH list.
TL;DR The actual question
I can use ActiveCell.Address, which gives me something like "A1" whether or not I have assigned a name to that cell. ActiveCell.Name gives "Sheet1!A1", so it's not much better. Any idea how to get it to return the name I have assigned instead?
Create a UDF to test the application names, it's less efficient but contains error handling within the function itself:
Sub SO()
'// Example how to call function
Debug.Print GetCellName(Range("A1"))
End Sub
Function GetCellName(myCell As Excel.Range) As Variant
Dim nameCheck As Variant
For Each nameCheck In Application.Names
If Replace(Replace(Replace(nameCheck, "=", ""), "'", ""), "!", "") = _
CStr(myCell.Parent.Name & myCell.Address) Then
GetCellName = CStr(nameCheck.Name)
Exit Function
End If
Next
GetCellName = CVErr(Excel.xlErrName)
End Function
Note you can also use this function in a worksheet cell like so:
=GetCellName(A1)
Perhaps this would work. This function returns the names assigned to a cell (or bigger range for that matter). If there's more than one name, it returns it as an array for array formula...or the user can supply an index to return only the desired name position
Public Function CellIsInRangeNames(sheetname As String, checkRange As Range, Optional itemNumber As Variant) As Variant
Dim oNM As Name
Dim oSht As Worksheet
Dim isect As Range
Dim namesCollection() As Variant
Set oSht = Worksheets(sheetname)
Dim i As Integer
i = -1
For Each oNM In oSht.Names
Set isect = Application.Intersect(Range(oNM.Name), checkRange)
If Not isect Is Nothing Then
i = i + 1
ReDim Preserve namesCollection(0 To i)
namesCollection(i) = CStr(oNM.Name)
End If
Next oNM
If i = -1 Then
'didn't find any
CellIsInRangeNames = xlErrName
ElseIf Not IsMissing(itemNumber) Then
'user wanted this instance only
If (itemNumber - 1 > UBound(namesCollection)) Or (itemNumber - 1 < LBound(namesCollection)) Then
CellIsInRangeNames = xlErrValue
Else
CellIsInRangeNames = namesCollection(itemNumber - 1)
End If
Else 'here's the list as an array
CellIsInRangeNames = namesCollection
End If
End Function