Missing value of measure (calculated member ) - sql-server

I've got a data warehouse which is underlying database of OLAP cube.
When I run query like that:
SELECT dimS.Attribute2,SUM(fact.LastValue)
FROM FactTable fact
JOIN DimS dimS ON fact.DimSKey = DimS.DimSKey
GROUP BY DimSKey.Attribute2
I can see that all existing Attribute2 at dimS table have corresponding rows at fact table.
On the other hand I've got a calculated measure:
CREATE MEMBER CURRENTCUBE.[MEASURES].[MyMeasure]
AS ([Measures].[FactTable - LastValue]
, [DimS].[S Hierarchy].[All].[Hierarchy SomeName]
, [DimS].[Category].[All]
, [DimS].[Question].CurrentMember
, [CimC].[Status].&[Active]
),DISPLAY_FOLDER='Folder',VISIBLE = 1;
and when running below MDX:
SELECT
{ [Measures].[MyMeasure] } ON COLUMNS,
{ ([Survey].[Attribute2].ALLMEMBERS ) } ON ROWS
FROM [MyCube]
I can see that 2 of Attribute2 have no values (null) assigned to them.
What can cause issue like that (DimS and cube has been just processed fully)?

Found the rootcause.
the reference in MDX definition of calculated measure to [DimS].[S Hierarchy].[All].[Hierarchy SomeName] is another calculated measure where actually we have hardcoded values within dimension hierarchy. And for [Attribute2] this condition is not met.

Related

How to show #ERROR as Zero or as Nothing in matrix cell when groups and calculated field are based on switch-function in SSRS?

Imagine simple BI task:
We have two grouping columns and one calculated field.
like
select group1, group2, sum(sales) Sum_of_sales from dbo.table1
group by group1, group2
When for some combination of grouping columns there's no ROW in dataset - report shows me Empty. It's ok.
Now i'm building matrix with groups depending on parametrs. Some sort of programmatic matrix. User deciedes what to analyze by himself. He chooses X_dimension and Y_dimension and target CalculatedField
Grouping expression for first group now looks like
=Switch(
Parameters!param1.Value = "var1", Fields!groupingColumn1.Value,
Parameters!param1.Value = "var2", Fields!groupingColumn2.Value)
And for second group
=Switch(
Parameters!param2.Value = "var3", Fields!groupingColumn3.Value,
Parameters!param2.Value = "var4", Fields!groupingColumn4.Value)
With target value:
=Switch(
Parameters!param3.Value = "var5", Count(Fields!sales_sum.Value),
Parameters!param3.Value = "var6", Sum(Fields!sales_sum.Value)
)
When there are sales in combinations of groups - it's ok. It shows me exact value - like i would sum it with calculator. But when THERE'S NO DATA for some partition - it just raises error in that cell. And it seems like no way out. Pls help.
P.S. I tried all possible variants such as
iif(sum(...) is Nothing, 0 , sum(...))
sum(iif(value > 0 , value , 0))
and combination of them
i tried comparing with ZERO, Nothing , and checking isNothing
but i still get error in cell

Weighted Average w/ Array Formula & Query That Pulls From A Separate Sheet

