MDX script - mix empty and non empty on the same axis - mdx

I would like to ask your help to understand the main logic of MDX query. I would like to query different dimensions from the cube. But: in some case I would like to hide the NULL values, but in other dimension it is still needed. In my case I would like to provide date weeks and it dates for every day within the time period. (Even if it has no data) The content would be order number, position number and company and of course the KPI: OTD_customer. I tried many times to fix the null value issue, but I'm beginner on MDX. I tried to use NON EMPTY keyword and also Nonempty function, but still don't have the wished result. One more complicated thing is to filter the date for time period: based on actual day the last 15 weeks. (this part is working fine)
> SELECT NON EMPTY
> { [OTD_customer_new] } ON COLUMNS, NON EMPTY
> {
> (
> (( strtoset("LASTPERIODS(15,([Date - Plan Delivery Date].[Calendar Week].&[" + left(ltrim("2017 KW 10"),4) +" KW " + right(ltrim("2017 KW 10"),2) + "]) ) ")
> , [Order Number].[Order Number].[Order Number].ALLMEMBERS
> , [Position Number].[Position Number].[Position Number].ALLMEMBERS
> ,[Date - Plan Delivery Date].[Day of the Week].ALLMEMBERS
> ,[Group Structure].[Group Structure].ALLMEMBERS
> ) )
> *
> ([Date - Plan Delivery Date].[Date].[All].FirstChild:
> tail
> ( filter
> ( [Date - Plan Delivery Date].[Date].[All].Children,
> [Date - Plan Delivery Date].[Date].CurrentMember.Name <= Format(Now(), "yyyyMMdd")
> ), 1
> ).item(0)
> ))
> }
> ON ROWS
> FROM [ProductionCube]
Shall I use the filter in where condition? what is the best way to query the result from the cube? When it will be in normal relation database I would use a simple joins for this purpose.. But here in MDX I don't see the possibility with left and inner joins in script. Based on my understanding the hole axis may have the possibility to filter the null values. Do you have any idea? (thank you for reading) Current result example can be found here

The Non Empty function designed to filter empty axes (when your output is calculated). The NonEmpty function does the calculation of set. So, if you run:
Non Empty {Set1} * {Set2}
You'll get only crossjoined non-empty records.
If you run:
NonEmpty({Set1} * {Set2}, [Measures].[NonEmptyMeasure])
You'll get the same result, but the mechanic is a bit different. If you want to filter only specific sets you may use NonEmpty around these sets:
{Set1} * NonEmpty({Set2}, [Measures].[NonEmptyMeasure])
Set1 won't be filtered. Nonetheless, all members of Set1 will crossjoined with all non-empty members of Set2. Most likely that's not what you want.
You have many extra attributes joined to your date. What do expect them to return for empty records? I may guess you want to return All member, say, Set1 is a date set and Set2 is a company set:
NonEmpty({Set1} * {Set2}, [Measures].[NonEmptyMeasure]) + { {Set1} - NonEmpty({Set1}, [Measures].[NonEmptyMeasure])} * {Set2}.Item(0).Parent
Explanation:
1. NonEmpty({Set1} * {Set2}, [Measures].[NonEmptyMeasure]) -- returns non-empty records
2. {Set1} - NonEmpty({Set1}, [Measures].[NonEmptyMeasure]) -- returns empty dates
3. {Set2}.Item(0).Parent -- returns All member
The result will look like the following:
|=====================================|
| 2016 week 51 | Company1 | 1 |
| 2016 week 51 | Company2 | 1 |
| 2016 week 51 | Company3 | 1 |
| 2016 week 52 | All companies | NULL |
=======================================
Is it the wished result?

Related

Not allow any null values in resultset MDX

