MDX Query with running total across crossjoined dimensions - ssas

I have a cube with the following three dimensions: Date, Time and Shift. I have a measure called [Pieces Succeeded], and I want a running total of the [Pieces Succeeded] by hour for a Shift. A Shift can span more than one day, so in the following query, I do a crossjoin of the Date and Time dimensions.
with
member [Measures].[Pieces Succeeded Running Total] as
sum([Time].[Hierarchy].[Hour].FirstMember:[Time].[Hour].CurrentMember, [Measures].[Pieces Succeeded])
select
{ [Measures].[Pieces Succeeded], [Measures].[Pieces Succeeded Running Total] } on columns,
nonempty(crossjoin([Date].[Month Hierarchy].[Day].Members, [Time].[Hierarchy].[Hour].Members)) on rows
from
[OEE]
where
[Shift].[Month Hierarchy].[Shift].&[501]
Which gives the following results:
Date Hour Pieces Succeeded Pieces Succeeded Running Total
03 Apr 2011 22 6393 6393
03 Apr 2011 23 6424 12817
04 Apr 2011 00 3816 3816
04 Apr 2011 01 5510 9326
04 Apr 2011 02 2090 11416
04 Apr 2011 03 7489 18905
04 Apr 2011 04 7307 26212
04 Apr 2011 05 5706 31918
How would I go about getting the sum to work on the crossjoined set so that the Running Total works across days?
Thanks

I spent all day on this, and finally figured it out. I thought it might be valuable for someone else, so here's the solution:
with
set DateHours as
nonempty(crossjoin([Date].[Month Hierarchy].[Day].Members, [Time].[Hierarchy].[Hour].Members), [Measures].[Pieces Succeeded])
member [Measures].[Rank] as
rank(([Date].[Month Hierarchy].CurrentMember, [Time].[Hierarchy].CurrentMember ), DateHours)
member [Measures].[Running Pieces Succeeded] as
iif([Measures].[Rank] = 1, [Measures].[Pieces Succeeded], sum(head(DateHours, [Measures].[rank]), [Measures].[Pieces Succeeded]))
select
{ [Measures].[Pieces Succeeded], [Measures].[Running Pieces Succeeded] } on columns,
non empty { DateHours } on rows
from
[OEE]
where
[Shift].[Month Hierarchy].[Shift].&[501]

Related

Sort String Value for Date in SQL

