MDX to get the value and use it on a hierarchy - mdx

I have a MDX script that my goal is to be able to get the value of a date that could it a day, week, month, quarter or year and then use it on a hierarchy.
WITH
MEMBER measures.suma AS
Sum
(
[Date Local].[year-quarter-month-week-day].Children
,IIF
(
(
[Measures].[Agent Time Logged in hh:mm:ss]
-
[Measures].[Activity Time Break]
-
[Measures].[Activity Time Meeting]
-
[Measures].[Activity Time Training]
)
/
26400 / 86400
> 1
,1
,
(
[Measures].[Agent Time Logged in hh:mm:ss]
-
[Measures].[Activity Time Break]
-
[Measures].[Activity Time Meeting]
-
[Measures].[Activity Time Training]
)
/
26400 / 86400
)
)
SELECT
{
measures.suma
,[Measures].[MyKeys]
,[Measures].[Agent Time Logged in hh:mm:ss]
,[Measures].[Activity Time Break]
,[Measures].[Activity Time Meeting]
,[Measures].[Activity Time Training]
,[Measures].[Activity time Lunch]
} ON 0
,NON EMPTY
[Agent].[login fullname].[login fullname] ON 1
FROM [HP TRANSACTIONAL]
WHERE
[Date Local].[Month].&[2015-08 August];-- DOESNT WORK
--[Date Local].[year-quarter-month-week-day].[Week].&[2015 Week 35] --IT WORKS
As you can see in my MDX script I want to sum all the activities of an agent and the client can choose any filter, per day, week, month, quarter or year.
Of course that thay can use my hierarchy "[Date Local].[Month].&[2015-08 August]" but my client is using EXCEL to create the reports and they can use any attribute of the date dimension.
So my goal is to find a way to indicate to my mdx script that if the client choose any attribute, should be able to get the current member and use the hierarchy to make the calculation.

Maybe just try the keyword Existing to try to force context up into your measure suma
WITH
MEMBER [measures].[suma] AS
Sum
(
EXISTING([Date Local].[year-quarter-month-week-day].MEMBERS)
,IIF
(
(
[Measures].[Agent Time Logged in hh:mm:ss]
-
[Measures].[Activity Time Break]
-
[Measures].[Activity Time Meeting]
-
[Measures].[Activity Time Training]
)
/
26400 / 86400
> 1
,1
,
(
[Measures].[Agent Time Logged in hh:mm:ss]
-
[Measures].[Activity Time Break]
-
[Measures].[Activity Time Meeting]
-
[Measures].[Activity Time Training]
)
/
26400 / 86400
)
)
SELECT
{
measures.suma
,[Measures].[MyKeys]
,[Measures].[Agent Time Logged in hh:mm:ss]
,[Measures].[Activity Time Break]
,[Measures].[Activity Time Meeting]
,[Measures].[Activity Time Training]
,[Measures].[Activity time Lunch]
} ON 0
,NON EMPTY
[Agent].[login fullname].[login fullname] ON 1
FROM [HP TRANSACTIONAL]
WHERE
[Date Local].[Month].&[2015-08 August];-- DOESNT WORK
--[Date Local].[year-quarter-month-week-day].[Week].&[2015 Week 35] --IT WORKS

I found a solution!!
WITH
MEMBER measures.suma AS
Sum
(
(EXISTING
[Date Local].[year-quarter-month-week-day].[Day name])
,IIF
(
(
[Measures].[Agent Time Logged in hh:mm:ss]
-
[Measures].[Activity Time Break]
-
[Measures].[Activity Time Meeting]
-
[Measures].[Activity Time Training]
)
/
26400 / 86400
> 1
,1
,
(
[Measures].[Agent Time Logged in hh:mm:ss]
-
[Measures].[Activity Time Break]
-
[Measures].[Activity Time Meeting]
-
[Measures].[Activity Time Training]
)
/
26400 / 86400
)
)
SELECT
{
measures.suma
,[Measures].[Agent Time Logged in hh:mm:ss]
,[Measures].[Activity Time Break]
,[Measures].[Activity Time Meeting]
,[Measures].[Activity Time Training]
,[Measures].[Activity time Lunch]
} ON 0
,NON EMPTY
[Agent].[login fullname].[login fullname] ON 1
FROM [HP TRANSACTIONAL]
WHERE
[Date Local].[Date Standard].&[2015-08-24T00:00:00];
--TEST
--[Date Local].[Week].&[2015 Week 35]
--[Date Local].[Month].&[2015-08 August]
--[Date Local].[year-quarter-month-week-day].[Week].&[2015 Week 35]
I hope this solution can help to other person.
Raul