I want to exclude any rows where there is a null value in my MDX query. Sounds simple enough:
SELECT
NON EMPTY{
....
}
ON 0
etc...
However, one of my columns has values even though the other ones only contain null vales.
Example:
Area | ComputerSales | Areadirector
WA (Null) Steve
NY 21312 Mary
How do I remove the first row, where there is a (null) value?
You could use HAVING
SELECT
{
[Measures].[Computer Sales]
,[Measures].[Areadirector]
} ON 0
,[AreaDimension].[Area].[Area] HAVING
(NOT
IsEmpty([Measures].[Computer Sales])) ON 1
FROM [YourCube];
Or make the set in a WITH clause first:
WITH
SET [S] AS
NonEmpty
(
[AreaDimension].[Area].[Area]
,[Measures].[Computer Sales]
)
SELECT
{
[Measures].[Computer Sales]
,[Measures].[Areadirector]
} ON 0
,[S] ON 1
FROM [YourCube];
Second approach is probably more efficient.
You can use for example FILTER and ISEMPTY function
SELECT
[Measures].[Fac Count] on 0,
FILTER(
[Time].[Date Key].children,
NOT ISEMPTY([Measures].[Fac Count])
)
on 1
FROM
[Test]
this simple query returns only date keys that Fac Count measure has non empty value.

Functionality Similar to SUMIFS with DAX?

