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

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

Related

BigQuery SQL to change start date and end date into groups of months

I work with a hotel client where they have a BigQuery database which has hotel booking data. I've shared the relevant columns in the image below which list the names of each hotel, the arrival date of the guest, the departure date, and the revenue generated from the each booking:
My problem statement is that I have to showcase how many rooms have been booked, and how much revenue has been made for each hotel every month where my final grid would look similar to this:
The important points to remember are:
the depart_dt - arrival_dt are the number of nights that the guest is staying
the Rez_rate_total / (depart_dt - arrival_dt) is the revenue made per night
My problem here is trying to figure out how to change the start date and end date columns into groups of months. The challenge comes when a guest arrives in one month and leaves in the next month. For example, Row 5 in the original data has the guest coming in on 18th July and leaving on 1st Aug - so 13 days of his stay and 13 days of revenue has to be included in July and 1 day has to be included in August.
I haven't used SQL in a while so this is as far as I got:
WITH
temp_table AS (
SELECT
hotel_long_nm,
arrival_dt,
depart_dt,
DATE_DIFF(depart_dt, arrival_dt, day) AS room_nights,
rez_rate_total
FROM
`DATABASE.analytics.bookings` )
SELECT
*
FROM
temp_table
Any help would be greatly appreciated!
Consider the following approach:
with bookings as (
select hotel_long_nm, date(arrival_dt) as arrival_dt, date(depart_dt) as depart_dt, rez_rate_total from project.dataset.bookings
),
tmp as (
-- expose the dates in the reservation (excluding last day of reservation)
select *, generate_date_array(arrival_dt,date_sub(depart_dt, interval 1 day)) as stay_dates from bookings
),
calc as (
-- unnest and calculate the daily rate
select
hotel_long_nm,
stay_dt,
1 as stay_nights,
rez_rate_total/array_length(stay_dates) as rez_rate_daily
from tmp
left join unnest(stay_dates) as stay_dt
),
agg as (
-- aggregate to the year-month level
select
date_trunc(stay_dt, month) as year_month,
hotel_long_nm,
sum(stay_nights) as room_nights,
round(sum(rez_rate_daily),2) as rez_rate_total
from calc
group by 1,2
)
select * from agg
order by hotel_long_nm, year_month
You can consider this approach, following this logic.
Validate if both dates are in the same month
If are not in the same month, i get the final date of the month of
arrival date and subtract both dates
I get the first date of the month of the depart date and subtract
and subtract both dates
In this code you can see an example:
SELECT
/*arrival date*/
CURRENT_DATE() AS the_arival,
/*depart_dt*/
DATE_ADD(CURRENT_DATE(), INTERVAL 30 DAY) AS the_depart,
/*total of night between arrival date and depart date*/
DATE_DIFF(DATE_ADD(CURRENT_DATE(), INTERVAL 30 DAY) , CURRENT_DATE(), DAY) AS total_room_nights,
/* validate if the dates are in the same month or different month if equal 0 same month if >0 another month */
DATE_DIFF(DATE_ADD(CURRENT_DATE(), INTERVAL 30 DAY) , CURRENT_DATE(), MONTH) AS Same_Month,/*1 no and 0 yes/
/*in this case are in different month*/
/*I get the final date of the arrival month and subtract with the arrival date*/
DATE_DIFF(DATE_SUB(DATE_TRUNC(DATE_ADD(DATE_ADD(CURRENT_DATE(), INTERVAL 30 DAY), INTERVAL 1 MONTH), MONTH), INTERVAL 1 DAY),DATE_ADD(CURRENT_DATE(), INTERVAL 30 DAY), DAY) as total_room_nights_first_mont,
/*I get the initial date of the depart month and subtract with the depart date i add +1 because is the night between last day of the mont and first day of the next month*/
DATE_DIFF(DATE_ADD(CURRENT_DATE(), INTERVAL 30 DAY),DATE_TRUNC(DATE_ADD(CURRENT_DATE(), INTERVAL 30 DAY), MONTH), DAY)+1 as total_room_nights_second_month
You can see more information about the date function.Click Here.

Bigquery YTD WORKDAYS calculation

I use the below calc to calculate workdays in a month.
i.e for calendar date = 28-05-2021 , i get 23 days ( monday to friday)
(select count(*) from unnest(generate_date_array(date_trunc(CALENDAR_DATE, month), last_day(CALENDAR_DATE, month ))) day
where not extract(dayofweek from day) in (1, 7)) as Workdays_Month,
I would like to calculate YTD Workdays based on the Calendar Date
i.e
if calendar date = 28-05-2021 then YTD workdays would be sum of workdays in months ( Jul 20 to May 21) financial year.
Assuming your financial year starts in July - you can use below
select count(*)
from unnest([struct(extract(year from current_date) as year, extract(month from current_date) as month)]),
unnest(generate_date_array(if(month < 7, date(year - 1, 7, 1), date(year, 7, 1)), last_day(date(year, month, 1)))) day
where not extract(dayofweek from day) in (1, 7)

