MDX SSAS 2008 Last year calculation - Leap year issue - sql-server

I have calculation which calculates the value from previous year, realized in following way:
([Measures].[SalesAmount LY], Leaves([Time])) =
(
PARALLELPERIOD
(
[Time].[Year - Month - Day].[Year],
1,
[Time].[Year - Month - Day].currentmember
),
[MEASURES].[SalesAmount]
)
I am doing it this way, because using only PARALLELPERIOD results in incorrect total calculations when selecting only some months for example. And it works just fine.
However, now I am facing following issue with leap year:
Month SalesAmount SalesAmount LY
------------- ------------ ---------------
January 2012 1000
February 2012 1100 --Leap year - 29.February
January 2013 1200 1000
February 2013 1300 1050
The missing value (1100 - 1050 = 50 in this case) is exactly equal to the value from 29.2.2012.
Does anyone have an idea how to solve this issue? How to get leap year working correctly, while still maintaining correct totals behavior? Any help would be greately appreciated.

This can help?
PARALLELPERIOD
(
[Time].[Year - Month - Day].[Year],
1,
ISLEAF([Time].[Year - Month - Day].currentmember),
Ancestor([[Time].[Year - Month - Day].currentmember, [Time].[Year - Month - Day].[Month]),
[Time].[Year - Month - Day].currentmember)
),
[MEASURES].[SalesAmount]
if the current member is a Day, it will refer to his month parent, so it doesn't matter if the month has 28 or 29 days.

Related

How to consider only last 7 quarter data on a rolling basis when I have data in "2021 - Q 4" format in SQL server

I need to consider only last 7 quarter data on a rolling basis when I have data in "2021 - Q 4" format
I am not able to do this as we do not have any other date in the table ,please suggest or help me with this,
shipped_planned_fiscal_quarter
2021 - Q 4
2021 - Q 2
2022 - Q 4
2021 - Q 2
2022 - Q 3
2021 - Q 2
Thanks in advance
a solution or a suggestion for the above problem

SSRS. How to group in a group?