Related

Combine Output of Queries in Pivot Table with PostgreSQL

Suppose I have a table called orders that looks like this:
id
order date
Orders_Wanted
Orders_Given
1
2020-11-29 19:12:44.417
2
6
1
2020-11-29 20:12:44.417
2
6
1
2020-11-30 23:37:28.692
8
2
1
2020-11-30 23:37:28.692
2
6
How do I write a query that shows the count of orders_wanted - orders_given by hour broken down into two columns, one that counts positive results and one that counts negative results (a note that orders_wanted and orders_given are times, so that's why I am calculating orders_wanted - orders_given). I would also like to add a final column that calculates the percentage of total orders per hour that are positive (count_orders_positive/ (count_orders_negative + Count_orders_positive)).
The output of the query would look something like this:
week
day
hour
count_orders_positive
count_orders_negative
Percentage_orders_positive
48
7
19
0
1
100%
48
7
20
0
1
100%
49
1
23
1
1
50%
So far I am able to get the bottom two results using these queries, but I don't know how to combine them.
SELECT
extract (week from (order_date at time zone 'MST' at time zone 'UTC') ) as "week",
extract (isodow from (order_date at time zone 'MST' at time zone 'UTC') ) as "day",
extract (hour from (order_date at time zone 'MST' at time zone 'UTC') ) as "hour",
Count (extract (hour from (order_date at time zone 'MST' at time zone 'UTC') )) as
"count_orders_positive"
from orders
WHERE orders_wanted - orders_given >= 0
group by week, day, hour
order by week, day, hour;
week
day
hour
count_orders_positive
49
1
23
1
SELECT
extract (week from (order_date at time zone 'MST' at time zone 'UTC') ) as "week",
extract (isodow from (order_date at time zone 'MST' at time zone 'UTC') ) as "day",
extract (hour from (order_date at time zone 'MST' at time zone 'UTC') ) as "hour",
Count (extract (hour from (order_date at time zone 'MST' at time zone 'UTC') )) as
"count_orders_negative"
from orders
WHERE orders_wanted - orders_given < 0
group by week, day, hour
order by week, day, hour;
week
day
hour
count_orders_negative
48
7
19
1
48
7
20
1
49
1
23
1
You can do conditional aggregation. avg() comes handy to compute the percentage:
select
extract (week from (order_date at time zone 'MST' at time zone 'UTC') ) as "week",
extract (isodow from (order_date at time zone 'MST' at time zone 'UTC') ) as "day",
extract (hour from (order_date at time zone 'MST' at time zone 'UTC') ) as "hour",
count(*) filter (where orders_wanted - orders_given >= 0) as count_orders_positive,
count(*) filter (where orders_wanted - orders_given < 0) as count_orders_negative,
100 * avg((orders_wanted - orders_given >= 0)::int) as percent_orders_positive
from orders
group by week, day, hour
order by week, day, hour;

OLAP Cube Calculation for Last Year Comparison on Week Day - MDX

I want to compare actual sales values with sales values of last year. The difficulty in this comparison is the compliance of the week days and thereby of the leap-year.
Example on day level:
2016-02-04 (thursday): actual sales: 580,- last year sales: 1.008,-
comparison with
2015-02-05 (thursday): actual sales: 1.008,-
So i want to compare the same week days in the month and not only the same dates.
Example on month level:
2016: (leap-year)
01.02.2016 - 29.02.2019 (february 2016) actual Sales: 19.300,- : last year Sales value: 19.000,-
comparison with
2015: (no leap year)
02.02.2015 - 02.03.2015 (february 2015 on week day logic) actual sales value: 19.000,-
I want not only compare February 2016 with february 2015 rather exactly the week day sales values summed.
I tried to write this calculation with an date calculation dimension and it works but only on the day level. Name of the calculation dimension: Date Calculations Week Day name of the member: ComparisonWD
SCOPE (
[Date].[Year - Quarter - Month - Date].MEMBERS,
[Date].[Date].MEMBERS );
( [Date Calculations Week Day].[ComparisonWD].[Previous Year],
[Date Calculations Week Day].[AggregationWD].Members )
= ( [Date Calculations Week Day].[ComparisonWD].DefaultMember,
ParallelPeriod( [Date].[Year - Quarter - Month - Date].[Date],
364,
[Date].[Year - Quarter - Month - Date].CurrentMember ) );
END SCOPE;
Result 2015:
Result 2016:
It works on day level, but as you seen not on the month and not onthe year level.
How can I achieve this?
I got the solution:
Cube Calculation Code for this problem:
// ------------------------------------------------------------------------
//
// Comparison Week Day - Date.Calendar
//
// ------------------------------------------------------------------------
SCOPE (
[Date].[Year - Quarter - Month - Date].MEMBERS,
[Date].[Date].MEMBERS );
///////////////////////////////////////////////////////////////////////////////////////
( [Date Calculations Week Day].[ComparisonWD].[Previous Year],
[Date Calculations Week Day].[AggregationWD].Members )
= SUM({ParallelPeriod([Date].[Year - Quarter - Month - Date].[Date], 364, Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Year - Quarter - Month - Date].[Date]).item(0)) :
Parallelperiod ([Date].[Year - Quarter - Month - Date].[Date], 364, Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Year - Quarter - Month - Date].[Date]).item((Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Year - Quarter - Month - Date].[Date])).Count - 1))}, [Date Calculations Week Day].[ComparisonWD].DefaultMember );
END SCOPE;
SCOPE ([Date Calculations Week Day].[ComparisonWD].[Diff. Over Previous Year]);
THIS = IIF( IsEmpty( [Date Calculations Week Day].[ComparisonWD].DefaultMember )
OR IsEmpty( [Date Calculations Week Day].[ComparisonWD].[Previous Year] ),
NULL,
[Date Calculations Week Day].[ComparisonWD].DefaultMember
- [Date Calculations Week Day].[ComparisonWD].[Previous Year] );
NON_EMPTY_BEHAVIOR(THIS) = [Date Calculations Week Day].[ComparisonWD].DefaultMember;
FORE_COLOR(THIS) = IIF( [Date Calculations Week Day].[ComparisonWD].[Diff. Over Previous Year] < 0, 255, 0); // 255 = RED
END SCOPE;
SCOPE ([Date Calculations Week Day].[ComparisonWD].[Diff. % Over Previous Year]);
THIS = IIF( IsEmpty( [Date Calculations Week Day].[ComparisonWD].[Diff. Over Previous Year] )
OR IsEmpty( [Date Calculations Week Day].[ComparisonWD].[Previous Year] ),
NULL,
[Date Calculations Week Day].[ComparisonWD].[Diff. Over Previous Year]
/ [Date Calculations Week Day].[ComparisonWD].[Previous Year] );
NON_EMPTY_BEHAVIOR(THIS) = [Date Calculations Week Day].[ComparisonWD].DefaultMember;
FORMAT_STRING(THIS) = 'Percent';
FORE_COLOR(THIS) = IIF( [Date Calculations Week Day].[ComparisonWD].[Diff. % Over Previous Year] < 0, 255, 0); // 255 = RED
END SCOPE;
///////////////
// Tuple (All years, All Months) is the default number (keeps compatibility with OWC11)
( [Date].[Year].[All], [Date].[MonthYear].[All],
Except( [Date Calculations Week Day].[ComparisonWD].[ComparisonWD].MEMBERS, [Date Calculations Week Day].[ComparisonWD].DefaultMember ) ) = [Date Calculations Week Day].[ComparisonWD].DefaultMember;
Now with summed values on every level:
With this Date Calculations Week Day Dimension you can show for every Measure the Prev Year Values on Week day logic.
Not exactly answering the question but in the following context PARALLELPERIOD seems quite generic:
1.
At the Month level:
WITH
MEMBER [Measures].[PY Internet Sales Amount] AS
(
ParallelPeriod
(
[Date].[Calendar].[Calendar Year]
,1
,[Date].[Calendar].CurrentMember
)
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Measures].[PY Internet Sales Amount]
} ON 0
,{
//[Date].[Calendar].[Date].&[20130101]:[Date].[Calendar].[Date].&[20130601]
[Date].[Calendar].[Month].[January 2012]:[Date].[Calendar].[Month].[December 2013]
} ON 1
FROM [Adventure Works];
Gives this:
2.
Changing to the Date level but leaving the PARALLELPERIOD calculation the same:
WITH
MEMBER [Measures].[PY Internet Sales Amount] AS
(
ParallelPeriod
(
[Date].[Calendar].[Calendar Year]
,1
,[Date].[Calendar].CurrentMember
)
,[Measures].[Internet Sales Amount]
)
SELECT
{
[Measures].[Internet Sales Amount]
,[Measures].[PY Internet Sales Amount]
} ON 0
,{
[Date].[Calendar].[Date].&[20130101]:[Date].[Calendar].[Date].&[20130601]
//[Date].[Calendar].[Month].[January 2012]:[Date].[Calendar].[Month].[December 2013]
} ON 1
FROM [Adventure Works];
Gives these results (no NULLS):
Just tried to imitate the problem as a mdx query in ssms and it works. How can i apply on my cube calculation:
with
set [DateRange] as ( { ParallelPeriod([Date].[Year - Quarter - Month - Date].[Date],
364,
Descendants( [Date].[Year - Quarter - Month - Date].[Year].&[2013] , [Date].[Year - Quarter - Month - Date].[Date]).item(0)
) :
Parallelperiod ([Date].[Year - Quarter - Month - Date].[Date],
364,
Descendants( [Date].[Year - Quarter - Month - Date].[Year].&[2013] , [Date].[Year - Quarter - Month - Date].[Date]).item((Descendants(
[Date].[Year - Quarter - Month - Date].[Year].&[2013] , [Date].[Year - Quarter - Month - Date].[Date])).Count - 1))})
Select {
[Measures].[Turnover]
} on Columns,
non empty
(
[DateRange]
) on Rows
from [Sales Cube]
Following result:
Turnover Net
03.01.2012 642
04.01.2012 665
05.01.2012 633
06.01.2012 730
07.01.2012 761
08.01.2012 531
09.01.2012 422
10.01.2012 488
11.01.2012 518
.
.
.
23.12.2012 618
24.12.2012 174
25.12.2012 137
26.12.2012 536
27.12.2012 981
28.12.2012 1.052
29.12.2012 1.006
30.12.2012 847
31.12.2012 695
01.01.2013 572
So you see, the date range is correct 2012-01-03 - 2013-01-01
In the query i take the date and descendant it to the lowest level (day) and then generate a date range. First date of range - 364 days and the last date of range -364 days to get the correct date range. Unfortunately i doesn't works in the cube calculation:
// ------------------------------------------------------------------------
//
// Comparison Week Day - Date.Calendar
//
// ------------------------------------------------------------------------
SCOPE (
[Date].[Year - Quarter - Month - Date].MEMBERS,
[Date].[Date].MEMBERS );
///////////////////////////////////////////////////////////////////////////////////////
( [Date Calculations Week Day].[ComparisonWD].[Previous Year],
[Date Calculations Week Day].[AggregationWD].Members )
= SUM( [Date Calculations Week Day].[ComparisonWD].DefaultMember,
{ParallelPeriod([Date].[Year - Quarter - Month - Date].[Date], 364, Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Date]).item(0)) :
Parallelperiod ([Date].[Year - Quarter - Month - Date].[Date], 364, Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Date]).item((Descendants( [Date].[Year - Quarter - Month - Date].CurrentMember , [Date].[Date])).Count - 1))} );
END SCOPE;

