mdx select data from period - reporting-services

For report based on OLAP I need to exctract data for period of current year and parallel of previous year.
If today is 2016-05-26,
Then I need these period of dates: 2016-01-01 - 2016-05-26 and 2015-01-01 - 2015-05-26
SELECT NON EMPTY
{ [Measures].[Sell In Return] } ON COLUMNS,
NON EMPTY { (
[Date].[Date].[Date].ALLMEMBERS *
[Product].[Prod Name].[Prod Name].ALLMEMBERS *
[Product].[Product].[Product].ALLMEMBERS *
[Date].[Month Calendar].[Month Calendar].ALLMEMBERS
) }
DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME
ON ROWS
FROM
[Table]

Here is a start for finding Today in the cube. I've moved Measures to the slicer and Today onto columns:
WITH
MEMBER [Measures].[Key for Today] AS
Format
(
Now()
,'yyyyMMdd'
)
MEMBER [Measures].[Today string] AS
'[Date].[Month Calendar].[Calendar Day].&[' + [Measures].[Key for Today]
+ ']'
SET [Today] AS
StrToMember
(
[Measures].[Today string]
,constrained
)
SET [TodayLstYr] AS
ParallelPeriod
(
[Date].[Date - Calendar Month].[Calendar Year]
,1
,[Today]
)
SET [ThisYear] AS
{
Ancestor
(
[Today]
,[Date].[Month Calendar].[Calendar Day]
).Item(0)
:
[Today]
}
MEMBER [Date].[Date - Calendar Month].[All].[ThisYear] AS
Aggregate([ThisYear])
SET [LastYear] AS
{
Ancestor
(
[TodayLstYr]
,[Date].[Month Calendar].[Calendar Day]
).Item(0)
:
[TodayLstYr]
}
MEMBER [Date].[Date - Calendar Month].[All].[LastYear] AS
Aggregate([LastYear])
SELECT
NON EMPTY
{
[Today]
,[Date].[Date - Calendar Month].[All].[ThisYear]
,[Date].[Date - Calendar Month].[All].[LastYear]
} ON COLUMNS
,NON EMPTY
[Product].[Prod Name].[Prod Name].ALLMEMBERS
*
[Product].[Product].[Product].ALLMEMBERS ON ROWS
FROM [Table]
WHERE
[Measures].[Sell In Return];

Here's one more approach of getting at it:
with set Today as //today's date
filter([Date].[Month Calendar].[Date].members,
Format([Date].[Month Calendar].currentmember.member_name, "Short Date") =
format(now(), "Short Date"))
set MonthBegToToday as //range of dates from current month's beginning till today
{today.item(0).firstsibling : today.item(0)}
set LastYearMonthBegToToday as //range of dates from current month's beginning till today (using parallelperiod function to get the "same date last year")
PARALLELPERIOD([Date].[Month Calendar].[Year], 1,
today.item(0).firstsibling)
:
PARALLELPERIOD([Date].[Month Calendar].[Year], 1,
today.item(0))
member Measures.SalesMonthBegToToday as //total sales by using SUM()
sum(MonthBegToToday, [Measures].[Sell In Return])
member Measures.SalesLastYearMonthBegToToday as
sum(LastYearMonthBegToToday, [Measures].[Sell In Return])

Thanks for help
I define 2 periods with member and add range onto columns
WITH
MEMBER [Measures].[Key for Today] AS Format (Now() ,'yyyyMMdd' )
member [measures].[CurrentYear] as Format (Now() ,'yyyy')
MEMBER [Measures].[TodayPrevYear] AS Format (DateAdd("YYYY",-1,Now()) ,'yyyyMMdd')
Member [measures].[PrevYear] as Format ( dateadd("YYYY",-1,Now()) ,'yyyy')
SELECT
NON EMPTY
{
StrToMember ( '[Date].[Date Key].[Date Key].&[' +[measures].[PrevYear]+'0101'+ ']',constrained )
:StrToMember ( '[Date].[Date Key].[Date Key].&[' + [Measures].[TodayPrevYear] + ']',constrained )
,
StrToMember ( '[Date].[Date Key].[Date Key].&[' +[measures].[CurrentYear]+'0101'+ ']',constrained )
:StrToMember ( '[Date].[Date Key].[Date Key].&[' + [Measures].[Key for Today] + ']',constrained )
} ON COLUMNS
,NON EMPTY
[Product].[Product].[Product].ALLMEMBERS
* [Product].[SKUs].[SKU].ALLMEMBERS
ON ROWS
FROM [Table]
WHERE
[Measures].[Sell In Return];

