MDX - Extract Last 24 hours data - ssas

I need to extract last 24 hours data from a cube. Below is the MDX I have written but it doesn't return the data according to current time (system time).
SELECT
[Date].[Calender-Year_Quarter_Month_Date].[Date] ON ROWS
,{[Measures].[Delay In Mintues]} ON COLUMNS
FROM
(
SELECT
{
StrToMember
("[Date].[Calender-Year_Quarter_Month_Date].[Date].&["
+
Format
(
Now() - 1
,'yyyyMMdd'
)
+ "]"
)
*
(
[Time].[Time-Hour_Time].[Hour].&["+FORMAT(NOW(),"HH")+"]
:
[Time].[Time-Hour_Time].[Hour].&[23].&[23:59]
)
}
+
{
StrToMember
("[Date].[Calender-Year_Quarter_Month_Date].[Date].&["
+
Format
(
Now()
,'yyyyMMdd'
)
+ "]"
)
*
(
[Time].[Time-Hour_Time].[Hour].&[0].&[00:00]
:
[Time].[Time-Hour_Time].[Hour].&["+FORMAT(NOW(),"HH")+"]
)
} ON COLUMNS
FROM [Delay Reasons]
);

(note: not tested)
Does this work?
SELECT
[Date].[Calender-Year_Quarter_Month_Date].[Date] ON ROWS
,{[Measures].[Delay In Mintues]} ON COLUMNS
FROM [Delay Reasons]
WHERE
{
StrToMember
("[Date].[Calender-Year_Quarter_Month_Date].[Date].&["
+
Format
(
Now() - 1
,'yyyyMMdd'
)
+ "]"
)
*
(
[Time].[Time-Hour_Time].[Hour].&["+FORMAT(NOW(),"HH")+"]
:
[Time].[Time-Hour_Time].[Hour].&[23].&[23:59]
)
}
+
{
StrToMember
("[Date].[Calender-Year_Quarter_Month_Date].[Date].&["
+
Format
(
Now()
,'yyyyMMdd'
)
+ "]"
)
*
(
[Time].[Time-Hour_Time].[Hour].&[0].&[00:00]
:
StrToMember
(
"[Time].[Time-Hour_Time].[Hour].&[" + Format(Now(),"HH") + "].&[00:00]"
)
)
};

Related

Date Table created with M is imported as an Expression

I am using SSAS Tabular 2019 and I have had no problem in loading my views or tables, but this time instead of loading a Date table from SQL Server I created my own Date table using custom M code, but it appears that the date table is being imported as an Expression and not as a table. Here is a screenshot:
Here is my M code:
let
Source = ( StartDate as date, EndDate as date ) as table =>
let
DateTable =
let
StartDateNumber = Number.From ( Date.StartOfYear ( StartDate ) ),
EndDateNumber = Number.From ( Date.AddYears ( Date.EndOfYear ( EndDate ), 1 ) ),
DateList = { StartDateNumber..EndDateNumber },
ToTable = Table.FromList ( DateList, Splitter.SplitByNothing() ),
ToDateType = Table.TransformColumnTypes ( ToTable, { "Column1", type date } ),
RenameToDate = Table.RenameColumns ( ToDateType, { "Column1", "Date" } )
in
RenameToDate,
// Day related fields are created here
Day_Fields =
let
Add_Day_Name = Table.AddColumn ( DateTable, "Weekday Name", each Date.DayOfWeekName ( [Date] ), type text ),
Add_Day_Number = Table.AddColumn ( Add_Day_Name, "Weekday Number", each Date.DayOfWeek ( [Date] ), Int64.Type )
in
Add_Day_Number,
// Month related fields are created here
Month_Fields =
let
Add_Month_Name = Table.AddColumn ( Day_Fields, "Month Name", each Date.MonthName ( [Date] ), type text ),
Add_Month_Number = Table.AddColumn ( Add_Month_Name, "Month Number", each Date.Month ( [Date] ), Int64.Type ),
Add_Month_Initials = Table.AddColumn ( Add_Month_Number, "Month Initials", each Text.Start ( [Month Name], 3 ), type text )
in
Add_Month_Initials,
// Year Related Fields are Create Here
Year_Fields =
let
Add_Year = Table.AddColumn ( Month_Fields, "Calendar Year Number", each Date.Year ( [Date] ), Int64.Type ),
Add_Year_Text = Table.AddColumn ( Add_Year, "Calendar Year", each "CY " & Text.From ( Date.Year ( [Date] ) ), type text )
in
Add_Year_Text
in
Year_Fields
in
Source
Can you please confirm what is happening here?