Syntax error to get the 6th Business day after 25th of the month plus 5 business days

Im working on a report that needs to show the exact date to determine who incurred late submission of charges. I added 3 queries and the last one to find the business day after the 25th of the month is giving me "An error occurred while performing operation 'sqlPrepareWithOptions' status = '239'
Can you help me please? The data item is 5 BUSINESS DAYS AFTER 25 and here's the query below:
CASE WHEN _day_of_week( _add_days( [FIND 25TH DAY OF MONTH] , 5 ) ) BETWEEN 1 AND 5
THEN '1'
WHEN _day_of_week( _add_days( [FIND 25TH DAY OF MONTH] , 6 ) ) BETWEEN 1 AND 5
THEN '1'
WHEN _day_of_week( _add_days( [FIND 25TH DAY OF MONTH] , 7 ) ) BETWEEN 1 AND 5
THEN '1'
WHEN _day_of_week( _add_days( [FIND 25TH DAY OF MONTH] , 5 ) ) BETWEEN 6 AND 7
THEN '0'
ELSE '0'
END
These are the 2 other queries that are working just fine:
LAST DAY OF LAST MONTH
_add_days (_first_of_month (CURRENT_DATE), -1)
FIND 25TH DAY OF MONTH
CASE
WHEN EXTRACT( DAY , _add_days([LAST DAY OF LAST MONTH] , - 2) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 2)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 3) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 3)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 4) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 4)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 5) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 5)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 6) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 6)
WHEN EXTRACT( DAY, _add_days([LAST DAY OF LAST MONTH], - 7) ) = 25
THEN _add_days([LAST DAY OF LAST MONTH] , - 7)
ELSE CURRENT_DATE
END

