SQL : Group by with case to set values for both conditions - sql

Pre Condition: [I am using Week as Sunday as first day of week]
I have table '#TT' as below
Column -> D_Date
----------
2020-12-27 |
2020-12-28 |
2020-12-29 |
2020-12-30 |
2020-12-31 |
2021-01-01 |
2021-01-02 |
I want to get week numbers for date And in case of year end with new year start, I want to mark the first week as 0 for new year if it's days contribution is less than 4 days i.e.
As per US week
2020-12-27 from this **53rd** start
2020-12-28
2020-12-29
2020-12-30
2020-12-31
2021-01-01
2021-01-02 and end at here
In above from 27 till 31 are 5 days of 2020 whereas for 1 and 2 of 2021 are 2 days, thus majority days are from 2020 and not 2021.
Now I want to mark week number for 2021 as 0 for dates 1 & 2 and not 1
I am using below query but it is decreasing my minimum year's week number too. How to achieve this? Please help me.
SELECT
DATEPART( week, D_Date ),
CASE
WHEN COUNT( DATEPART( week, D_Date ) ) > 1 THEN MAX( DATEPART(week, D_Date ) - 1 )
ELSE DATEPART( week, D_Date )
END AS [State]
FROM
#tt
GROUP BY
DATEPART( year, D_Date ),
DATEPART( week, D_Date );

Related

Split date range into new records for each month in Snowflake View

Input
ID StartDate EndDate
ABC 12/14/2020 1/14/2021
XYZ 12/13/2020 12/23/2021
DEF 12/3/2020 2/3/2021
Output
ID StartDate EndDate YEAR MONTH No. Of Days
ABC 12/14/2020 12/31/2020 2020 12 18
ABC 1/1/2021 1/14/2021 2021 1 14
XYZ 12/13/2020 12/23/2020 2020 12 11
DEF 12/3/2020 12/31/2020 2020 12 29
DEF 1/1/2021 1/31/2021 2021 1 31
DEF 2/1/2021 2/3/2021 2021 2 3
Input and output samples are given above. Each record has to split by each month across the given date range.
Idea here is to generate data-set with all dates filled in between start-date and end-date.
Used table(split_to_table(repeat(',',TIMESTAMPDIFF(day, sdate,edate)-1),',')), for same.
Once we have all dates, just select the relevant dates.
with data_cte (id,sdate,edate) as (
select * from values
('ABC','2020-12-14'::date,'2021-01-14'::date),
('XYZ','2020-12-13'::date,'2020-12-23'::date),
('DEF','2020-12-03'::date,'2021-02-03'::date)
), cte_2 as
(
select d.*,
case when sdate = edate then edate
else
dateadd(day, index, sdate)
end next_date,
last_day(next_date) ldate,
case when month(sdate) = month(next_date)
AND year(sdate) = year(next_date)
then sdate
else
date_trunc(month,next_date)
end fdate
from data_cte d,
table(split_to_table(repeat(',',TIMESTAMPDIFF(day, sdate,edate)-1),',')) t
)
select
fdate Startdate,
next_date Enddate,
extract(year,Startdate) year,
extract(month,Startdate) month,
datediff(day,Startdate,Enddate)+1 no_of_days
from cte_2
where (next_date = ldate
OR next_date = edate)
OR sdate = edate;
STARTDATE
ENDDATE
YEAR
MONTH
NO_OF_DAYS
2020-12-14
2020-12-31
2020
12
18
2021-01-01
2021-01-14
2021
1
14
2020-12-13
2020-12-23
2020
12
11
2020-12-03
2020-12-31
2020
12
29
2021-01-01
2021-01-31
2021
1
31
2021-02-01
2021-02-03
2021
2
3
After you create out 'OUTPUT' table, you can insert records as:
INSERT INTO OUTPUT_TABLE
SELECT
ID,
StartDate,
EndDate,
YEAR(StartDate) as year,
MONTH(StartDate) as month,
DATEDIFF(day, StartDate, EndDate)
FROM INPUT_TABLE;

How can I create a week group column in my Date Dimension Table based on this specific logic?

