MDX Count with a Filter? - filter

We want to count the weeks where "Inventory Units" were greater then 0.
I have put this together but it doesn't quite work, it counts all weeks for an item not just the ones where Inventory > 0. I have tried some filters but they always result in #error as the result
WITH
SET [PreviousSixWeeks] AS
Tail
(
Filter
(
[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Week]
,
[Measures].[Inventory Units] > 0
)
,6
)
MEMBER [Measures].[INVWeekCount] AS
DistinctCount(PreviousSixWeeks*[Measures].[Inventory Units]*[Item].[Item Code])
SELECT
{[Measures].[INVWeekCount]} ON COLUMNS
,{[Item].[Item Code].[Item Code]} ON ROWS
FROM
(
SELECT
{[Location].[Location].&[64]} ON COLUMNS
FROM
(
SELECT
{
[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[2].&[8]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[2].&[9]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[10]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[11]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[12]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[13]
} ON COLUMNS
FROM [RFP]
)
);

Try this to count weeks with inventory, make sure it returns desired results then add any filters you want.
WITH MEMBER [Measures].[InvWeekCount] AS
FILTER([Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Week].MEMBERS,
[Measures].[Inventory Units]>0).COUNT
SELECT [Measures].[InvWeekCount] ON COLUMNS,
[Item].[Item Code].[Item Code].MEMBERS ON ROWS
FROM [Test Cube]

Better to avoid Filter if you can as its performance is not great:
WITH
SET [PreviousSixWeeks] AS
Tail
(
[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Week].MEMBERS
,6
)
MEMBER [Measures].[INVWeekCount] AS
Count(NonEmpty((EXISTING PreviousSixWeeks),[Measures].[Inventory Units]))
SELECT
{[Measures].[INVWeekCount]} ON COLUMNS
,{[Item].[Item Code].[Item Code]} ON ROWS
FROM
(
SELECT
{[Location].[Location].&[64]} ON COLUMNS
FROM
(
SELECT
{
[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[2].&[8]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[2].&[9]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[10]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[11]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[12]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[13]
} ON COLUMNS
FROM [RFP]
)
);
But this is a better way of doing Count with a filter criterion - it performs a lot better:
WITH
MEMBER [Measures].[InvWeekCount] AS
Sum
(
Time.[Yr-Qtr-Per-Wk-Day].[Fiscal Week].MEMBERS
,IIF
(
(NOT
IsEmpty([Measures].[Inventory Units]))
,1
,0
)
)
SELECT
[Measures].[InvWeekCount] ON COLUMNS
,[Item].[Item Code].[Item Code].MEMBERS ON ROWS
FROM
(
SELECT
{[Location].[Location].&[64]} ON COLUMNS
FROM
(
SELECT
{
[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[2].&[8]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[2].&[9]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[10]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[11]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[12]
,[Time].[Yr-Qtr-Per-Wk-Day].[Fiscal Year].&[2016].&[1].&[3].&[13]
} ON COLUMNS
FROM [RFP]
)
);
note
in terms of simple AdvWrks code this is what you're using:
WITH
MEMBER [Measures].[InvWeekCount] AS
Filter
(
[Product].[Product].[Product]
,
[Measures].[Internet Order Quantity] > 0
).Count
SELECT
[Measures].[InvWeekCount] ON COLUMNS
,[Customer].[Customer Geography].[Country] ON ROWS
FROM [Adventure Works];
But this is the recommended efficient method:
WITH
MEMBER [Measures].[InvWeekCount] AS
Sum
(
[Product].[Product].[Product]
,IIF
(
(NOT
IsEmpty([Measures].[Internet Order Quantity]))
,1
,NULL
)
)
SELECT
[Measures].[InvWeekCount] ON COLUMNS
,[Customer].[Customer Geography].[Country] ON ROWS
FROM [Adventure Works];

Related

DAX/PowerBI Rank taking a variable/parameter into account

I'm working on a ranking/scoring system and I'm missing the PERCENTRANK.INC function in powerBI. Instead I have worked out below formula which is the closest I can get.
Score =
DIVIDE (
RANKX (
FILTER ( 'Table', NOT ( ISBLANK ( [Sold amounts] ) ) ),
[Sold amounts],
,
ASC
) - 1,
COUNTROWS ( FILTER ( 'Table', NOT ( ISBLANK ( [Sold amounts] ) ) ) ) - 1
)
I really want to have the formula to take the type of "Fruit" into account in my scoring/ranking.
In short each fruit should be scored separately, with a range per fruit sold.
Could this somehow be done with a variable (VAR)?
Example of data:
This should work.
Score =
VAR fruit = 'Table'[Fruit]
VAR filteredTable = FILTER ( 'Table', NOT ( ISBLANK ( [Sold amount] ) ) && 'Table'[Fruit] = fruit)
RETURN
DIVIDE (
RANKX (
filteredTable,
[Sold amount],
,
ASC
) - 1,
COUNTROWS ( filteredTable ) - 1
)

How do you repeat rows in a table multiple time

I created a table a DAX Studio and want to repeat all the rows (with all the columns) in a new table multiple times; to my choosing.
//create temp table of Historic Facilities for all annual groups 1 to 3
TABLE HistFac =
ADDCOLUMNS ( FacSchHist,
"Rank", RANKX ( FacSchHist, [WtAvg] ),
"Annual Group", (RANKX ( FacSchHist, [WtAvg] ) - FLOOR((RANKX ( FacSchHist, [WtAvg] ) - 1) /3 * 3,3)))
EVALUATE
NonHistFac
ORDER BY [Annual Group],
[WtAvg] DESC
I want the maintain the original order in the repeated list. There are obviously many ways to construct a table (see code above); however, how does one repeat the list of rows?
Thanks you for any suggestions.
Try to remove the filters that are affecting the measure inside RANKX because of the context transition coming from the table provide in the first argument of GENERATE
DEFINE
TABLE HistFac =
GENERATE (
{ 1, 2, 3 },
ADDCOLUMNS (
ADDCOLUMNS (
FacSchHist,
"#Rank",
RANKX (
FacSchHist,
CALCULATE ( [WtAvg], REMOVEFILTERS ( TableSupliedInTheFirstArgument ) )
)
),
"Annual Group",
[#Rank]
- FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
)
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
Or simply use variables to compute in a different filter context.
DEFINE
TABLE HistFac =
VAR RankedTable =
ADDCOLUMNS ( FacSchHist, "#Rank", RANKX ( FacSchHist, [WtAvg] ) )
VAR SomeCalculationOnRankedTable =
ADDCOLUMNS (
RankedTable,
"Annual Group",
[#Rank]
- FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
RETURN
GENERATE ( { 1, 2, 3 }, SomeCalculationOnRankedTable )
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
You can use GENERATE for repeating the rows:
DEFINE
TABLE HistFac =
GENERATE (
{ 1, 2, 3 },
ADDCOLUMNS (
FacSchHist,
"Rank", RANKX ( FacSchHist, [WtAvg] ),
"Annual Group",
(
RANKX ( FacSchHist, [WtAvg] )
- FLOOR ( ( RANKX ( FacSchHist, [WtAvg] ) - 1 ) / 3 * 3, 3 )
)
)
)
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
A better way to write this code will be to use nested ADDCOLUMNS:
DEFINE
TABLE HistFac =
GENERATE (
{ 1, 2, 3 },
ADDCOLUMNS (
ADDCOLUMNS ( FacSchHist, "#Rank", RANKX ( FacSchHist, [WtAvg] ) ),
"Annual Group",
[#Rank]
- FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
)
EVALUATE
NonHistFac
ORDER BY
[Annual Group],
[WtAvg] DESC
AntrikshSharma - I will give those a try now , appreciate your guidance.
Okay, the code worked fine; but uncovered a problem. After the initial ranking of the list, and before the replication - I do not want to continue ranking.
In other words, I want the initial ranked-list to be reproduced 3x without any further ranking; just have each duplicated occurrence appear after the initial list in the exact order.
If the initial list was 12345, then 12345,12345,12345 - thank you for the more efficient code as well.
AntrikshSharma, your comment and code, "Or simply use variables to compute in a different filter context" is genius. The code performed as expected. The problem I'm experiencing is with the UNION of the two tables "NonHistFac" and "HistFac". I will provide an image to explain then the most current code.
15yr cycle of Hist & NonHist Facilities
The image shows the goal. combine the NonHistFac (all surveyed every 5yrs) with the HistFac (all surveyed every 3yrs). The original ranking must be maintained (this is currently met.)
Here is the problem. The numbers within the image are the Values as produced by the GENERATE function. When the tables are combined and the NonHistFac are mixed with the HistFac, they are not evenly distributed throughout the 1 to 5 Values.
What appears in Values 4 and 5 is obviously the remaining HistFac. I need to have the entire combination distributed from 1 to 5; or as shown, over the 15 year cycle.
Thank you.
// produce non-historic table with additional columns and replicate all rows 3x
TABLE NonHistFac =
VAR NonHistRankedTable =
ADDCOLUMNS ( FacSchNonHist, "#Rank", RANKX ( FacSchNonHist, [WtAvg] ) )
VAR NonHistAnnualizedRankedTable =
ADDCOLUMNS (
NonHistRankedTable,
"Annual Group",
[#Rank] - FLOOR ( ( [#Rank] - 1 ) / 5 * 5, 5 )
)
RETURN
GENERATE ( { 1, 2, 3 }, NonHistAnnualizedRankedTable )
// from the FLOOR & GENERATE functions, 5 x 3 = 15 (this is a 15 year cycle)
//produce historic facility table with additional columns and replicate all rows 5x
TABLE HistFac =
VAR HistRankedTable =
ADDCOLUMNS ( FacSchHist, "#Rank", RANKX ( FacSchHist, [WtAvg] ) )
VAR HistAnnualizedRankedTable =
ADDCOLUMNS (
HistRankedTable,
"Annual Group",
[#Rank] - FLOOR ( ( [#Rank] - 1 ) / 3 * 3, 3 )
)
RETURN
GENERATE ( { 1, 2, 3, 4, 5 }, HistAnnualizedRankedTable )
// from the FLOOR & GENERATE functions, 3 x 5 = 15 (this is a 15 year cycle)
// combine the tables NonHistFac & HistFac to create one-table representing a 15 yr cycle
VAR FacSchUnion =
UNION(
NonHistFac,
HistFac
)
VAR FacSch15yr =
DISTINCT(FacSchUnion)
EVALUATE
FacSch15yr
ORDER BY [Value],
[Annual Group],
[WtAvg] DESC

How to put 2 rows returned from a query into into 2 columns of a single row in Oracle sql

I run a query that returns 2 rows
SELECT a FROM TABLE-A WHERE condition=something;
row1 Value1
row2 Value2
Now, I want to put it in a new table in 2 columns of a single row
SELECT column1, column2 FROM TABLE-B WHERE condition=something;
row1 column1 column2
value1 value2
Can you please help me with this?
It is unclear how you want to pick which row goes into which column - here are a couple of options:
SELECT MIN( a ) AS minimum_value,
MAX( a ) AS maximum_value
FROM table_a
WHERE 1=1;
or
SELECT MAX( a ) KEEP ( DENSE_RANK FIRST ORDER BY ROWNUM ) AS first_value,
MAX( a ) KEEP ( DENSE_RANK LAST ORDER BY ROWNUM ) AS last_value
FROM table_a
WHERE 1=1;
or
SELECT *
FROM ( SELECT a, ROWNUM AS rn FROM table_a WHERE 1=1 )
PIVOT ( MAX(a) FOR rn IN ( 1 AS first_value, 2 AS second_value ) );

Get first three rows : with clause

I have the following Query:
with TEMPRESULT AS
(
select CONTACTS.line_id , count(*) totalcount
from CONTACTS
where (((E_DATE-S_DATE)*24*60*60)<=60 and to_char(S_DATE,'YYYY-MM-DD')='2015-12-12')
group by CONTACTS.line_id
order by totalcount DESC
)
I want TEMPRESULT holds only the first three rows returned by select, how to do that ?
You can specify a condition on rownum:
with TEMPRESULT AS
(
select * from
(
select CONTACTS.line_id , count(*) totalcount
from CONTACTS
where (((E_DATE-S_DATE)*24*60*60)<=60 and to_char(S_DATE,'YYYY-MM-DD')='2015-12-12')
group by CONTACTS.line_id
order by totalcount DESC
) x
where rownum < 3
)
if you have oracle 12c you can use the fetch first
WITH TEMPRESULT AS
(SELECT CONTACTS.line_id ,
COUNT(*) totalcount
FROM CONTACTS
WHERE (((E_DATE-S_DATE)*24*60*60)<=60
AND TO_CHAR(S_DATE,'YYYY-MM-DD') ='2015-12-12')
GROUP BY CONTACTS.line_id
ORDER BY 2 DESC
FETCH FIRST 3 rows only
)
SELECT * FROM tempresult

codeigniter active record Join multiple select statements

I cannot find any refrence on joining multiple selects like the query below in active record, anyone know how such is done?
select a1.act, a1.date, a2.clos
from
(
SELECT count( AccountActiveDate ) act, DATE_FORMAT( AccountActiveDate, '%Y-%m' ) date
FROM customert cust
GROUP BY YEAR( AccountActiveDate ) , MONTH( AccountActiveDate )
) a1
join
(
SELECT count( AccountClosedDate ) clos, DATE_FORMAT( AccountClosedDate, '%Y-%m' ) date
FROM customert cust2
GROUP BY YEAR( AccountClosedDate) , MONTH( AccountClosedDate)
) a2
ON a1.date = a2.date
You can put you sql string like this:
$this->db->query('YOUR QUERY HERE')
Example:
$this->db->query('SELECT * FROM tbl_users WHERE age > 18');

Resources