Oracle : SQL : Return seconds between two datetime fields

All, I have read a number of solutions and from what I saw doesn't resolve my issue. The reason, I have one datetime stamp right before midnight AND I have one datetime stamp after midnight.
Using the EXTRACT function doesn't cut it because the hours/min/sec before midnight will be 86k seconds and the hours/min/sec after will be within the 100s. The number of seconds should be around 240, but in this scenario it is -86,000+
Here is what I was using, but again, doesn't work for those datetime stamps before and after midnight.
( ( EXTRACT( hour FROM CALL_START_TIME ) * 60 * 60 ) +
( EXTRACT( minute FROM CALL_START_TIME ) * 60 ) +
( EXTRACT( second FROM CALL_START_TIME ) ) ) -
( ( EXTRACT( hour FROM CALL_END_TIME ) * 60 * 60 ) +
( EXTRACT( minute FROM CALL_END_TIME ) * 60 ) +
( EXTRACT( second FROM CALL_END_TIME ) ) ) AS SPEED_TO_ANSWER
If you subtract start time from end time, you get the number of days, which may be something like 0.00123 in your case. Multiply by 24 to get to hours, then with 60 to get minutes, again with 60 to get seconds:
(CALL_END_TIME - CALL_START_TIME) * 24 * 60 * 60