Sample workbook: http://1drv.ms/1VDgAjf
I've got a table similar to:
ActiveDate CommenceDate Amount
-------------------------------------------
20150115 20150201 10
20150115 20150201 2
20150223 20150301 3
20150223 20150202 5
I need to calculate the following:
Date Amount
---------------------
25-Jan-15 0
30-Jan-15 0
04-Feb-15 12
09-Feb-15 12
14-Feb-15 12
19-Feb-15 12
24-Feb-15 17
01-Mar-15 20
06-Mar-15 20
11-Mar-15 20
So.. in Excel I've tested this with the following statement:
=SUMIFS(
Table[amount]
,Table[commence] ,"<="&TEXT(<<DateRef>>, "yyyymmdd")
,Table[active] ,"<="&TEXT(<<DateRef>>, "yyyymmdd")
)
This works fine.. my question is, how do i replicate this in DAX?
Here is my best stab (assuming a date dimension, and it connected to "CommenceDate"):
TotalAmount :=
CALCULATE (
SUM ( Table[Amount] ),
FILTER (
ALL ( 'Date'[Date] ),
'Date'[Date] <= MAX ( 'Date'[Date] )
)
)
My best idea (and i think it's a pretty crappy idea), is to add a new column that gives me the greater of ActiveDate, or CommenceDate and then use an in-active relationship to join to that, and make the relationship active just for this calculation?
=IF([#active]>[#commence], [active], [commence])
Thoughts?
Your thought of creating an additional column is probably the best in this case. No matter what you do, you'll have to escape the active relationship between Transactions[commence] and DimDate[DateKey] to get this logic working correctly.
After doing that manipulation, you'll then have to filter on two columns ([active], [commence]) against the current date in context. This will be more cumbersome and less efficient than navigating a single relationship and using a single filter.
The thing to keep in mind is that you need to apply the relationship manipulation step before, not with the filter manipulation step. This looks like the following nested CALCULATE():
TotalAmount:=
CALCULATE(
CALCULATE(
SUM(Transactions[Amount])
,USERELATIONSHIP(Transactions[MaxDateKey], DimDate[DateKey])
)
,FILTER(
ALL('Date')
,'Date'[Date] <= MAX('Date'[Date])
)
)

MDX Using multiple date dimensions

What I want to do is generate a report containing an overview of gains and losses (of contracts). For example:
Year | contract_gains | contract_losses
_______________________________________
2015 | 10 | 2
2016 | 15 | 4
Showing the gains is quite easy because I can just count distinct contracts (which is the aggregator for the measure value) with a start period.
SELECT
{[contract_start_date].[year].MEMBERS}
ON ROWS,
{[Measures].[value]}
ON COLUMNS
FROM Cube
Showing the losses seperately is also easy because I can do the same with the second date dimension.
SELECT
{[contract_end_date].[year].MEMBERS}
ON ROWS,
{[Measures].[value]}
ON COLUMNS
FROM Cube
But what I want to do is generate a report containing both of the values in a single report. Sadly I have no idea how I can do this.
A little slow method, going cell by cell. Does this work for you -
WITH MEMBER [Measures].contract_losses AS
(
GENERATE
(
[contract_start_date].[year].CURRENTMEMBER,
FILTER
(
[contract_end_date].[year].MEMBERS,
CStr([contract_start_date].[year].CURRENTMEMBER.MEMBER_VALUE) = CStr([contract_end_date].[year].CURRENTMEMBER.MEMBER_VALUE)
)
).ITEM(0)
,
[Measures].[value]
)
MEMBER [Measures].contract_gains AS
[Measures].[value]
SELECT
NON EMPTY {[contract_start_date].[year].MEMBERS}
ON ROWS,
{[Measures].contract_gains, [Measures].contract_losses}
ON COLUMNS
FROM [Cube]

finding range by comparing two tables

I have a table in database as "EXPERIENCE RANGE" with rows as (I can also edit this table according to my need)
0
0.5
1
2
3
5
10
20
I have total experience as integer. I need to display the range in which it lies.
Example - for experience of 8, Range will be 5 - 10
I need to write a sql query. Any ideas will be quite helpful as I am new to SQL.
I cannot hard code it..need to take values from tables only.
Assuming that you are using Oracle, the following query works fine with your existing table:
SELECT
( SELECT MAX( value ) FROM experience_range WHERE value <= :search_value ) AS range_start,
( SELECT MIN( value ) FROM experience_range WHERE value > :search_value ) AS range_end
FROM dual;
No need to hardcode the values, and no need to store the lower and upper bounds redundantly.
you can do it with CASE Expression, the syntax is:
SELECT
CASE
WHEN experience >= 0 and experience <= 4 THEN '0-4'
WHEN experience >= 5 and experience <= 10 THEN '5-10'
.....
ELSE 'No Range'
END as Range
FROM Table_Name
If you do need to store the ranges in a table, I would personally suggest altering the structure of the range table (Assuming you are able to), maybe something like:
|--------------------------------------|
|ID|DESCRIPTION|LOWER_LIMIT|UPPER_LIMIT|
|1 | 0 - 0.5 | 0 | 0.5 |
|2 | 0.5 - 1 | 0.5 | 1 |
...
Then you could get your range by running something like:
SELECT DESCRIPTION FROM [RANGES] WHERE <VALUE> >= LOWER_LIMIT AND <VALUE> < UPPER_LIMIT
EDIT - Mikhail's answer also works, defining the ranges within the query itself is also an option and probably simpler providing you don't need to get these ranges from several reports. (That would require editing every report/query individually)
EDIT 2 - I see you are not able to hardcode the ranges, in which case the above would be best. Can I ask why you are unable to hardcode them?

Adding a percent column to MS Access Query

I'm trying to add a column which calculates percentages of different products in MS Access Query. Basically, this is the structure of the query that I'm trying to reach:
Product |
Total |
Percentage
Prod1 |
15 |
21.13%
Prod2 |
23 |
32.39%
Prod3 |
33 |
46.48%
Product |
71 |
100%
The formula for finding the percent I use is: ([Total Q of a Product]/[Totals of all Products])*100, but when I try to use the expression builder (since my SQL skills are basic) in MS Access to calculate it..
= [CountOfProcuts] / Sum([CountOfProducts])
..I receive an error message "Cannot have aggregate function in GROUP BY clause.. (and the expression goes here)". I also tried the option with two queries: one that calculates only the totals and another that use the first one to calculate the percentages, but the result was the same.
I'll be grateful if someone can help me with this.
You can get all but the last row of your desired output with this query.
SELECT
y.Product,
y.Total,
Format((y.Total/sub.SumOfTotal),'#.##%') AS Percentage
FROM
YourTable AS y,
(
SELECT Sum(Total) AS SumOfTotal
FROM YourTable
) AS sub;
Since that query does not include a JOIN or WHERE condition, it returns a cross join between the table and the single row of the subquery.
If you need the last row from your question example, you can UNION the query with another which returns the fabricated row you want. In this example, I used a custom Dual table which is designed to always contain one and only one row. But you could substitute another table or query which returns a single row.
SELECT
y.Product,
y.Total,
Format((y.Total/sub.SumOfTotal),'#.##%') AS Percentage
FROM
YourTable AS y,
(
SELECT Sum(Total) AS SumOfTotal
FROM YourTable
) AS sub
UNION ALL
SELECT
'Product',
DSum('Total', 'YourTable'),
'100%'
FROM Dual;