Link To Sheet
So I've got an array formula which I've included below. I need to adjust this so that it becomes a weighted average based on variables stored on a sheet titled Variables.
Current Formula:
=ARRAYFORMULA(QUERY(
{PROPER(ADP!A3:A),ADP!E3:S;
PROPER(ADP!J3:J),ADP!S3:S;
PROPER(ADP!Z3:Z),ADP!AG3:AG},
"select Col1, Sum(Col2)
where
Col2 is not null and
Col1 is not null
group by Col1
order by Sum(Col2)
label
Col1 'PLAYER',
Sum(Col2) 'ADP AVG'"))
Here's what I thought would work but doesn't:
=ARRAYFORMULA(QUERY(
{PROPER(ADP!A3:A),ADP!E3:E*(Variables!$F$11/Variables!$F$14);
PROPER(ADP!J3:J),ADP!S3:S*(Variables!$F$12/Variables!$F$14);
PROPER(ADP!Z3:Z),ADP!AG3:AG*(Variables!$F$13/Variables!$F$14)},
"select Col1, Sum(Col2)
where
Col2 is not null and
Col1 is not null
group by Col1
order by Sum(Col2)
label
Col1 'PLAYER',
Sum(Col2) 'ADP AVG'"))
What I'm trying to get is the value pulled in K to be multiplied by the value in VariablesF11, the value pulled in Y to be multiplied by VariablesF12, and the value in AL multiplied by the variables in F13. And have that numerator divided by the value in VariablesF14.
After our extensive chat, I'm providing here the answer we came up with, just on the chance it might somehow help someone else. But the issue in your case was less about the technicalities of the formula, and more about the structuring of multiple data sources, and the associated logic to pull the data together.
Here is the main formula:
={"Adjusted
Ranking
by " & Variables!F21;
arrayformula(
if(A2:A<>"",
( if(((D2:D>0) * Source1Used),D2:D,Variables!$F$21)*Variables!$F$12
+ if(((F2:F>0) * Source2Used),F2:F,Variables!$F$21)*Variables!$F$13
+ if(((H2:H>0) * Source3Used),H2:H,Variables!$F$21)*Variables!$F$14
+ if(((J2:J>0) * Source4Used),J2:J,Variables!$F$21)*Variables!$F$15
+ if(((L2:L>0) * Source5Used),L2:L,Variables!$F$21)*Variables!$F$16
+ if(((N2:N>0) * Source6Used),N2:N,Variables!$F$21)*Variables!$F$17 )) / Variables!$F$18) }
A2:A is the list of players' names. The D2:D>0 is a test of whether that player has a rating obtained from a particular data source.
Source1Used is a named range for a tickbox cell, where the user can indicate whether that data source is to be included in the calculations.
This formula creates an average value, using from 1 to 6 possible sources, user selectable.
The formula that gave the rating value for one specific source is as follows:
={"Rating in
Source1";ArrayFormula(if(A2:A<>"",if(C2:C,vlookup(A2:A,indirect("ADP!$" & ADP!E3 & "$10:" & ADP!E5),ADP!E6-ADP!E4+1,0),0),""))}
This takes a name in column A, checks if it is listed in a specific source's data, and if so, it pulls back the rating value from the data source. INDIRECT is used since the column locations for each data source may vary, but are obtained from a fixed table, in cells ADP!E3 and E5. E4 and E6 are the numeric values of the column letters.

Counting rows in a table based on multiple array criterias

I am trying to count rows in a table based on multiple criteria in different columns of that table. The criteria are not directly in the formula though; they are arrays which I would like to refer to (and not list them in the formula directly).
Range table example:
Group Status
a 1
b 4
b 6
c 4
a 6
d 5
d 4
a 2
b 2
d 3
b 2
c 1
c 2
c 1
a 4
b 3
Criteria/arrays example:
group
a
b
status
1
2
3
I am able to do this if i only have one array search through a range (1 column) in that table:
{=SUM(COUNTIFS(data[Group],group[group]))}
Returns "9" as expected (=sum of rows in the group column of the data table which match any values in group[group])
But if I add a second different range and a different array I get an incorrect result:
{=SUM(COUNTIFS(data[Group],group[group], data[Status],status[status]))}
Returns "3" but should return "5" (=sum of rows which have 1, 2 or 3 in the status column and a or b in the group column)
I searched and googled for various ideas related to using sumproduct or defining arrays within the formula instead of classifying the whole formula as an array but I was not able to get expected results via those means.
Thank you for your help.
Because your group and status criteria are a different number of values (2 values for group, but 3 values for status), I'm not sure you can do this in a single formula. Best way I know of to do this would be to use a helper column (which can be hidden if preferred).
Put this array formula in a helper column and copy down the length of your data (array formulas must be confirmed with Ctrl+Shift+Enter):
=AND(OR(data[#Group]=group[group]),OR(data[#Status]=status[status]))
And then get the count with: =COUNTIF(helpercolumn,TRUE)
You could use a slightly different approach, using Power Query / Power Pivot.
Name your tables Data, Group and Status, then create the following query, named Filtered Data:
let
tbData = Excel.CurrentWorkbook(){[Name="Data"]}[Content],
tbGroup = Excel.CurrentWorkbook(){[Name="Group"]}[Content],
tbStatus = Excel.CurrentWorkbook(){[Name="Status"]}[Content],
#"Merged Group" = Table.NestedJoin(tbData,{"Group"},tbGroup,{"Group"},"tbGroup",JoinKind.Inner),
#"Merged Status" = Table.NestedJoin(#"Merged Group",{"Status"},tbStatus,{"Status"},"Merged Status",JoinKind.Inner),
#"Removed Columns" = Table.RemoveColumns(#"Merged Status",{"tbGroup", "Merged Status"}),
#"Changed Type" = Table.TransformColumnTypes(#"Removed Columns",{{"Status", type number}})
in
#"Changed Type"
Load To as connection only, and tick Load to Data Model
Now create a DAX measure:
Status Sum:=SUM ( 'Filtered Data'[Status] )
You can then use the following formula on your worksheet, to get the Sum of Status values, for rows matching the criteria specified in the Group and Status tables:
=CUBEVALUE("ThisWorkbookDataModel","[Measures].[Status Sum]")
Simply refresh the data connection to update the value.

Make a new array with items derived from another array

Given a PostgreSQL ARRAY of items of one type, how can I create a new array where each item is derived from the items in the initial array?
Example: I have an array of INTERVAL values. I want a new array where each item is a NUMERIC(10, 1) that is the total number of seconds in the corresponding INTERVAL value.
I know how to convert one INTERVAL value:
foo=> SELECT '00:01:20.000'::INTERVAL AS duration_interval;
duration_interval
-------------------
00:01:20
(1 row)
foo=> SELECT extract(EPOCH FROM date_trunc('second', '00:01:20.000'::INTERVAL))
::NUMERIC(10, 1) AS duration_seconds;
duration_seconds
------------------
80.0
(1 row)
The array does not exist in a table – this is a value returned from another function call – so the conversion code needs to operate on it as an array.
How can I convert an array of INTERVAL values to an array of corresponding NUMERIC values?
You need to unnest() the array, do the conversion and then aggregate back into an array.
Assuming you want to do this on a real table with a primary key:
SELECT pk, array_agg(extract(epoch from dur_int)::numeric(10,1)
ORDER BY ordinality) AS duration_seconds
FROM my_table, unnest(duration_interval) WITH ORDINALITY d(dur_int)
GROUP BY pk;
If you have a single array, such as the result from a function call:
SELECT array_agg(extract(epoch from dur_int)::numeric(10,1)
ORDER BY ordinality) AS duration_seconds
FROM unnest(function(...)) WITH ORDINALITY d(dur_int);
Note that you need the WITH ORDINALITY clause when unnesting the array. This will add a column ordinality to the result such that every row has two columns: (dur_int interval, ordinality bigint). When putting the array back again with seconds instead of an interval, you order the rows by the ordinality column. That way you ensure that the order in the resulting array of seconds is the same as in the original array of intervals. (In general, SQL row sources have no specific ordering, the server may present rows in any order it prefers.)
If you have access to the function and you are not breaking other uses of it, you might be better off by changing the function such that you can use its result directly.
If there is a primary key then #Patrick answer is enough. If not then use row_number to aggregate on:
with i(i) as (values
(array['00:01:20.000','00:00:30.000']::interval[]),
(array['00:02:10.000','00:01:30.000']::interval[])
)
select array_agg(extract(epoch from a)::numeric(10,1))
from (
select i, row_number() over() as r
from i
) s, unnest(i) a (a)
group by r
;
array_agg
--------------
{80.0,30.0}
{130.0,90.0}

MDX Group & Count

I'm having the below MDX Query
WITH
MEMBER Measures.Improvement AS
[Measures].[School Evaluation]
-
(
[Measures].[School Evaluation]
,[Cycle].[Name].CurrentMember.PREVMEMBER
)
MEMBER Measures.PreviousEvaluation AS
(
[Measures].[School Evaluation]
,[Cycle].[Name].CurrentMember.PREVMEMBER
)
SELECT
Measures.Improvement ON COLUMNS,
Filter (
{ [Cycle].[Name].[Name].ALLMEMBERS }
* { [School].[Name En].[Name En].ALLMEMBERS }
, Measures.PreviousEvaluation > 0
AND
[Measures].[School Evaluation] > 0
)
ON ROWS
FROM [SchoolCube];
This code generates the below output
Now what I need is to count the occurrence of Improvement "-2,-1,0,..." across all the schools So I have something like this
How Can I achieve this?
Thanks,
You have to add another dimension "Improvement" that holds possible values for either a fixed range, e.g. -10..+10 or you build the range dynamically based on your data.
Add a second measure group to the cube based on that dimension table and create a measure "Improvement base", that sums the improvement value. This is a helper measure to simplify the following steps.
Now you can create a new calculated measure:
CREATE MEMBER CURRENTCUBE.[Measures].[Count Improvements] AS
SUM(IIF([Measures].[Improvement] = [Measures].[Improvement base], 1, 0));
Maybe you have to scope the All-member of the Improvement dimension to sum the children.

Resources