SQL - pull data for date range based on a start date - sql

I have the below SQL query, which pulls account revenues for the past 3 months, along with each account's service start date (I'm using Amazon Redshift via SQL Workbench)
select distinct r.account_id, r.account_name, s.start_date
,SUM(CASE WHEN r.datekey between '20200601' and '20200630' THEN revenue ELSE 0 END) AS "June 2020"
,SUM(CASE WHEN r.datekey between '20200701' and '20200731' THEN revenue ELSE 0 END) AS "July 2020"
,SUM(CASE WHEN r.datekey between '20200801' and '20200831' THEN revenue ELSE 0 END) AS "August 2020"
from revenues r
join start_dates s on r.account_id = s.account_id
group by r.account_id, r.account_name, s.start_date;
How can modify the above query to pull revenues for the 3 months after each client's start date, keeping in mind this 3-month range will be different for each client? I've tried using DATEPART and DATEADD but I haven't found a solution using those statements.

You can change the join conditions to filter the revenues of each account_id on the 3 months that follow it start_date, and then use conditional aggregation:
select
s.account_id,
sum(case when r.datekey < dateadd(month, 1, s.start_date) then revenue else 0 end) as month1,
sum(case when r.datekey >= dateadd(month, 1, s.start_date) and r.datekey < dateadd(month, 2, s.start_date) then revenue else 0 end) as month2,
sum(case when r.datekey >= dateadd(month, 2, s.start_date) then revenue else 0 end) as month3
from start_dates s
left join revenues r
on r.account_id = s.account_id
and r.datekey >= s.start_date
and r.datekey < dateadd(month, 3, s.start_date)
group by s.account_id

Here, use DATEDIFF with start_date and GETDATE()
select distinct r.account_id, r.account_name, s.start_date
,SUM(CASE WHEN r.datekey between '20200601' and '20200630' THEN revenue ELSE 0 END) AS "June 2020"
,SUM(CASE WHEN r.datekey between '20200701' and '20200731' THEN revenue ELSE 0 END) AS "July 2020"
,SUM(CASE WHEN r.datekey between '20200801' and '20200831' THEN revenue ELSE 0 END) AS "August 2020"
from revenues r
join start_dates s on r.account_id = s.account_id
WHERE DATEDIFF(s.start_date, GETDATE())<=90
group by r.account_id, r.account_name, s.start_date;

Related

Get data of 2 different dates in 2 different columns sql

I have a sql table having columns Name, VisitingDate, StayTime
I want a query which can give me data in which in 1 column I can get data of thismonthvisit and other column I can get data of lastmonthvisit and in 3rd column I can data of summation of StayTime of particular person .
Database Table : --
Name
VisitingDate
StayTime(in minutes)
A
2021-04-20
5
A
2021-04-21
15
A
2021-03-20
10
B
2021-03-20
5
Result Wanted : --
Name
Thismonthvisit
TotalStayTimeThismonth(in minutes)
LastmonthVisit
TotalStayTimelastmonth(in minutes)
A
2
20
1
10
B
0
0
1
5
Here is what you are looking for :
select name,
SUM(CASE WHEN FORMAT(VisitingDate, 'YYYYMM') = FORMAT(getdate(),'YYYYMM') THEN 1 ELSE 0 END) AS ThisMonthVisit,
SUM(CASE WHEN FORMAT(VisitingDate, 'YYYYMM') = FORMAT(getdate(),'YYYYMM') THEN StayTime ELSE 0 END) AS TotalStayTimeThisMonth,
SUM(CASE WHEN FORMAT(VisitingDate, 'YYYYMM') = FORMAT(dateadd(month, -1, getdate()),'YYYYMM') THEN 1 ELSE 0 END) AS LastMonthVisit,
SUM(CASE WHEN FORMAT(VisitingDate, 'YYYYMM') = FORMAT(dateadd(month, -1, getdate()),'YYYYMM') THEN StayTime ELSE 0 END) AS TotalStayTimeLastMonth
from MyTable
where FORMAT(VisitingDate, 'YYYYMM') > FORMAT(dateadd(month, -2, getdate()),'YYYYMM')
group by Name
SEE DEMO HERE
You can use aggregation:
select name,
sum(case when month(visitingdate) = month(getdate())
then 1 else 0
end) as cnt_thismonth,
sum(case when month(visitingdate) = month(getdate())
then staytime else 0
end) staytime_thismonth,
sum(case when month(visitingdate) <> month(getdate())
then 1 else 0
end) as cnt_lastmonth,
sum(case when month(visitingdate) <> month(getdate())
then staytime else 0
end) staytime_lastmonth
from t
where visitingdate >= dateadd(month, -1, datefromparts(year(getdate()), month(getdate()), 1))
group by name;

