How to make a (MDX) calculation in a SSAS cube to get the difference between a value from the current row and a value from the previous row? - ssas

I would like to make a calculation to get the difference between the departDate from my current row and the arriveDateNextStop from my previous row. I have a fact table which has multiple columns. The three most important columns are: id, departDate, arriveDateNextStop.
If I have for example these two rows in my fact table:
id departDate arriveDateNextStop
1 01-01-2019 03-01-2019
1 04-01-2019 07-01-2019
Explanation: On 1 January 2019 I depart to the next destination and I arrive there on 3 January 2019. On 4 January 2019 I again depart to the next destination and I arrive there on 7 January 2019.
Now I would like to know how many days the idle time was (the amount of days between the arrival and the next depart). So with this example the idle time would be 1, because between 3 January 2019 and 4 January 2019 is one day.
First, I made this 'calculation' in Management Studio as a SQL query. See query below:
SELECT s.Id, s.departDate as Depart_current_place, s.arriveDateNextStop as Arrival_next_stop, LAG(arriveDateNextStop) OVER (ORDER BY arriveDateNextStop) AS Arrival_current_stop, DATEDIFF(DAY, LAG(arriveDateNextStop) OVER (ORDER BY arriveDateNextStop), departDate) AS Amount_of_days
FROM MyTable s
WHERE Id = 9
GROUP BY s.departDate, s.Id, s.arriveDateNextStop
ORDER BY s.departDate
This query works fine, but how can I do this in my cube as a calculation in MDX?

I don't have the same example, but the similar cube structure with Completed/Received date:
with
member departDate as [Received].[Year Qtr Month].CurrentMember.Member_Key
member arriveDate as [Completed].[Year Qtr Month].CurrentMember.Member_Key
member arriveDateNextStop as [Completed].[Year Qtr Month].CurrentMember.Lead(1).Member_Key
member idleDays as departDate-arriveDateNextStop
SELECT NON EMPTY { departDate,arriveDate,arriveDateNextStop,idleDays } ON 0
, NON EMPTY
{ ([Completed].[Year Qtr Month].[Date].ALLMEMBERS
* [Received].[Year Qtr Month].[Date].ALLMEMBERS ) } ON 1
FROM ( SELECT ( { [Completed].[Year Qtr Month].[Date].&[6213] } ) ON COLUMNS
FROM [MyCube])
I also have integer key for a date dimension (CurrentMember.Member_Key). 1 = 1998-01-01, 2 = 1998-01-02 etc. till today. You need to create a property in a Date dimension if your Date key is classic YYYYMMDD (which you cannot subtract to get days difference, I can do that in my example). And use it like CurrentMember.Properties("property name") instead of Member_Key.
Main formula part: Lag/Lead function to get prev. or next member.
Please update in case of questions.

Related

Add results to a row regarding the last 12 months rows- SQL Server