I am using SQL Server 2014 and I have a table in my Database called Date Dimension.
It has a column called "Date" which contains daily dates from 01 January 2013 to 31 December 2025 (extract of the column given below):
Date
2022-01-01
2022-01-02
2022-01-03
2022-01-04
2022-01-05
2022-01-06
2022-01-07
2022-01-09
...
2022-01-30
2022-01-31
...
I need to create a new column in the Date Dimension Table called "HR_WeekGroup" based on the following logic:
A WeekGroup will start on a Monday and end on a Sunday. WeekGroups will be calculated for EACH Month separately. That is, if the 1st Day of a Month is a Saturday, the WeekGroup for that week will consist of only 2 days (Saturday and Sunday) and if the last Day of that Month is a Monday, the weekGroup will consist of only 1 Day (Monday).
Here is what I'm after (based on the Month of January 2022):
Date HR_WeekGroup
2022-01-01 Wk 01Jan2022-02Jan2022
2022-01-02 Wk 01Jan2022-02Jan2022
2022-01-03 Wk 03Jan2022-09Jan2022
2022-01-04 Wk 03Jan2022-09Jan2022
2022-01-05 Wk 03Jan2022-09Jan2022
2022-01-06 Wk 03Jan2022-09Jan2022
2022-01-07 Wk 03Jan2022-09Jan2022
2022-01-09 Wk 03Jan2022-09Jan2022
... ...
2022-01-30 Wk 24Jan2022-30Jan2022
2022-01-31 Wk 31Jan2022
...
What would be the T-SQL Code that would allow me to create this column?
I had a look at the following pages but I can't figure out how to apply the examples to my specific problem.
What is the SQL syntax to create a column in my Date Dimension Table that will group the dates into this specific week grouping?
How to Group Data by Week in SQL Server
Set DateFirst 1;
-- The above changes the start of the week to Monday.
-- This makes the week as starting on Monday and ending on Sunday
-- DayOfWeek 1 means Monday
-- DayOfWeek 7 means Sunday
with cte as (
select
Date_Column,
MONTH(Date_Column) as [MONTH], -- Month in the year
DAY(Date_Column) as [DAY], -- Day in the month
DATEPART(week,Date_Column) as [WeekOfTheYear], --Week number of the year
DATEPART(dw,Date_Column) as [DayOfWeek], -- The week day of the week
Min(Date_Column) OVER (Partition by DATEPART(week,Date_Column), MONTH(Date_Column), YEAR(Date_Column) ) as [MinDateWeekGroup],
Max(Date_Column) OVER (Partition by DATEPART(week,Date_Column), MONTH(Date_Column), YEAR(Date_Column) ) as [MaxDateWeekGroup]
from date_dimension
--order by YEAR(Date_Column), MONTH(Date_Column), DAY(Date_Column)
)
select
Date_Column,
case when [MinDateWeekGroup] = [MaxDateWeekGroup]
THEN CONCAT('Wk ',
Right('0'+Convert(varchar(10), Day([MinDateWeekGroup])),2),
Convert(char(3), [MinDateWeekGroup], 0),Convert(char(4),YEAR([MinDateWeekGroup])) )
ELSE
CONCAT('Wk ',
Right('0'+Convert(varchar(10), Day([MinDateWeekGroup])),2),
Convert(char(3), [MinDateWeekGroup], 0),Convert(char(4),YEAR([MinDateWeekGroup])),
'-',
Right('0'+Convert(varchar(10), Day([MaxDateWeekGroup])),2),
Convert(char(3), [MaxDateWeekGroup], 0),Convert(char(4),YEAR([MaxDateWeekGroup]))
)
END as [HR_WeekGroup]
from cte
order by YEAR(Date_Column), MONTH(Date_Column), DAY(Date_Column)

Creating FISCAL_WEEK column in SQL Server Calendar table