Rewrite the query to get output for cross years?

SELECT
sum(case
when "year" = '2016' then "svalue"
ELSE 0
END) as 'sva_2016',
sum(case
when "year" = '2017' then "svalue"
ELSE 0
END) as 'sva_2017',
sum(case
when "year" = '2018' then "svalue"
ELSE 0
END) as 'sva_2018',
sum(case
when "year" = '2019' then "svalue"
ELSE 0
END) as 'sva_2019',
sum(case
when "year" = '2016' then "ltr"
ELSE 0
END) as 'lva_2016',
sum(case
when "year" = '2017' then "ltr"
ELSE 0
END) as 'lva_2017',
sum(case
when "year" = '2018' then "ltr"
ELSE 0
END) as 'lva_2018',
sum(case
when "year" = '2019' then "ltr"
ELSE 0
END) as 'lva_2019',
'Apr 1 - Jan 31' as 'Period',
"code" as 'FACode'
FROM "FCJOIN"
WHERE "code" IN
(
SELECT "fccode"
FROM "fcdetails"
)
AND "month" between '04' and '12'
AND "year" IN ( '2016' , '2017' , '2018' , '2019' )
GROUP BY "code"
The above query gives me the correct out put for svalues and ltr for
April 2016- December 2016
April 2017- December 2017
April 2018- December 2018
April 2019- December 2019
Now I want to get the values of svalues and ltrs for the period of
April 2016- January 2017
April 2017- January 2018
April 2018- January 2019
April 2019- January 2020
You may use CAST("year" + '-' + "month" + '-01' AS DATETIME) to compare operations.
Btw. it is good example to use PIVOT operator.
Convert the year/month to a date and use date comparisons:
select f.code,
sum(case when v.dte >= '2016-04-01' and v.dte < '2017-04-01'
then f.svalue else 0
end) as svalue_2016,
. . .
sum(case when v.dte >= '2016-04-01' and v.dte < '2017-04-01'
then f.ltr else 0
end) as ltr_2016,
. . .
from fcjoin f cross apply
(values (datefromparts(f.year, f.month, 1))
) v(dte)
where f.code in (select fd.fccode from fcdetails fd)
group by code;
I removed all the double quotes, because they just complicate the query.

Month number retention cohort calculation issue with Redshift