At my last meeting someone asked me if it was possible to hide people who where ill since a year from a dashboard. So I'm searching for the best way to actually KNOW who has been ill for 12 months.
I am working with a table with the number of days you've been absent for every kind of absence you could have, the number of days you should have been working that month, with a row per person, department and profession each month.
So it looks something like this :
PersonID
YEAR
MONTH
DEPARTMENT
PROFESSION
Absence1
Absence2
Absence3
WORKING DAYS OF THE MONTH...
11111
2021
07
HR
ASSISTANT
0
2
0
22
11111
2021
08
HR
ASSISTANT
0
0
0
22
==> So if I'm on a row of July 2021 I need to check the lines from June 2020 to June 2021.
My guess is that I need to add a column to this table who will say (with some kind of loop maybe) "if for the last 12 months (rows) the total number of days of absence equal the number of working days of the last 12 months then "ILL FOR A YEAR OR MORE" for each person (knowing that a person can work in more than one department or more than one profession so she'll have more than one row per month).
But I really have no idea how to actually write it in a script as I usually do very basic things. I'm using SQL SERVER and have 429 207 rows in the table. I'm thinking about doing it in the whole table and not only treating this month's rows because in the dashboard we show an historic.
Your table is heavily denormalized. If you want to represent all this information in the database, I would have expected the following tables, instead of just one:
Person
Department
Illness (list of illnesses)
IllnessAbsence (join table between Person and Illness)
Either way, you can get the information you need with something like this:
I've assumed you want the whole table, so you need a window function
We need to flip the logic on its head: exclude all rows which have no non-absence in the last 12 months
SELECT
PersonID,
YEAR,
MONTH,
DEPARTMENT,
PROFESSION,
ILLNESS1,
ILLNESS2,
ILLNESS3,
[WORKING DAYS OF THE MONTH]
FROM (
SELECT *,
NotIllLast12Months = COUNT(CASE WHEN DATEFROMPARTS(YEAR + 1, MONTH, 1) >= GETDATE()
AND ILLNESS1 + ILLNESS2 + ILLNESS3 = 0 THEN 1 END)
OVER (PARTITION BY ID)
FROM HETP_ABS
) abs
WHERE NotIllLast12Months > 0;

MDX - Average over the whole time period, even when no data exists

I have a fact table with 1 row for each day. Example:
ID Date Value
1 20190101 10
1 20190102 15
2 20190101 31
If I take a simple Value average in SSAS cube I get:
ID Average <Formula>
1 12.5 (10+15)/2
2 15.5 31/2
As I understand, 15.5 is there because in total there are 2 days in the scope as only two days exist in the fact data when I select the whole month.
However, I need to calculate a monthly average instead. It should check that there are 31 days in that month (based on Date dimension) and get this result:
ID Average <Formula>
1 0.8 (10+15)/31
2 1 31/31
So far I've tried to create some "fake rows" if my data, for example I've tried to create rows with Value = 0 for dates 20190103-20190131 for ID=1.
This works, it forces the calculation for ID=1 to always take all days in the period, but it messes up my other calculations in the cube.
Any other ways to force average calculation in SSAS multidimensional cube to always calculate for the entire month?
If you want to do the calculation in the Cube, you can use the Descendants function on your Date dimension
For eg., the following gives the number of days in a month using the AdventureWorks sample
WITH MEMBER Measures.DayCount AS
Descendants
(
[Date].[Calendar].CurrentMember,
[Date].[Calendar].[Date],
LEAVES
).Count
SELECT [Measures].[DayCount] ON 0,
[Date].[Calendar].[Month].ALLMEMBERS ON 1
FROM [Adventure Works]
I would recommend:
select id, eomonth(date) as eom,
sum(value) * 1.0 / day(eomonth(date)) as average
from t
group by id, eomonth(date);
EOMONTH() returns the last day of the month. You can extract the day to get the number of days in the month.
The * 1.0is because SQL Server does integer division. Your numbers look like integers, but if you are getting 15.5, then you actually have numerics or something other than an integer.

Selecting sets of data and creating a new column in SQL Server

In SQL Server can you select the first set of values (i.e. week numbers 1 - 52) give them another value in a new column, then select the next lot of values.
The problem I am having is the data table I am working on has week numbers for each financial year, which starts the first Sunday after 1 October. So it simply iterates 1 - 52 for each financial year.
I am trying to make a column in a view that grabs the first 52 gives them the a financial year value of 1, then grabs the next 52 and gives them a financial year value of 2 etc (obviously with year 1 starting at the first record). I do have the Week Ending Date column to work with also.
Here is a snippet of the table:
Is this possible?
Leave the Sundays and Octobers. If I understand correctly, you only need to assign a rank to each occurrence of week number in order of the ending dates.
Please try this (but use copy of the table or transaction to check first; of course T is name of your table):
update T
set fiscal_year = YearNumbers.FiscalYear
from T
inner join
(
select WeekEndingDate, WeekNumber, DENSE_RANK() over (partition by WeekNumber order by WeekEndingDate) as FiscalYear
from T
) as YearNumbers
on T.WeekEndingDate = YearNumbers.WeekEndingDate and T.WeekNumber = YearNumbers.WeekNumber