Case expression in json_build_object()

I want to add a case expression inside of my json_build_object for the times where and endtime has not yet been set.
CODE
Current
SELECT json_build_object(
'endtime', json_agg(CONCAT(endtime::timestamp::date, ' ', endtime::timestamp(0)::time )),
'starttime', json_agg(CONCAT(starttime::timestamp::date, ' ', starttime::timestamp(0)::time )),
'totaltime', json_agg(starttime::timestamp - endtime::timestamp),
)
FROM jobs
Expected
SELECT json_build_object(
'endtime', json_agg(CONCAT(endtime::timestamp::date, ' ', endtime::timestamp(0)::time )),
'starttime', json_agg(CONCAT(starttime::timestamp::date, ' ', starttime::timestamp(0)::time )),
CASE WHEN endtime IS NULL
THEN 'totaltime', json_agg(starttime::timestamp - NOW()::timestamp)
ELSE 'totaltime', json_agg(starttime::timestamp - endtime::timestamp)
END
)
FROM jobs
RESULT
Current
{
"endtime" : [" ", "2019-07-22 18:50:06", "2019-07-19 19:24:13", "2019-07-19 16:23:46"],
"starttime" : ["2019-07-24 16:02:49", "2019-07-22 20:12:01", "2019-07-19 16:55:55", "2019-07-19 14:56:48"],
"totaltime" : [null, "01:21:55.150273", "-02:28:17.795901", "-01:26:57.872932"]
}
Expected
When the endtime is null I would like like the totaltime to be the time till now
{
"endtime" : [" ", "2019-07-22 18:50:06", "2019-07-19 19:24:13", "2019-07-19 16:23:46"],
"starttime" : ["2019-07-24 16:02:49", "2019-07-22 20:12:01", "2019-07-19 16:55:55", "2019-07-19 14:56:48"],
"totaltime" : ["01:2..timeTillNow", "01:21:55.150273", "-02:28:17.795901", "-01:26:57.872932"]
}
Because you're using aggregated functions, if you put the case when endtime around the json_agg, you're checking the value of the aggregated endtime and it must be in a group by.
Instead, just like the concat, the case goes inside the json_agg. This expression will be evaluated for each row to provide json_agg with the values to aggregate.
SELECT json_build_object(
'endtime', json_agg(
concat(endtime::timestamp::date, ' ', endtime::timestamp(0)::time )
),
'starttime', json_agg(
concat(starttime::timestamp::date, ' ', starttime::timestamp(0)::time )
),
'totaltime', json_agg(
case when endtime is null
then starttime::timestamp - NOW()::timestamp
else starttime::timestamp - endtime::timestamp
end
)
)
FROM jobs;

How to transform path/string by collapsing repeated elements?