I have an issue as I am trying to select Date values stored in SQL server as String value with this format "Thu, 08 Jul 2021 06:08:20 -0700" and i need to select all table with newest date in first but I do not know how to convert this String into Date and sort it. Thanks in advance.
Table
|Thu, 08 Jul 2021 06:08:20 -0700|
|Fri, 09 Jul 2021 01:08:20 -0700|
|Sun, 11 Jul 2021 07:08:20 -0700|
output (Newest Date first)
|Sun, 11 Jul 2021 07:08:20 -0700|
|Fri, 09 Jul 2021 01:08:20 -0700|
|Thu, 08 Jul 2021 06:08:20 -0700|
Your date is just missing a valid timezone offset value so needs a ":" inserted so it's -07:00, you can do this with stuff and use substring to ignore the irrelevant day name. You don't state a specific database platform, for SQL Server you can then cast to a datetimeoffset, other databases have similar but slightly varied syntax. This assumes the strings are all formatted consistently of course.
declare #d varchar(30)='Thu, 08 Jul 2021 06:08:20 -0700'
select Cast(Stuff(Substring(#d,6,26),25,0,':') as datetimeoffset(0))
Result
2021-07-08 06:08:20 -07:00

How to calculate median monthly from date of month table?

My dataset:
Date Num_orders
Mar 21 2019 69
Mar 22 2019 82
Mar 24 2019 312
Mar 25 2019 199
Mar 26 2019 2,629
Mar 27 2019 2,819
Mar 28 2019 3,123
Mar 29 2019 3,332
Mar 30 2019 1,863
Mar 31 2019 1,097
Apr 01 2019 1,578
Apr 02 2019 2,353
Apr 03 2019 2,768
Apr 04 2019 2,648
Apr 05 2019 3,192
Apr 06 2019 2,363
Apr 07 2019 1,578
Apr 08 2019 3,090
Apr 09 2019 3,814
Apr 10 2019 3,836
...
I need to calculate the monthly median number of orders from days of the same month:
The desired results:
Month Median_monthly
Mar 2019 1,863
Apr 2019 2,768
May 2019 2,876
Jun 2019 ...
...
I tried to use function date_trunc to extract month from the dataset then group by 'month' but it didn't work out. Thanks for your help, I use Google Bigquery (#standard) environment!
Probably you tried to use PERCENTILE_CONT which can not be used with GROUP BY:
Try to use APPROX_QUANTILES(x, 100)[OFFSET(50)]. It should work with GROUP BY.
SELECT APPROX_QUANTILES](Num_orders, 100)\[OFFSET(50)\] AS median
FROM myTable
GROUP BY Month
Alternativele you can use PERCENTILE_CONT within subquery:
SELECT
DISTINCT Month, median
FROM (
SELECT
Month,
PERCENTILE_CONT(Num_orders, 0.5) OVER(PARTITION BY Month) AS median
FROM myTable
)
This would often be done using DISTINCT:
SELECT DISTINCT DATE_TRUNC(month, date),
PERCENTILE_CONT(Num_orders, 0.5) OVER (PARTITION BY DATE_TRUNC(month, date) AS median
FROM myTable;
Note: There are two percentile functions, PERCENTILE_CONT() and PERCENTILE_DISC(). They have different results when there is a "tie" in the middle of the data.

SQL Grouping cube and pivot

I'm trying to do the following query where I obtain a table grouping by years, month and sites, and then I pivot this sites to columns:
SELECT * FROM
(
SELECT
DECODE(GROUPING(TO_CHAR(TM.TIMESTAMP,'YYYY'))
,0, TO_CHAR(TM.TIMESTAMP,'YYYY')
,1, 'TOTAL') AS "YEAR",
DECODE(GROUPING(TO_CHAR(TM.TIMESTAMP,'MM'))
,0, TO_CHAR(TM.TIMESTAMP,'MM')
,1, 'TOTAL') AS "MONTH",
DECODE(GROUPING(TS.CODIGO5)
,0, TS.CODIGO5
,1, 'TOTAL') AS BU,
SUM(TM.KWHGEN) AS GEN
FROM T_MEDIDAS_CO TM
JOIN T_Sede TS ON TM.id_sede=TS.id_sede
WHERE TO_CHAR(TM.TIMESTAMP,'YYYY') IN (2015,2014)
AND TS.CODIGO5 IN ('FINSI', 'FINOC')
GROUP BY CUBE (TO_CHAR(TM.TIMESTAMP,'YYYY'), TO_CHAR(TM.TIMESTAMP,'MM'), TS.CODIGO5)
ORDER BY TO_CHAR(TM.TIMESTAMP,'YYYY') DESC, TO_CHAR(TM.TIMESTAMP,'MM') DESC, 3
)
PIVOT
(
SUM(GEN)
FOR BU IN ('FINCI' AS FINCI,'FINSI' AS FINSI, 'FINOC' AS FINOC, 'TOTAL' AS TOTAL)
)
ORDER BY "YEAR" DESC, "MONTH" DESC
to obtain this result
YEAR MONTH FINCI FINOC TOTAL
2015 12 110376,17 109991,55 220367,72
2015 11 92032,56 97938,09 189970,65
2015 10 77668,67 79273,98 156942,65
2015 09 87079,46 91203,73 178283,19
2015 08 99992,38 100220,24 200212,62
2015 07 142430 133979,74 276409,74
2015 06 107006,73 104320,96 211327,69
2015 05 86264 90985,62 177249,62
2015 04 85838,41 87147,74 172986,15
2015 03 106178,39 106342,4 212520,79
2015 02 125007,65 122790,76 247798,41
2015 01 134934,67 135897,7 270832,37
2015 TOTAL 1254809,09 1260092,51 2514901,6
2014 12 121185,25 122014,9 243200,15
2014 11 94682,9 94221,47 188904,37
2014 10 87212,59 92222,92 179435,51
2014 09 97306,19 100701,93 198008,12
2014 08 97738,26 101901,88 199640,14
2014 07 113242,07 117496,84 230738,91
2014 06 98234,69 98092,2 196326,89
2014 05 91202,74 102214,94 193417,68
2014 04 88517,65 103756,83 192274,48
2014 03 107541,53 119236,48 226778,01
2014 02 127880,75 131451,38 259332,13
2014 01 141381,35 143836,44 285217,79
2014 TOTAL 1266125,97 1327148,21 2593274,18
TOTAL 12 231561,42 232006,45 463567,87
TOTAL 11 186715,46 192159,56 378875,02
TOTAL 10 164881,26 171496,9 336378,16
TOTAL 09 184385,65 191905,66 376291,31
TOTAL 08 197730,64 202122,12 399852,76
TOTAL 07 255672,07 251476,58 507148,65
TOTAL 06 205241,42 202413,16 407654,58
TOTAL 05 177466,74 193200,56 370667,3
TOTAL 04 174356,06 190904,57 365260,63
TOTAL 03 213719,92 225578,88 439298,8
TOTAL 02 252888,4 254242,14 507130,54
TOTAL 01 276316,02 279734,14 556050,16
TOTAL TOTAL 2520935,06 2587240,72 5108175,78
But, I don't need the TOTAL | MONTH rows, how can I fix it?
Thanks a lot

Best way to store aggregated values

We need to store aggregated values for different accounts which summarise various numbers on Month/Year basis. These numbers would be updated each time the data is updated (usually once or twice every 24 hours).
I'm expecting the data to be the results of PIVOT functions e.g.:
Year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2011 0 0 0 0 0 0 95 33 34 24 36 52
Each account will need different aggregates e.g. "Count Of Customers", "Count Of Orders" and "Value Of Sales" and I'm not sure whether it would be best to add a key to the data or use separate tables e.g.:
Year Key Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2011 CntOrders 0 0 0 0 0 0 95 33 34 24 36 52
2011 CntCust 0 0 0 0 0 0 95 33 34 24 36 52
2011 ValOrders 0 0 0 0 0 0 95 33 34 24 36 52
Or
dbo.CountOfOrders
Year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2011 0 0 0 0 0 0 95 33 34 24 36 52
dbo.ValueOfOrders
Year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2011 0 0 0 0 0 0 95 33 34 24 36 52
I've read a number of posts suggesting both NoSQL and SQL Server so I'm not sure which way we should go or how to decide.
We can't justify a dedicated cube at the moment but I'm wondering if it would be better to store the values in a NoSQL database or whether we should stick with SQL Server?
I'll stick with SQL. However, if you are worried about the time to rebuild such PIVOT table, don't, because you don't have to necessarily build a table with unique "key".
Build it with key + process datetime and just append it to the main pivot. So during creation of the incrementals it will be bounded by your transaction timestamp (begin and end). There should be much bloat. If there is, you can collapse the process dates in a weekend job.
Set up a job to run stored procedures that insert data into tables.
Store the data like Account,Year,Month,Value
Use views of these tables for reporting multiple aggregates.
Definitely stick with SQL. There is no reason to add technical overhead for such a simple task.

MDX: Aggregates over a set

What I am trying to achieves looks very simple, yet I cannot make it work.
My facts are orders which have a date and I have a typical time dimension with the 'Month" and 'Year' levels.
I would like to get an output which lists the number of orders for the last 6 months and the total, like this:
Oct 2009 20
Nov 2009 30
Dec 2009 25
Jan 2009 15
Feb 2010 45
Mar 2010 5
Total 140
I can create the set with the members Oct 2009 until Mar 2010 and I manage to get this part of my desired output:
Oct 2009 20
Nov 2009 30
Dec 2009 25
Jan 2009 15
Feb 2010 45
Mar 2010 5
Just I fail to get the total line.
You can achieve this by adding the ALL member to the set and then wrapping it all in the VisualTotals() function
SELECT
... on COLUMNS,
VISUALTOTALS (
{[Month].[Month].[Oct 2009]:[Month].[Month].[Mar 2010]
, [Month].[Month].[All] }
) ON ROWS
FROM <cube>
here is one possible solution for Adventure Works DW Demo Cube. The query selects the last 6 Order Counts and add a sum on the date dimension:
WITH MEMBER [Date].[Calendar].[Last 6 Mth Order Count] AS
aggregate(
ClosingPeriod([Date].[Calendar].[Month], [Date].[Calendar].[All Periods]).Lag(6)
: ClosingPeriod([Date].[Calendar].[Month], [Date].[Calendar].[All Periods])
)
SELECT {[Measures].[Order Count]} ON COLUMNS
, {ClosingPeriod([Date].[Calendar].[Month], [Date].[Calendar].[All Periods]).Lag(6)
: ClosingPeriod([Date].[Calendar].[Month], [Date].[Calendar].[All Periods])
,[Date].[Calendar].[Last 6 Mth Order Count]}
ON ROWS
FROM [Adventure Works]