I'm trying to calculate user retention cohorts in redshift by month for the last 9 months. But I'm running into an issue where the month cohorts in the below query aren't being rolled into the correct month.
The data types I'm querying are:
userid - varchar
activated-varchar
Here is the query I'm trying to run:
with by_month as
(SELECT
userid
DATE_TRUNC('month', cast ("activated" as date)) AS joined_month
FROM customers
GROUP BY 1, 2),
first_month as
(select userid,
joined_month,
FIRST_VALUE(order_month) OVER (PARTITION BY userid ORDER BY
joined_month asc rows unbounded preceding) AS first
FROM by_month),
months as (select userid,
joined_month,
first,
extract(month from (joined_month - first_month)) as month_number
from first_month)
SELECT
first as "cohort",
SUM(CASE WHEN month_number = '0' THEN 1 ELSE 0 END) AS " Month 0",
SUM(CASE WHEN month_number = '1' THEN 1 ELSE 0 END) AS " Month 1",
SUM(CASE WHEN month_number = '2' THEN 1 ELSE 0 END) AS " Month 2",
SUM(CASE WHEN month_number = '3' THEN 1 ELSE 0 END) AS " Month 3",
SUM(CASE WHEN month_number = '4' THEN 1 ELSE 0 END) AS " Month 4",
SUM(CASE WHEN month_number = '5' THEN 1 ELSE 0 END) AS " Month 5",
SUM(CASE WHEN month_number = '6' THEN 1 ELSE 0 END) AS " Month 6",
SUM(CASE WHEN month_number = '7' THEN 1 ELSE 0 END) AS " Month 7",
SUM(CASE WHEN month_number = '8' THEN 1 ELSE 0 END) AS " Month 8",
SUM(CASE WHEN month_number = '9' THEN 1 ELSE 0 END) AS " Month 9"
from months
where first_month >= '2018-08-01'
GROUP BY 1
ORDER BY 1 desc
When I get the results back, I get an impossible number for a couple of cohorts:
Such as:
Cohort Month 0 Month 1
'2019-01-01' 95 120
I did some digging and found the month numbers aren't being counted correctly For instance, for the cohort of '2019-01-01 the month_ number is t's capturing 0,1, and 3 correctly but 2 is being miss-attributed to month 1. Any help on the fix would be much appreciated thank you!
Now, try
SELECT userid, joined_month, first_month, month_number FROM months
WHERE first = '2019-01-01'
(feel free to add other columns to drill down to the problem) add activated, order_month, etc until you get the right handle on what is causing it.

Select distinct count usage divided by month

I do have a table license_Usage which works like a log of the usage of licenses in a day
ID User license date
1 1 A 22/1/2015
2 1 A 23/1/2015
3 1 B 23/1/2015
4 1 A 24/1/2015
5 2 A 22/2/2015
6 2 A 23/2/2015
7 1 B 23/2/2015
Where I want it to return the count of licenses of the day of the month with most usage of licenses the result should look like:
User Jan Feb
1 2 1 ...
2 0 2
I know I can get the total of licenses in a month using this query:
SELECT vlu.[Userkey],
COUNT(CASE WHEN MONTH = 1 THEN 1 END) as JAN,
COUNT(CASE WHEN MONTH = 2 THEN 1 END) as FEB,
COUNT(CASE WHEN MONTH = 3 THEN 1 END) as MAR,
COUNT(CASE WHEN MONTH = 4 THEN 1 END) as APR,
COUNT(CASE WHEN MONTH = 5 THEN 1 END) as MAY,
COUNT(CASE WHEN MONTH = 6 THEN 1 END) as JUN,
COUNT(CASE WHEN MONTH = 7 THEN 1 END) as JUL,
COUNT(CASE WHEN MONTH = 8 THEN 1 END) as AUG,
COUNT(CASE WHEN MONTH = 9 THEN 1 END) as SEP,
COUNT(CASE WHEN MONTH = 10 THEN 1 END) as OCT,
COUNT(CASE WHEN MONTH = 11 THEN 1 END) as NOV,
COUNT(CASE WHEN MONTH = 12 THEN 1 END) as DEC
FROM license_usage vlu
CROSS APPLY (SELECT MONTH(vlu.EndDate)) AS CA(Month)
WHERE vlu.[EndDate] >='2015-01-01'
AND vlu.[EndDate] < '2016-01-01'
GROUP BY vlu.[Userkey]
How can I get it to return my results?
Example:
http://sqlfiddle.com/#!3/be0b4/1
Got it by using distinct on the Count (*)
select umd.pbrUserkey,
max(case when mm = 1 then cnt else 0 end) as Jan,
max(case when mm = 2 then cnt else 0 end) as Feb,
max(case when mm = 3 then cnt else 0 end) as Mar,
max(case when mm = 4 then cnt else 0 end) as Apr,
max(case when mm = 5 then cnt else 0 end) as May
from (select vluk.pbrUserkey, month(vluk.EndDate) as mm, day(vluk.EndDate) as dd,
count(distinct vluk.idPackage) as cnt
from [license_usage] as vluk
where vluk.[EndDate] >= '2015-01-01' AND vluk.[EndDate] < '2016-01-01'
group by vluk.Userkey, month(vluk.EndDate), day(vluk.EndDate)
) umd
group by umd.Userkey;
If I understand correctly, you want the maximum by day usage per month for each user. The basic data you want is:
select UserKey, month(license_usage) as mm, day(license_usage) as dd,
count(distinct license) as cnt
from license_usage vlu
where vlu.EndDate] >= '2015-01-01' and vlu.EndDate < '2016-01-01'
group by UserKey, month(license_usage), day(license_usage);
Then you can pivot this in several ways, such as using conditional aggregation:
select UserKey,
max(case when mm = 1 then cnt else 0 end) as Jan,
. . .
from (select UserKey, month(license_usage) as mm, day(license_usage) as dd,
count(distinct license) as cnt
from license_usage vlu
where vlu.EndDate] >= '2015-01-01' AND vlu.EndDate < '2016-01-01'
group by UserKey, month(license_usage), day(license_usage)
) umd
group by UserKey;
CROSS APPLY is an interesting approach, but I can't think of a simpler way to get this information.