There is a filed in my table that represents pathways like below:
Item1->Item1->Item2-> Item3->Item3->Item3->Item1
In most cases this is quite looong sequence with many instances of same consecutive Items.
How I can shorted above path to something like below? in BigQuery!
Item1(x2)->Item2->Item3(x3)->Item1
I wanted to convince myself that this was possible just through array manipulation (using standard SQL), and I came up with a solution. An alternate way to solve the problem would be to use analytic functions, where you could detect changes in item along the path.
CREATE TEMPORARY FUNCTION PartsToString(
parts_and_offsets ARRAY<STRUCT<part STRING, off INT64>>) AS ((
SELECT
STRING_AGG(
CONCAT(part_and_offset.part,
IF(parts_and_offsets[OFFSET(off + 1)].off - part_and_offset.off = 1,
"",
CONCAT("(x", CAST(parts_and_offsets[OFFSET(off + 1)].off - part_and_offset.off AS STRING), ")"))))
FROM UNNEST(parts_and_offsets) AS part_and_offset WITH OFFSET off
WHERE off + 1 < ARRAY_LENGTH(parts_and_offsets)
));
CREATE TEMPORARY FUNCTION PathwayToParts(pathway STRING) AS ((
SELECT
ARRAY_CONCAT(
ARRAY_AGG(
STRUCT(part, off)),
[STRUCT("" AS part, ARRAY_LENGTH(ANY_VALUE(parts)) AS off)]) AS parts_and_offsets
FROM (SELECT SPLIT(pathway, "->") AS parts),
UNNEST(parts) AS part WITH OFFSET off
WHERE off = 0 OR part != parts[OFFSET(off - 1)]
));
WITH YourTable AS (
SELECT "Item1->Item2->Item2->Item2->Item3->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item4" AS pathway
UNION ALL SELECT "Item1->Item2->Item2->Item3->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item1->Item4" AS pathway
UNION ALL SELECT "Item1->Item1->Item1" AS pathway
UNION ALL SELECT "Item1->Item2->Item2" AS pathway
UNION ALL SELECT "Item1->Item1->Item2" AS pathway
UNION ALL SELECT "Item1->Item2->Item3" AS pathway
)
SELECT PartsToString(PathwayToParts(pathway)) AS parts_string
FROM YourTable;
Using Scalar JS UDF (Standard SQL) <-- would be my choice
CREATE TEMPORARY FUNCTION collapse_repeated(pathway STRING)
RETURNS STRING LANGUAGE js AS """
var items = pathway.split('->');
short = ''; elem = items[0]; count = 0;
for (var i = 0; i < items.length; i++) {
if (items[i] !== elem) {
if (short.length > 0) {short += '->'}
short += elem; if (count > 1) {short += '(x' + count.toString() + ')';}
elem = items[i]; count = 1;
} else {
count++;
}
}
if (short.length > 0) {short += '->'}
short += elem; if (count > 1) {short += '(x' + count.toString() + ')';}
return short;
""";
WITH YourTable AS (
SELECT "Item1->Item2->Item2->Item2->Item3->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item4" AS pathway
UNION ALL SELECT "Item1->Item2->Item2->Item3->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item1->Item4" AS pathway
UNION ALL SELECT "Item1->Item1->Item1" AS pathway
UNION ALL SELECT "Item1->Item2->Item2" AS pathway
)
SELECT collapse_repeated(pathway) AS shorten_pathway, pathway
FROM YourTable
Note: Same JS can be easily “translated” to JS UDF in Legacy SQL
Using Window Functions (Legacy SQL)
SELECT GROUP_CONCAT_UNQUOTED(IF(repeats=1, item, CONCAT(item, "(x", STRING(repeats), ")")), "->"), pathway
FROM (
SELECT MIN(pos) AS ord, MIN(item) AS item, COUNT(1) AS repeats, pathway
FROM (
SELECT item, pos, IFNULL(grp, 0)AS grp, pathway FROM (
SELECT item, pos, SUM(change) OVER(PARTITION BY pathway ORDER BY pos ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS grp, pathway
FROM (
SELECT item, pos, IF(item=next_item, 0, 1) AS change, pathway FROM (
SELECT item, pos, LEAD(item) OVER(PARTITION BY pathway ORDER BY pos) AS next_item, pathway
FROM (
SELECT item, POSITION(item) AS pos, pathway FROM (
SELECT SPLIT(pathway, "->") AS item, pathway FROM
(SELECT "Item1->Item2->Item2->Item2->Item3->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item2->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item1->Item4" AS pathway),
(SELECT "Item1->Item2->Item2->Item3->Item1->Item1->Item1->Item2->Item3->Item3->Item2->Item2->Item2->Item1->Item4" AS pathway),
(SELECT "Item1->Item1->Item1" AS pathway),
(SELECT "Item1->Item2->Item2" AS pathway)
)
)
)
)
)
)
GROUP BY grp, pathway
ORDER BY ord
)
GROUP BY pathway

With MDX how to sort by month

How do I sort by month. Now the sorting is alfabetical. And that is not correct. I want january before april - not the other way run :)
Im working in report builder 3.0 and have tried this (=format(Fields!Måned.Value,"MM") as a calculated member called monthsort, but it dosent Work. (Måned = month in Danish).
I have the following MDX-code:
WITH
SET [prodSet] AS
[Borger].[Anonym Borgernøgle DPR].[Anonym Borgernøgle DPR].ALLMEMBERS
SET [prodDtSet] AS
NonEmpty
(
[prodSet]
*
{
( [SundhedOgOmsorg - Ydelse].[Ydelse].[Ydelse].ALLMEMBERS *
[Kalender].[År].[År].ALLMEMBERS *
[Kalender].[Måned].[Måned].ALLMEMBERS )
}
,[Measures].[Antal unikke brugere - Visiteret Tid]
)
SET [prodDtSetFiltered] AS
Filter
(
[prodDtSet]
,
(NOT
[prodDtSet].Item(
[prodDtSet].CurrentOrdinal - 1).Item(0)
IS
[prodDtSet].Item(
[prodDtSet].CurrentOrdinal - 2).Item(0))
OR
[prodDtSet].CurrentOrdinal = 1
)
SELECT
{ [Measures].[Antal unikke brugere - Visiteret Tid] } ON 0
,[prodDtSetFiltered] ON 1
FROM
(
SELECT
{
[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.1 Hjemmetrænerforløb]
,[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.2 Komb. Hjemmetræner & Terapeutforløb]
,[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.3 Komplekse Rehabiliteringsforløb]
,[SundhedOgOmsorg - Ydelse].[Ydelse].&[12.7. hverdagsrehab. revis.gr. m. tp.]
} ON COLUMNS
FROM
(
SELECT
{[SundhedOgOmsorg - Modul].[Modul].&[Hjemmehjælp]} ON COLUMNS
FROM [FrbLis]
)
)
WHERE
[SundhedOgOmsorg - Modul].[Modul].&[Hjemmehjælp]
You can try and pull the
MEMBER [Measures].[MånedSortKey] AS [Kalender].[Måned].CURRENTMEMBER.PROPERTIES('KEY')
You can also use MEMBER_KEY instead of PROPERTIES('KEY')
And Sort by it in the report.
(I'm assuming your Key is a Date or a Int which should be more sortable than a string)
(...)
MEMBER [Measures].[MånedSortKey] AS [Kalender].[Måned].CURRENTMEMBER.PROPERTIES('KEY')
SELECT
{
[Measures].[Antal unikke brugere - Visiteret Tid],
[Measures].[MånedSortKey]
} ON 0,
[prodDtSetFiltered] ON 1
FROM (
(...)
You will probably need to use the following function in your script:
Order : https://msdn.microsoft.com/en-us/library/ms145587.aspx
The <numeric expression> to use as an argument will be the Month member's .membervalue property.
Taking mxix measure (I've used membervalue rather than key - although both should work) you should be able to enforce an order inside the mdx:
WITH
MEMBER [Measures].[MånedSortKey] AS
[Kalender].[Måned].CURRENTMEMBER.membervalue
SET [prodSet] AS
[Borger].[Anonym Borgernøgle DPR].[Anonym Borgernøgle DPR].ALLMEMBERS
SET [prodDtSet] AS
NonEmpty
(
[prodSet]
*
{
( [SundhedOgOmsorg - Ydelse].[Ydelse].[Ydelse].ALLMEMBERS *
[Kalender].[År].[År].ALLMEMBERS *
[Kalender].[Måned].[Måned].ALLMEMBERS )
}
,[Measures].[Antal unikke brugere - Visiteret Tid]
)
SET [prodDtSetFiltered] AS
Filter
(
[prodDtSet]
,
(NOT
[prodDtSet].Item(
[prodDtSet].CurrentOrdinal - 1).Item(0)
IS
[prodDtSet].Item(
[prodDtSet].CurrentOrdinal - 2).Item(0))
OR
[prodDtSet].CurrentOrdinal = 1
)
SELECT
{ [Measures].[Antal unikke brugere - Visiteret Tid] } ON 0
,ORDER(
[prodDtSetFiltered],
[Measures].[MånedSortKey],
BDESC
) ON 1
FROM
...
...

StrToMember does not accept calculated measure (mdx)

I try to create a member by using some calculated measure (I have called it 'MyDay' here). I return date members on an axis and the members have a property which I want to use. I can return the property itself, but cannot create the member and work with it.
WITH
MEMBER [Measures].[MyDay] as DatePart("d", MyDateDimension.CurrentMember.Properties("MyProperty"))
MEMBER MyDateDimension.[MyMember] AS
STRTOMEMBER("MyDateDimension.&[2015]&[4]&[" + CStr([Measures].[MyDay]) + "]")
MEMBER [Measures].[SomeOther] as (MyDateDimension.[MyMember], [Measures].[Other]
SELECT
{
MyDateDimension.Members)
} ON COLUMNS,
{
[Measures].[MyDay] //works,
[Measures].[SomeOther] //error
}
If I replace 'MyDateDimension.CurrentMember' by some hard coded date member,
it works fine.
And this also works:
MEMBER [Measures].[SomeOther] as (STRTOMEMBER("MyDateDimension.&[2015]&[4]&[" + CStr([Measures].[MyDay]) + "]"), [Measures].[Other])
If you put the strToMember directly in the SomeMeasure then things start to function:
WITH
MEMBER [Measures].[MyDay] AS
Datepart
("d"
,[Date].[Calendar].CurrentMember.Member_Caption
)
MEMBER [Date].[Calendar].[MyMember] AS
StrToMember
(
'[Date].[Calendar].&[200603' + Cstr([Measures].[MyDay]) + ']'
,constrained
)
MEMBER [Measures].[SomeOther] AS
(
//[Date].[Calendar].[MyMember]
StrToMember
(
'[Date].[Calendar].&[200603' + Cstr([Measures].[MyDay]) + ']'
,constrained
)
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[MyDay]
,[Measures].[SomeOther]
} ON COLUMNS
,Tail
(
Descendants
(
[Date].[Calendar].[Month].&[2005]&[8]
,[Date].[Calendar].[Date]
)
,10
) ON ROWS
FROM [Adventure Works];
A slightly tidier version:
WITH
MEMBER [Measures].[MyDay] AS
Datepart
("d"
,[Date].[Calendar].CurrentMember.Member_Caption
)
MEMBER [Measures].[MyDayString] AS
'[Date].[Calendar].&[200603' + Cstr([Measures].[MyDay]) + ']'
MEMBER [Measures].[SomeOther] AS
(
StrToMember
(
[Measures].[MyDayString]
,constrained
)
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[MyDay]
,[Measures].[SomeOther]
} ON COLUMNS
,Tail
(
Descendants
(
[Date].[Calendar].[Month].&[2005]&[8]
,[Date].[Calendar].[Date]
)
,10
) ON ROWS
FROM [Adventure Works];
Above returns the following:
So something like this in your cube:
WITH
MEMBER [Measures].[MyDay] AS
Datepart
("d"
,MyDateDimension.CurrentMember.Properties("MyProperty")
)
MEMBER [Measures].[MyDayString] AS
StrToMember('MyDateDimension.&[2015]&[4]&[' + Cstr([Measures].[MyDay]) + ']')
MEMBER [Measures].[SomeOther] AS
(
StrToMember
(
[Measures].[MyDayString]
,constrained
)
,[Measures].[Other]
)
SELECT
{
[Measures].[MyDay]
,[Measures].[SomeOther]
} ON COLUMNS
,{MyDateDimension.MEMBERS} ON ROWS
FROM YourCube;
Try using the SUM function in the definition of [Measures].[SomeOther]. It will accept calculated members.
MEMBER [Measures].[SomeOther] as
SUM(
MyDateDimension.[MyMember],
[Measures].[Other]
)