SQL query to find dates of last year equivalent to today's date

I am writing a SQL query to find business working dates of last year equivalent to today's date.
In this query it should fetch :-
For e.g. if today is 5th January, 2021 and it is the second day of second week of the year. So I need to find the exact equivalent date of the second day of second week of the previous year. So it would be 7th January, 2020.
And with this, I need the business working dates of that week of 7th January 2020 (i.e. excluding Saturday & Sunday)
Which will come up as 2020-Jan-06 to 2020-Jan-10 according to the example.
So I will need the report between 6th Jan - 10th Jan, 2020.
I am trying to use this code to find date of last year equivalent to today's date (5th Jan, 2021 viz. second day of second week)
select Convert(date, (DATEADD(year, -1, getdate()+2))) ;
2021-01-05 is the 2nd day of the first week of 2021 according to ISO standards.
If you want the 2nd day of the first week of 2021, then it is either today's date minus 52 weeks or 53 weeks. Based on the Wikipedia page for ISO dates:
[53 week years are those] years in which 1 January or 31 December are Thursdays
So, we want that for the previous year. Hence, I think the following should work:
select dateadd(week,
(case when 'Thursday' in (datename(weekday, datefromparts(year(getdate()) - 1, 1, 1)),
datename(weekday, datefromparts(year(getdate()) - 1, 12, 31))
)
then -53 else -52
end),
convert(date, getdate())
)
Note that this returns 2019-12-31, which is the correct value based on ISO standards.
I have use multiple CTE to show you the step by step calculation. It should be pretty easy to follow.
Basically it find the week_no and day_no_of_week for 2021-01-05 and then use that to find the same date for 2020
declare #input_date date = '2021-01-05',
#year_offset int = -1; -- previous year
with
cte1 as
(
select input_date = #input_date,
week_no = DATEPART(WEEK, #input_date),
first_day_of_week = DATEADD(WEEK, DATEDIFF(WEEK, 0, #input_date), 0)
),
cte2 as
(
select *,
day_no_of_week = DATEDIFF(DAY, first_day_of_week, #input_date) + 1
from cte1
),
cte3 as
(
select *,
first_day_of_the_prev_year = DATEADD(YEAR, DATEDIFF(YEAR, 0, #input_date) + #year_offset, 0)
from cte2
),
cte4 as
(
select *,
first_day_of_week_prev_year = DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(WEEK, week_no - 1, first_day_of_the_prev_year)), 0)
from cte3
)
select *,
DATEADD(DAY, day_no_of_week - 1, first_day_of_week_prev_year) as the_required_date
from cte4

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;

Return number of weeks in Postgres

This is what I am using right now and it returns the number of days between beginDate and endDate
date( ' $(#endDate)') - date('$(#beginDate)') as weekNumber
How can I get it to return the number of weeks between the two?
The simplest way would be to divide the number of days by seven, although that would not take into account the starting day of the week.
You could use this instead:
extract (week from date '$(#endDate)') -extract (week from date '$(#startDate)')
which would use iso8601 week numbers. But beware of spanning years!
Version 1:
/*
Design:
Week begins on day of start date
Options:
1) Count only whole weeks
2) Count partial weeks on the right side (end date side)
*/
select
sum(case when ('2013-02-08'::date - ind::date) >= 7 then 1 else 0 end) as whole_weeks,
count(*) as partial_right
from
generate_series('2013-01-01'::date /*dow=2*/,'2013-02-05'::date /*dow=2*/,'7 days') ind
Version 2:
/*
Design:
Week begins on specific day of week (5 chosen in this example)
Options:
1) Count only whole weeks
2) Count partial weeks on the right side (end date side)
3) Count partial weeks on the left side (start date side)
4) Count partial weeks on both sides
*/
select
sum(case when days = 7 then 1 else 0 end) as whole_weeks,
sum(case when days = 7 or max_ind = week_start then 1 else 0 end) as partial_right,
sum(case when days = 7 or week_start < min_ind then 1 else 0 end) as partial_left,
count(*) as partial_both_sides
from
(
select
ind - (case when dow < bow then dow + 7 - bow else dow - bow end)::int as week_start,
count(*) as days,
min(ind) as min_ind,
max(ind) as max_ind
from
(select
ind::date as ind,
extract(isodow from ind) as dow,
5::int as bow
from
generate_series('2013-01-01'::date /*dow=2*/,'2013-02-08'::date /*dow=5*/,'1 day') ind
) inp
group by
week_start
) t