I have SSRS report like below with Boolean parameter to show 12h view or 24h view. To fit report into single screen the 24h report need to group by every 2hr.
07:00 08:00 09:00 10:00 11:00 12:00 13:00 14:00 ...
Line 1 25 30 24 26 25 25 30 30 ...
08:00 10:00 12:00 14:00 ...
Line 1 55 50 50 60 ...
The query for the dataset is:
SELECT LineID
,Hour
,HourValue
,Target
FROM vwData
ORDER BY LineID, CASE WHEN [Hour] > 6 THEN - 1 ELSE [Hour] END
How can I achieve this?
This declares your bit variable (which should be true when they want the 24 hour view - false when 12 hour)
DECLARE #24Hour bit = 0
SELECT CASE WHEN #24Hour = 0
THEN Hour
ELSE Hour + (Hour % 2)
END AS [HourGroup]
,SUM(Target) AS [TargetTotal]
FROM vwData
GROUP BY CASE WHEN #24Hour = 0
THEN Hour
ELSE Hour + (Hour % 2)
END
If they want the 24 hour view, we make hour = hour + hour % 2. (7 = 8, 8=8, 9=10, etc., etc.). If you had a more complex query, I would suggest reading up on cross apply, but this is so simple I think this will suffice. The grouping by makes sure to aggregate the REAL 7 and REAL 8 hour records (which will both be returned as "8", if using the 24 hour view). If you don't group your results, you will get two 8 oclock records - one with the REAL 7 hour total and one with the REAL 8 hour total.
EDIT:
Since you didn't include the schema of your DB, I'm guessing that 'Target' is the value being summated, but it could just as easily be 'HourValue'. Furthermore, I have no idea why you would need LineID, so I omitted it from my answer. But you can easily modify that if it's inaccurate. In the future, you should provide some sample data and your database schema so that others aren't forced to make assumptions or guess.
You could add a calculated field with a value given by something like this: `Fields!Hour.Value + Fields!Hour.Value Mod 2' and then group on that field, using a parameter to choose the Group By field in the report (Your new field or the actual hour value).

Get week number of month SQL Server

I am trying to find the week number of a particular month given a date, so I want to know which week is that for given month
Example if I enter
2016 Feb 2 ---> Week 1
2016 Feb 9 ---> Week 2
2016 June 2 ---> week 1
2016 Jan 25 ---> week 5
Can I achieve this in a T-SQL query?
I have seen the following option
DATEPART(wk, BookingTimeStamp)
But that gives the week number of the year, not the month
The idea is to build result per week for a given month
The first result using "SQL Server and Weeks in Month" returned this article. It shows two ways using DATEPART along with other date parsing functions. Here is one solution:
DECLARE #MyDate DATETIME =GETDATE()
SELECT DATEDIFF(WEEK, DATEADD(MONTH, DATEDIFF(MONTH, 0, #MyDate), 0), #MyDate) +1
I ran into the same problem when I wanted to get not the number of the week in the year, but the number of the week in relation to the month.
In my solution, you can divide every day of date by 7. Then all the days of week 1 will be between 0 and 1. All days of week 2 are between 1 and 2, and so on.
This is a simple example of a practice query where you can use the case construct to find the number of the week.
Solution 1 (a bit confusing)
SELECT
case
when CAST(strftime('%d', date) as real) / 7 BETWEEN 0 AND 1 then 'week_1'
when CAST(strftime('%d', date) as real) / 7 BETWEEN 1 AND 2 then 'week_2'
when CAST(strftime('%d', date) as real) / 7 BETWEEN 2 AND 3 then 'week_3'
when CAST(strftime('%d', date) as real) / 7 BETWEEN 3 AND 4 then 'week_4'
when CAST(strftime('%d', date) as real) / 7 BETWEEN 4 AND 5 then 'a_bit_of_week_5'
end as week
FROM cost
WHERE strftime('%Y', date) = '2022';
Solution 2 (simple)
SELECT
case
when CAST(strftime('%d', date) as integer) BETWEEN 1 AND 7 then 'week_1'
when CAST(strftime('%d', date) as integer) BETWEEN 7 AND 14 then 'week_2'
when CAST(strftime('%d', date) as integer) BETWEEN 14 AND 21 then 'week_3'
when CAST(strftime('%d', date) as integer) BETWEEN 21 AND 28 then 'week_4'
when CAST(strftime('%d', date) as integer) BETWEEN 28 AND 31 then 'a_bit_of_week_5'
end as week
FROM cost
WHERE strftime('%Y', date) = '2022';
Deduction of solution 1
If you're just looking for a solution to an issue, then you don't need to read any further. I just want to tell you how I arrived at this solution and why you can trust it.
This solution can be visualized using the Python programming language.
from matplotlib import pyplot as plt
days = [x for x in range(1, 32)]
days_on_seven = [x / 7 for x in range(1, 32)] # Divide each day by 7
print(days_on_seven)
## Result is below
[0.14285714285714285,
0.2857142857142857,
0.42857142857142855,
0.5714285714285714,
0.7142857142857143,
0.8571428571428571,
1.0,
1.1428571428571428,
1.2857142857142858,
1.4285714285714286,
1.5714285714285714,
1.7142857142857142,
1.8571428571428572,
2.0,
2.142857142857143,
2.2857142857142856,
2.4285714285714284,
2.5714285714285716,
2.7142857142857144,
2.857142857142857,
3.0,
3.142857142857143,
3.2857142857142856,
3.4285714285714284,
3.5714285714285716,
...
3.857142857142857,
4.0,
4.142857142857143,
4.285714285714286,
4.428571428571429]
Visualisation
As you can see, we get an array of increasing numbers. Let's graph the resulting numbers for each day of the month.
from matplotlib import pyplot as plt
import seaborn as sns
sns.lineplot(x=days, y=days_on_seven)
plt.xlabel("Number of day in month")
plt.ylabel("Result of division by 7")
plt.title("day / 7 plot")
The graph below by link
https://i.stack.imgur.com/SIVfT.png
The graph is very crude, but you can see, as noted earlier, that all the days of week 1 will be between 0 and 1. All days of week 2 are between 1 and 2, and so on.
I hope my decision was helpful and interesting to you.

How do I get Google Sheets to give me the average time of day in a series of dates?

I need to find the average time of day over the course of several days.
Column A
Row 1 - 07/13/14 02:45 PM
Row 2 - 07/12/14 10:45 PM
Row 3 - 07/12/14 04:07 PM
Row 4 - 07/11/14 12:30 AM
Row 5 - 07/11/14 06:15 PM
Row 6 - 07/10/14 05:30 PM
Row 7 - 07/10/14 01:00 AM
Row 8 - 07/10/14 04:00 AM
=AVERAGE(A1:A8) returns 7/11/14 2:51 PM. The average of these times should be 8:51 PM. AVERAGE seems to be incorporating the date in the average and I can't have that.
=AVERAGE(TIMEVALUE((A1:A8)) returns #VALUE.
The only way I can get 8:51 PM is by first converting each cell in Column A to either 1/1/14 or 1/2/14 so the dates remain in the 24 hour range by using
=IF(AND(TIMEVALUE(A1) > TIMEVALUE("12:00 AM"), TIMEVALUE(A1) < TIMEVALUE("5:00 AM")),DATEVALUE("1/2/14") + TIMEVALUE(A1), DATEVALUE("1/1/14") + TIMEVALUE(A1))
and then taking the average of the converted cells, which are in Column B
Column B
Row 1 - 01/01/14 02:45 PM
Row 2 - 01/01/14 10:45 PM
Row 3 - 01/01/14 04:07 PM
Row 4 - 01/02/14 12:30 AM
Row 5 - 01/01/14 06:15 PM
Row 6 - 01/01/14 05:30 PM
Row 7 - 01/02/14 01:00 AM
Row 8 - 01/02/14 04:00 AM
I tried using
=IF(AND(TIMEVALUE(A1:A8) > TIMEVALUE("12:00 AM"), TIMEVALUE(A1:A8) < TIMEVALUE("5:00 AM")),DATEVALUE("1/2/14")+DATEVALUE(A1:A8), datevalue("1/1/14")+TIMEVALUE(A1:A8))
but that also returns #VALUE.
Thanks in advance.
From what I can understand, the "correct average" you are providing is in fact wrong. You said
The average of these times should be 8:51 PM.
While I am finding it to be 11:51:30 AM.
In any case, when extracting timevalues from dates, this formula should do the trick:
=ARRAYFORMULA(AVERAGE(TIMEVALUE(A1:A8)))
You may want to take a look at ARRAYFORMULA API, but here's a description extract:
[ARRAYFORMULA] Enables the display of values returned from an array formula into multiple rows and/or columns and the use of non-array functions with arrays.

How to check if week number is even or odd in ANSI C?

I`ve a small app that returns is week even or not.
time_t now = time(0);
tm *ltm = localtime(&now);
int twin=(ltm->tm_yday/7)%2
But independently from the 1st day of the year so it returns
mon, thu, we, etc
0,1,1,1,1,1,1
in the next week
1,0,0,0,0,0,0
In the next year
mon, thu, we, etc
0,0,1,1,1,1,1
in the next week
1,1,0,0,0,0,0
and so on..
Twin- if number modulo 2 = 0
So I have to add shift to change week number in each sunday or monday. Any suggestions?
You are assuming that first week has exactly 7 days which is incorrect.
For example Jan 1st 2013 was Tuesday, so the first week is only 5 days long.
How about using strftime? Something like:
time_t now = time(0);
tm *ltm = localtime(&now);
char weekNr[3];
strftime(weekNr, sizeof(weekNr), "%W", ltm);
int isOdd = atoi(weeknr) % 2;
What you call twin, in English is usually called even.
About your question, the issue here is that you are not calculating the week number correctly: you are simply dividing by 7, and that's not enough because the start of year and the start of week vary each year.
Moreover, there are several different ways to decide which one is week 1. See for example this code, to get started.
UPDATE: Copying shamelessly from the eglibc source code:
1) The week number of the current year as a decimal number, range 00 to 53, starting with the first Sunday as the first day of week 01 (strftime("%U")):
tp->tm_yday - tp->tm_wday + 7) / 7
2) The week number of the current year as a decimal number, range 00 to 53, starting with the first Monday as the first day of week 01 (strftime("%W")):
(tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7
3) The ISO 8601 week number (see NOTES) of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the new year (strftime("%V")):
Well this is complicated... so you are better with the idea by #MaikuMori of using strftime``, but with"%V", and then parse the result, withatoi()`.

Resources