SQL statement dynamically using current time to choose a time frame in a field (Oracle)

All, I have something that is stumping me and I have seen a lot of examples, but nothing is helping solve this.
I have time frames like 03:30:00 to 11:29:59 that I work with (say shift times). I want to dynamically query data for the last shift based on the current shift.
Example: if it is currently between 11:30:00 AM and 7:29:59 PM, I want get the last shift that was between 03:30:00 AM and 11:30:00 AM.
This would look like an if statement in my mind:
If time between .... then
select time between....
elseif time between.... then
select time between...
I tried many combinations and can't figure this out. I think I would need a CASE and maybe a subquery? or maybe DECODE will work?
SELECT CAST(ccd.DATEc AS TIME) as time_occured,
FROM db.datatb ccd
WHERE ccd.DATE > SYSDATE - interval '1440' minute
AND (
((TO_CHAR(SYSDATE, 'hh24:mi:ss')BETWEEN '03:30:00' AND '11:29:59' IN (SELECT
ccd.DATEc FROM db.datatb WHERE (CAST(ccd.DATEc AS TIME)NOT BETWEEN '03:30:00
AM' AND '07:29:59 PM')))
OR (TO_CHAR(SYSDATE, 'hh24:mi:ss')BETWEEN '11:30:00' AND '19:29:59' IN
(SELECT ccd.DATEc FROM db.datatb WHERE (CAST(ccd.DATEc AS TIME) BETWEEN
'03:30:00 AM' AND '11:29:59 AM')))
OR (TO_CHAR(SYSDATE, 'hh24:mi:ss')NOT BETWEEN '03:30:00' AND '19:29:59' IN
(SELECT ccd.DATEc FROM db.datatb WHERE (CAST(ccd.DATEc AS TIME) BETWEEN
'11:30:00 AM' AND '07:29:59 PM')))
)
SELECT *
FROM db.datatb
CROSS JOIN
( SELECT TRUNC( SYSDATE - INTERVAL '210' MINUTE )
+ NUMTODSINTERVAL(
TRUNC(
( SYSDATE - INTERVAL '210' MINUTE
- TRUNC( SYSDATE - INTERVAL '210' MINUTE )
) * 3
) * 480
+ 210,
'MINUTE'
) AS current_shift_start
FROM DUAL
) css
WHERE DATEc >= css.current_shift_start - INTERVAL '8' HOUR
AND DATEc < css.current_shift_start;
Explanation:
The shifts are 8 hours each starting at 03:30 (or 210 minutes past midnight); so SYSDATE - INTERVAL '210' MINUTE will move offset the times so that after this offset they start at 00:00, 08:00 and 16:00 which is thirds of a day.
date_value - TRUNC( date_value ) calculates the fraction of a day (between 0 and 1) that the time component represents; so TRUNC( ( date_value - TRUNC( date_value ) ) * 3 ) maps that fraction of the day to 0, 1 or 2 corresponding to whether it is in the 1st, 2nd or 3rd 8 hour period of the day. Multiple that value by 480 minutes and then add the 210 minutes that the date was originally offset by and you have the minutes past the start of the day that the shift starts.