We have a requirement. We need to create a fiscal_week column in a SQL Server table.
Table will have data as Normal_date column as fiscal_date and fiscal_year column which will have year part of the date.
Logic for FISCAL_WEEK is like this:
FIRST FISCAL WEEK WILL START FROM 1 JAN OF EVERY YEAR AND IT WILL BE TILL FIRST FRIDAY.
SECOND WEEK STARTS FROM SATURDAY AND IT WILL RUN TILL NEXT FRIDAY.
THIS WILL GO ON TILL THE END OF YEAR (31 JAN)
We will have data something as below table.
Table With Fields as per Requirement
How would I create query for this ? We will have data from 2010 till 2035 years in the table.
Thanks,
Mahesh
You can use an ad-hoc tally table to create the dates and then the window function sum() over() to calculate the Fiscal_Week
Declare #Date1 date = '2020-01-01'
Declare #Date2 date = '2035-12-31'
Select Fiscal_Date = D
,Fiscal_Year = DatePart(YEAR,D)
,Day_Name = DateName(WEEKDAY,D)
,Fiscal_Week = case when DateName(WEEKDAY,#Date1)='Saturday' then 0 else 1 end
+sum(case when DateName(WEEKDAY,D)='Saturday' then 1 else 0 end) over (partition by DatePart(YEAR,D) order by D)
From ( Select Top (DateDiff(DAY,#Date1,#Date2)+1) D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),#Date1)
From master..spt_values n1,master..spt_values n2,master..spt_values n3
) A
Results
Fiscal_Date Fiscal_Year Day_Name Fiscal_Week
2020-01-01 2020 Wednesday 1
2020-01-02 2020 Thursday 1
2020-01-03 2020 Friday 1
2020-01-04 2020 Saturday 2
2020-01-05 2020 Sunday 2
2020-01-06 2020 Monday 2
...
Other way I found would be as below.
SET DATEFIRST 6
GO
SELECT FISCAL_DATE, DATEPART(WEEK,Fiscal_Date) FISCAL_WEEK FROM ERP.CUSTOM_FISCAL_CALENDER

How do I compare a current partial month vs a previous partial month with postgres?

I'm building some basic reports and I want to see if I'm on track to surpass last month's metrics without waiting for the month to end. Basically I want to compare June 1 (start of current month) through June 23 (current_date) against May 1 (start of previous month) through May 23 (current_date - 1 month).
My goal is to show a count of distinct users that did event1 and event2.
Here's what I have so far:
CREATE VIEW events AS
(SELECT *
FROM public.event
WHERE TYPE in ('event1',
'event2')
AND created_at > now() - interval '1 months' );
CREATE VIEW MAU AS
(SELECT EXTRACT(DOW
FROM created_at) AS month,
DATE_TRUNC('week', created_at) AS week,
COUNT(*) AS total_engagement,
COUNT(DISTINCT user_id) AS total_users
FROM events
GROUP BY 2,
1
ORDER BY week DESC);
SELECT month,
week,
SUM(total_engagement) OVER (PARTITION BY month
ORDER BY week) AS total_engagment
FROM MAU
ORDER BY 1 DESC,
2
Here's an example of what that returns:
Month Week Unique Engagement
6 2017-05-22 00:00:00 165
6 2017-05-29 00:00:00 355
6 2017-06-05 00:00:00 572
6 2017-06-12 00:00:00 723
5 2017-05-22 00:00:00 757
5 2017-05-29 00:00:00 1549
5 2017-06-05 00:00:00 2394
5 2017-06-12 00:00:00 3261
5 2017-06-19 00:00:00 3592
Expected return
Month Day Total Engagement
6 1 50
6 2 100
6 3 180
5 1 89
5 2 213
5 3 284
5 4 341
Can you point out where I've got this wrong or if there's an easier way to do it?
You are confusing days, weeks and months in your question but from the expected output I assume that you want month number, week number within a month and a count of those pairs.
SELECT
month,
week,
count(*) as total_engagement
FROM (
SELECT
extract(month from created_at) as month,
extract('day' from date_trunc('week', created_at::date) -
date_trunc('week', date_trunc('month', created_at::date))) / 7 + 1 as week
FROM public.event
WHERE type IN ('event1', 'event2')
AND created_at > now() - interval '1 month'
) t
GROUP BY 1,2
The most interesting part could be getting the week number within a month and for that you can check this answer.

SQL count number of users every 7 days

I am new to SQL and I need to find count of users every 7 days. I have a table with users for every single day starting from April 2015 up until now:
...
2015-05-16 00:00
2015-05-16 00:00
2015-05-17 00:00
2015-05-17 00:00
2015-05-17 00:00
2015-05-17 00:00
2015-05-17 00:00
2015-05-18 00:00
2015-05-18 00:00
...
and I need to count the number of users every 7 days (weekly) so I have data weekly.
SELECT COUNT(user_id), Activity_Date FROM TABLE_NAME
I need output like this:
TotalUsers week1 week2 week3 ..........and so on
82 80 14 16
I am using DB Visualizer to query Oracle database.
You should try following,
Select
sum(Week1) + sum(Week2) + sum(Week3) + sum(Week4) + sum(Week5) as Total,
sum(Week1) as Week1,
sum(Week2) as Week2,
sum(Week3) as Week3,
sum(Week4) as Week4,
sum(Week5) as Week5
From (
select
case when week = 1 then 1 else 0 end as Week1,
case when week = 2 then 1 else 0 end as Week2,
case when week = 3 then 1 else 0 end as Week3,
case when week = 4 then 1 else 0 end as Week4,
case when week = 5 then 1 else 0 end as Week5
from
(
Select
CEILING(datepart(dd,visitdate)/7+1) week,
user_id
from visitor
)T
)D
Here is Fiddle
You need to add month & year in the result as well.
SELECT COUNT(user_id), Activity_Date FROM TABLE_NAME WHERE Activity_Date > '2015-06-31';
That would get the amount of users for the last 7 days.
This is my test table:
user_id act_date
1 01/04/2015
2 01/04/2015
3 04/04/2015
4 05/04/2015
..
This is my query:
select week_offset, count(*) nb from (
select trunc((act_date-to_date('01042015','DDMMYYYY'))/7) as week_offset from test_date)
group by week_offset
order by 1
and this is the output:
week_offset nb
0 6
1 3
4 5
5 7
6 3
7 1
18 1
Week offset is the number of the week from 01/04/2015, and we can show the first day of the week.
See here for live testing.
How do you define your weeks? Here's an approach for SQL Server that starts each seven-day block relative to the start of April. The expressions will vary according to your specific needs:
select
dateadd(
dd,
datediff(dd, cast('20150401' as date), Activity_Date) / 7 * 7,
cast('20150401' as date)
) as WeekStart,
count(*)
from T
group by datediff(dd, cast('20150401' as date), Activity_Date) / 7
Oracle:
select
trunc(Activity_date, 'DAY') as WeekStart,
count(*)
from T
group by trunc(Activity_date, 'DAY') /* D and DAY are the same thing */