Optimize query for for cumulative result

I have this query to find out item count for every month of year. But I am looking for a optimized query for cumulative result
SELECT
COUNT(ITM.ID) AS ItemCount,
Month(ITM.ItemProcureDate),
Year(ITM.ItemProcureDate)
FROM
Rpt_Item ITM
WHERE
ITM.ItemProcureDate IS NOT NULL
AND
ITM.ItemStatusID = 2 -- Item sold, Item Rejected
AND
ITM.ItemProcureDate >= CONVERT(DATETIME,'02/01/2014',1) --#Beg_Date
AND
ITM.ItemProcureDate <= CONVERT(DATETIME,'04/12/2014',1) --#End_Date
GROUP BY
Month(ITM.ItemProcureDate),
Year(ITM.ItemProcureDate)
Query result should be like this:
Item sold In month 2
Item Sold Till Month 2
Item Rejected 1
Item Rejected Till Month 1
Year 2014
Month Feb
Last Date of Month 02/28/2014
-----------------------------------------------
Item sold In month 2
Item Sold Till Month 4
Item Rejected 1
Item Rejected Till Month 2
Year 2014
Month March
LastDate of Month 03/31/2014
-----------------------------------------------
Item sold In month 2
Item Sold Till Month 6
Item Rejected 1
Item Rejected Till Month 3
Year 2014
Month April
Last Date of Month 04/30/2014
I have to find out Item_Sold, Item_Rejected, Item_Added for last three months where every next month it should be cumulative of all previous months values of Item_Sold, Item_Rejected, Item_Added
In SQL Server 2008, you can do this using a correlated subquery or using a non-equijoin. SQL Server 2012 supports a cumulative sum function. Here is a way to do it with a correlated subquery:
with ym as (
SELECT COUNT(ITM.ID) AS ItemCount,
Month(ITM.ItemProcureDate) as mon, Year(ITM.ItemProcureDate) as yr,
Month(ITM.ItemProcureDate) + 100*Year(ITM.ItemProcureDate) as yyyymm
FROM Rpt_Item ITM
WHERE ITM.ItemProcureDate IS NOT NULL AND
ITM.ItemStatusID = 2 AND
ITM.ItemProcureDate >= CONVERT(DATETIME,'02/01/2014',1) AND
ITM.ItemProcureDate <= CONVERT(DATETIME,'04/12/2014',1)
GROUP BY Month(ITM.ItemProcureDate), Year(ITM.ItemProcureDate)
)
select ym.*,
(select sum(ItemCount)
from ym ym2
where ym.yyyymm <= ym.yyyy.mm
) as cumsum
from ym;
Note that this puts the year-month into a YYYYMM format. This is just a convenience so the comparison on the time period uses only one column.
Also, if the ITM table is really big or is a view, then this might not perform as well as one would like. If performance is an issue, use a temporary table instead of a CTE. (SQL Server tends not to materialize CTEs so it is likely to run the code twice.)

Get monthly report in sql

I got in my data base colums logs, data, type
How to get logs from year from now with month distinction
f.ex:
row
logs = 'error...'
data = 2012-11-05 11:24:08
type = 1
....
And I want get them in that view
month logs-count type
January 100 1
January 100 2
February 160 1
February 120 2
....
For mysql:
select monthname(data) as month, count(*) as logs-count, type
from table
group by month, type
You need to group by both date and type to get multiple rows per month.
try this one:
select datename(month, data) as month count(logs)as logscount, type from table
try this,If these columns are in same table
select monthname(data) as month,count(logs)as logs-count,type from table
group by month