Related

Calculate date of holiday using a factor table to add/subtract days from a specific date

DB-Fiddle
CREATE TABLE holidays (
id int primary key,
name VARCHAR(255),
calc_type VARCHAR(255),
calc_factor VARCHAR(255)
);
INSERT INTO holidays
(id, name, calc_type, calc_factor
)
VALUES
("1", "Holdiay_01", "fixed", "0"),
("2", "Holdiay_02", "fixed", "0"),
("3", "Holdiay_03", "fixed", "0"),
("4", "Holdiay_04", "moveable", "10"),
("5", "Holdiay_05", "moveable", "-5");
The table above I want to use to calculate the date of a holiday in an SQL query.
The holidays are divided in two different calculation types:
fixed = same date every year
(YYYY-03-01, YYYY-05-12, YYYY-08-09)
moveable = date is calculated by adding/subtracting a pre-defined amount of days (calc_factor) from a fixed date:
(YYYY-11-12) + 10, (YYYY-11-12) - 5
In the end the result should look like this:
id name date
1 Holiday_01 2019-03-01
2 Holiday_02 2019-05-12
3 Holiday_03 2019-08-09
4 Holiday_04 2019-11-22
5 Holiday_05 2019-11-07
I tried to go with something like this but could not make it work so far:
SELECT
id,
name,
CASE (
WHEN name = "Holdiay_01" THEN DATE_ADD(YEAR(CURDATE()) & MONTH(3) & DAY(1), INTERVAL calc_factor)
WHEN name = "Holdiay_02" THEN DATE_ADD(YEAR(CURDATE()) & MONTH(5) & DAY(12), INTERVAL calc_factor)
WHEN name = "Holdiay_03" THEN DATE_ADD(YEAR(CURDATE()) & MONTH(9) & DAY(8), INTERVAL calc_factor)
WHEN name = "Holdiay_04" THEN DATE_ADD(YEAR(CURDATE()) & MONTH(11) & DAY(12), INTERVAL calc_factor)
WHEN name = "Holdiay_05" THEN DATE_ADD(YEAR(CURDATE()) & MONTH(11) & DAY(12), INTERVAL calc_factor)
ELSE NULL END ) AS date
FROM holidays;
How do I have to modify my query to get the expected result?
MySQL has the CONCAT() function, which allows you to concatenate two or more strings. The function actually allows for one or more arguments, but its main use is to concatenate two or more strings.
Following is your answer:
SELECT
id,
name,
CASE
WHEN name = 'Holdiay_01' THEN DATE_ADD((CONCAT(YEAR(CURDATE()),'-03-01')),
INTERVAL (calc_factor) DAY)
WHEN name = 'Holdiay_02' THEN DATE_ADD((CONCAT(YEAR(CURDATE()),'-05-12')),
INTERVAL (calc_factor) DAY)
WHEN name = 'Holdiay_03' THEN DATE_ADD((CONCAT(YEAR(CURDATE()),'-08-09')),
INTERVAL (calc_factor) DAY)
WHEN name = 'Holdiay_04' THEN DATE_ADD((CONCAT(YEAR(CURDATE()),'-11-12')),
INTERVAL (calc_factor) DAY)
WHEN name = 'Holdiay_05' THEN DATE_ADD((CONCAT(YEAR(CURDATE()),'-11-12')),
INTERVAL (calc_factor) DAY)
ELSE NULL END AS date
FROM holidays;
Also check in DB Fiddle:
DB-Fiddle
You have a rather perverse data model -- a row regarding a holiday but not the date. That said, the following does what you want after fixing the holiday names:
SELECT id, name,
(CASE WHEN name = 'Holiday_01' THEN DATE_ADD(CONCAT(YEAR(CURDATE()), '-03-01'), INTERVAL calc_factor DAY)
WHEN name = 'Holiday_02' THEN DATE_ADD(CONCAT(YEAR(CURDATE()), '-05-12'), INTERVAL calc_factor DAY)
WHEN name = 'Holiday_03' THEN DATE_ADD(CONCAT(YEAR(CURDATE()), '-09-08'), INTERVAL calc_factor DAY)
WHEN name = 'Holiday_04' THEN DATE_ADD(CONCAT(YEAR(CURDATE()), '-11-12'), INTERVAL calc_factor DAY)
WHEN name = 'Holiday_05' THEN DATE_ADD(CONCAT(YEAR(CURDATE()), '-11-12'), INTERVAL calc_factor DAY)
END) as date
FROM holidays;
Here is the corresponding db<>fiddle.
Some issues with your code apart from the misspelt names:
& is a bitwise AND operator. You appear to want to construct a date, so CONCAT() is appropriate.
INTERVAL requires a time unit.
MONTH() and DAY() are functions that extract those components from a date. An argument such as "3" is converted to a date -- and because it is not a date, the returned value is NULL.
As a matter of simplification, ELSE NULL is superfluous, because CASE expressions return NULL if no conditions match.