Group by year in sql

I am trying to group by year but was not able to do.I can get the column count but not year wise. this is what i tried.
select t_contract ,
sum(CASE t_contract when '18' then 1 else 0 end) as XL,
sum(CASE t_contract when '01' then 1 else 0 end) as VC,
sum(CASE t_contract when '75' then 1 else 0 end) as AN,
sum(CASE t_contract when '48' then 1 else 0 end) as CS
from icps.dbo.tickets
WHERE
t_date_time_issued >= DATEADD(year, -6, GETDATE())
GROUP BY contract
.. but i want to add year .. where i have t_date_time _issued column.
My another query is I have a column called t_zone_name and I want to sum all the rows where t_zone_anme like '%ICeland%' an i tried this:
sum(CASE t_zone_name like '%ICeland%' then 1 else 0 end) as ICELAND
but I get an error on statement like... thanks in advance.
LIKE
YEAR XL VC AN CS total
2010 50 50 50 50 200
2011 5 5 5 5 20
Try the below query:
SELECT t_contract, YEAR(t_date_time_issued) As Yr, SUM(CASE WHEN t_zone_name like '%ICeland%' THEN 1 ELSE 0 END) AS ICELAND
SUM(CASE t_contract when '18' then 1 else 0 end) as XL,
SUM(CASE t_contract when '01' then 1 else 0 end) as VC,
SUM(CASE t_contract when '75' then 1 else 0 end) as AN,
SUM(CASE t_contract when '48' then 1 else 0 end) as CS
FROM icps.dbo.tickets
WHERE YEAR(t_date_time_issued) >= (YEAR(GetDate()) - 6)
GROUP BY t_contract, YEAR(t_date_time_issued)
You might need change the order of t_contract and YEAR(t_date_time_issued) depending on which grouping you want to apply first.
As suggested by #ray I have replaced DATEPART(yyyy, t_date_time_issued) >= DATEPART(yyyy, DATEADD(year, -6, GETDATE())) with year(t_date_time_issued) >= (year(GetDate()) - 6)
If you want to group by year, in sql server, you might
GROUP BY DATEDIFF(year,t_date_time_issued, GETDATE())
In other DB engine, usually has method to get year part, or use substring to get year part from a time string.