How to get previous month data in MDX

I am trying to get previous month data for my SSRS report.But i am not getting any result.Could you please give any help.Below is my query.
SELECT
NON EMPTY
{[Measures].[Trade Net Amount]} ON COLUMNS
,NON EMPTY
{
[Fund].[Fund Name].[Fund Name].ALLMEMBERS*
[Transaction Type].[Transaction Description].[Transaction Description].ALLMEMBERS*
[Calendar Day].[Year].[Year].ALLMEMBERS*
[Calendar Day].[Month].[Month].ALLMEMBERS
}
DIMENSION PROPERTIES
MEMBER_CAPTION
,MEMBER_UNIQUE_NAME
ON ROWS
FROM
(
--FROM ( SELECT ( STRTOSET(#CalendarDayMonth, CONSTRAINED) ) ON COLUMNS
--FROM ( SELECT ( STRTOSET(#CalendarDayYear, CONSTRAINED) ) ON COLUMNS
SELECT
StrToMember
(
"[Calendar Day].[Calender Hierarchy].[Month].[" + Format(Now(),"yyyy")
+
Format
(
Now()
,"MMM"
)
+ "].PrevMember"
) ON COLUMNS
FROM [Escher_Hybrid]
);

Date difference in mysql based on 360 days

I working on a financial project where i need to calculate the difference of arrear days. If I use the method datediff() of mysql then it returns the result based on 365 days. I need the result based on 360 days. if use the following sql query
select datediff('20140908','20130908') from dual;
mysql returns the date difference 365. This is the actual date difference but in accounting/Financial calculation the difference is exactly one year (360 days). This is what I want. The result should be 360 instead 365.
Currently I want to use US standard.
to get the same result like Excel, I found the following code to use in MySQL:
select case
when (day(Startdate)>=30 or Startdate=last_day(Startdate) then
case
when(day(Enddate)>=30) then
30*(12*(year(Enddate)-year(Startdate))+month(Enddate)-month(Startdate))
else
30*(12*(year(Enddate)-year(Startdate))+month(Enddate)-month(Startdate))+days(Enddate)-30
end
else
30*(12*(year(Enddate)-year(Startdate))+month(Enddate)-month(Startdate))+days(Enddate)-days(Startdate)
end
Use
TO_DAYS(date2) - To_DAYS(date1)
It returns the number of days between date1 and date2. Then you can do with the result what you need.
sdate = from date
edate = to date
this calculate the days between the 2 date, taking into account that a month is 30 days, 1 year is 360 days, and checking if the date are at the end of the month, so e.g. from 1.1.2019 to 28.2.2019 = 60 days etc.
to be 1 month or 1 year, the edate should be a day before, so 1.1 - 31.1 = 30 days, 1.1 - 1.2 = 31 days
SELECT GREATEST(
0,
(YEAR(DATE_ADD(edate, INTERVAL 1 DAY)) - YEAR(sdate)) * 360 +
(MONTH(DATE_ADD(edate, INTERVAL 1 DAY)) - MONTH(sdate)) * 30 +
(
IF(DAYOFMONTH(DATE_ADD(edate, INTERVAL 1 DAY)) = DAYOFMONTH(LAST_DAY(DATE_ADD(edate, INTERVAL 1 DAY))), 30, DAYOFMONTH(DATE_ADD(edate, INTERVAL 1 DAY))) -
IF(DAYOFMONTH(sdate) = DAYOFMONTH(LAST_DAY(sdate)), 30, DAYOFMONTH(sdate))
)
Pretty late here, but posting my solution for future reference
CREATE FUNCTION `DAYS360_UDF`(sdate DATE, edate DATE)
RETURNS INTEGER
DETERMINISTIC
CONTAINS SQL
BEGIN
DECLARE sdate_360 INTEGER;
DECLARE edate_360 INTEGER;
SET sdate_360 = ( YEAR(sdate) * 360 ) + ( (MONTH(sdate)-1)*30 ) + DAY(sdate);
SET edate_360 = ( YEAR(edate) * 360 ) + ( (MONTH(edate)-1)*30 ) + DAY(edate);
RETURN edate_360 - sdate_360;
END
Usage -
select DAYS360_UDF('20130908', '20140908')

SQL Function for Financial Day of the year

How to get the financial day of the year i.e., if i pass 2nd of april to the function, it should return 2. The financial year starts on 1st of April for every year.
Fiscal calendars are specific to the organization and, although rare, can change. The simplest solution is to create a table that outlines the Fiscal calendar. So, you can mimic this using a CTE but it is better to store it as a table.
With FiscalCalendarStarts As
(
Select 1 As FiscalPeriod
, Cast('20120401' As DateTime) As StartDate
Union All
Select FiscalPeriod + 1
, Case
When Month(StartDate) = 12 Then DateAdd(m, Month(StartDate) - 12 + 1, StartDate)
Else DateAdd(m, 1, StartDate)
End
From FiscalCalendarStarts
Where FiscalPeriod < 12
)
, FiscalCalendar As
(
Select FiscalPeriod
, StartDate
, DateAdd(d, -1, DateAdd(m, 1, StartDate)) As EndDate
From FiscalCalendarStarts
)
Select *
From FiscalCalendar
Where #SomeDate Between StartDate And EndDate
Edit
To get the day count (which I admit I did not provide in the above solution), the trick is to determine the actual fiscal year start date based on the input date. To do that, you could do something like the following, which per your request, I've put into a function
Create Function dbo.FiscalDay ( #Input datetime )
Returns int
As
Begin
Declare #StartDayMonth char(4);
Set #StartDayMonth = '0401';
Return (
Select DateDiff(d, FYStartDate, #Input) + 1
From (
Select DateAdd(yyyy
, Case
When DatePart(dy, #Input) >= DatePart(dy, StartDate) Then 0
Else -1
End
, StartDate) As FYStartDate
From (
Select Cast( Cast(Year(#Input) As char(4))
+ #StartDayMonth As datetime ) As StartDate
) As S1
) As S
)
End
I start with the stub of 0401 which represents the month and day of the start of the fiscal year. To that I prepend the passed date's year so I get something like 20120401 if a date in 2012 was passed. If #Input is later than 1-Apr, then we're in the new fiscal year for the year of the #Input. If #Input is earlier than 1-Apr, then we're in the fiscal year that start on 1-Apr of the previous year. Now that we have the fiscal start date, we can simply find the numbers of days between them and add 1 (otherwise 1-Apr will be seen as day 0 instead of day 1). Note that passing 31-Mar-2012 returns 366 instead of 365 since 2012 was a leap year.
#Olivarsham, The financial year in not common for every country. Some where it is Apr-mar, some where it is Jan-Dec. So It it is your special application requirement then you need to write for your self. I think no standard query for that.
Kindly try this function. This will return your the day number of the fiscal year.
CREATE FUNCTION [dbo].[FiscalDay] (#CurrentDATE datetime)
RETURNS int
AS
BEGIN
DECLARE #FiscalDay int;
DECLARE #YearStartDate DateTime;
Set #YearStartDate=Cast('20120401' As DateTime)
set #FiscalDay = DATEDIFF(DAY,#YearStartDate , #CurrentDATE)
RETURN(#FiscalDay);
END;
GO

SQL Server. Stored procedure to get the biweekly periods

I'm currently trying to write a stored procedure that can compute the biweekly periods when a date is passed in as a parameter.
The business logic: the first Monday of the year is first day of the biweekly period.
For example in 2010:
period period_start period_end
1 2010-01-04 2010-01-17
2 2010-01-18 2010-01-31
3 2010-02-01 2010-02-14
....
26 2010-12-20 2011-01-02
Passing today's date of 2010-12-31 will return 26, 2010-12-20 and 2011-01-02. How to achieve this?
#Lamak did the hard part, figuring out the first Monday in the year (upvoted). I revised his routine a bit to take a datetime value, like so:
-- Return first Monday for the year being passed in
CREATE FUNCTION dbo.FirstMonday (#TargetDay datetime)
RETURNS DATE
AS
BEGIN
DECLARE #Return DATE
-- Set to first of its year
SET #TargetDay = dateadd(dd, -datepart(dayofyear, #TargetDay) + 1, #TargetDay)
;WITH Dates AS
(
SELECT #TargetDay AS DateVal
UNION ALL
SELECT DATEADD(d, 1, DateVal) AS DateVal
FROM Dates
WHERE DATEADD(d, 1, DateVal) < DATEADD(m, 1, #TargetDay)
)
SELECT #Return = MIN(DateVal)
FROM Dates
WHERE DATENAME(WEEKDAY,DateVal) = 'Monday'
RETURN #Return
END
GO
-- Test it
print dbo.FirstMonday(getdate())
print dbo.FirstMonday('Jan 1, 2010')
From there, it's just some datetime arithmatic:
DECLARE
#FirstMonday datetime
,#TargetDay datetime
,#BiWeek int
SET #TargetDay = getdate()
--SET #TargetDay = 'Jan 17, 2010'
-- Get the first Monday
SET #FirstMonday = dbo.FirstMonday(#TargetDay)
-- Calculate the bi-weekly period
SET #BiWeek = datediff(dd, #FirstMonday, #TargetDay) / 14
-- Print results
PRINT #BiWeek + 1
PRINT dateadd(dd, #BiWeek * 14, #FirstMonday)
PRINT dateadd(dd, #BiWeek * 14 + 13, #FirstMonday)
-- Or return them as a dataset
SELECT
#BiWeek + 1 Period
,dateadd(dd, #BiWeek * 14, #FirstMonday) PeriodStart
,dateadd(dd, #BiWeek * 14 + 13, #FirstMonday) PeriodEnd
This fails when you pick a day in the year that falls before the first Monday, as it returns the first biweekly period after that date. (Or does it fail? You did not specify what the proper period is for such dates... :)
However, as #HLGEM says, depending on what you are doing you are probably better off building and using some form of biweekly period lookup table, especially if you need proper handling of those early dates.
You can create a function to get the first Monday of a year. Something like this should work:
CREATE FUNCTION dbo.FirstMonday(#Year VARCHAR(4))
RETURNS DATE
AS
BEGIN
DECLARE #Return DATE;
WITH Dates AS
(
SELECT CONVERT(DATE,#Year+'0101') AS DateVal
UNION ALL
SELECT DATEADD(d, 1, DateVal) AS DateVal
FROM Dates
WHERE DATEADD(d, 1, DateVal) < DATEADD(m, 1, #Year+'0101')
)
SELECT #Return = MIN(DateVal)
FROM Dates
WHERE DATENAME(WEEKDAY,DateVal) = 'Monday'
RETURN #Return
END