Difficulty in creating new variable in SQL - sql

I need like to create some new variables of years (2015, 2016, ---, 2022) based on start date and end date. If someone's year of start date is 2017 and year of end date is 2020 then for that person value in 2017, 2018, 2019, and 2020 columns will be 'Yes'
I used the following code and got the attached table.
select *
,case when startdate >= '2015-01-01 00:00:00.000' and enddate <= '2015-12-31 00:00:00.000' then 'yes' end as '2015'
,case when startdate >= '2016-01-01 00:00:00.000' and enddate <= '2016-12-31 00:00:00.000' then 'yes' end as '2016'
,case when startdate >= '2017-01-01 00:00:00.000' and enddate <= '2017-12-31 00:00:00.000' then 'yes' end as '2017'
,case when startdate >= '2018-01-01 00:00:00.000' and enddate <= '2018-12-31 00:00:00.000' then 'yes' end as '2018'
,case when startdate >= '2019-01-01 00:00:00.000' and enddate <= '2019-12-31 00:00:00.000' then 'yes' end as '2019'
,case when startdate >= '2020-01-01 00:00:00.000' and enddate <= '2020-12-31 00:00:00.000' then 'yes' end as '2020'
,case when startdate >= '2021-01-01 00:00:00.000' and enddate <= '2021-12-31 00:00:00.000' then 'yes' end as '2021'
,case when startdate >= '2022-01-01 00:00:00.000' and enddate <= '2022-12-31 00:00:00.000' then 'yes' end as '2022'
from #have
order by ID
Using the code mentioned above, I got the attached table. Someone's start date is in 2018 and end date is in 2020. They are not showing as 'Yes' in those years.

select *
,case when startdate < '20160101' and enddate > '20150101' then 'yes' end as "2015"
,case when startdate < '20170101' and enddate > '20160101' then 'yes' end as "2016"
,case when startdate < '20180101' and enddate > '20170101' then 'yes' end as "2017"
,case when startdate < '20190101' and enddate > '20180101' then 'yes' end as "2018"
,case when startdate < '20200101' and enddate > '20190101' then 'yes' end as "2019"
,case when startdate < '20210101' and enddate > '20200101' then 'yes' end as "2020"
,case when startdate < '20220101' and enddate > '20210101' then 'yes' end as "2021"
,case when startdate < '20230101' and enddate > '20220101' then 'yes' end as "2022"
from #have
order by ID
There's probably also a way to do this using a CROSS APPLY to a table-value constructor VALUES() clause, but I'm not even sure what database you're using so I won't try guess at the right syntax just yet.

I was able to figure out the solution. See below
select *
,case when 2015 >= year(startdate) and 2015 <= year(enddate) then 'yes' end as '2015'
,case when 2016 >= year(startdate) and 2016 <= year(enddate) then 'yes' end as '2016'
,case when 2017 >= year(startdate) and 2017 <= year(enddate) then 'yes' end as '2017'
,case when 2018 >= year(startdate) and 2018 <= year(enddate) then 'yes' end as '2018'
,case when 2019 >= year(startdate) and 2019 <= year(enddate) then 'yes' end as '2019'
,case when 2020 >= year(startdate) and 2020 <= year(enddate) then 'yes' end as '2020'
,case when 2021 >= year(startdate) and 2021 <= year(enddate) then 'yes' end as '2021'
,case when 2022 >= year(startdate) and 2022 <= year(enddate) then 'yes' end as '2022'
from #Have
order by PID

Related

Total of DATEDIFF from different ROWS with different DATES

I'm trying to get the total days of datediff from different items. There are few conditions:
Some dates are before the StartDate '2020/04/01'
Some dates are after the EndDate '2020/04/30'
Delivery Dates could be before/after or between Start/End dates
Collection Dates could be before/after or between Start/End dates
For example, items have different Delivery and Collection dates between StartDate and EndDate or they could be the same but if the Delivery and Collection dates are not in between Startdate and EndDate so the result should be the datediff between StartDate and EndDate.
In my case the StartDate is 2020/04/01 and EndDate is 2020/04/30
Here is my query:
DECLARE #StartDate DATE
DECLARE #EndDate DATE
SET #StartDate = '2020/04/01'
SET #EndDate = '2020/04/30'
select distinct itemno,
sum ( case when deliverydate between #StartDate and #EndDate and collectiondate between #StartDate and #enddate then
(DATEDIFF(day,deliverydate,collectiondate)-(DATEDIFF(week,deliverydate,collectiondate)*2))+1-(CASE WHEN DATENAME(weekday, deliverydate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(weekday, collectiondate) = 'Saturday' then 1 else 0 end)
when deliverydate between #StartDate and #enddate and collectiondate >= #enddate then
(DATEDIFF(day,deliverydate,#EndDate)-(DATEDIFF(week,deliverydate,#EndDate)*2))+1-(CASE WHEN DATENAME(weekday, deliverydate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(weekday,#EndDate) = 'Saturday' then 1 else 0 end)
when deliverydate <= #StartDate and ci.docdate#5 >= #EndDate then
(DATEDIFF(day,#StartDate,#EndDate)-(DATEDIFF(week,#StartDate,#EndDate)*2))+1-(CASE WHEN DATENAME(weekday, #StartDate) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(weekday, #endDate) = 'Saturday' then 1 else 0 end)
when deliverydate <= #StartDate and ci.docdate#5 between #startdate and #EndDate then
(DATEDIFF(day,#StartDate,ci.docdate#5)-(DATEDIFF(week,#StartDate,ci.docdate#5)*2))+1-(CASE WHEN DATENAME(weekday,ci.docdate#5) = 'Sunday' THEN 1 ELSE 0 END)
- (CASE WHEN DATENAME(weekday, #StartDate) = 'Saturday' then 1 else 0 end)
else 0 end
) as Daysonhire,
from Stock
where itemno = '001127'
group by itemno
MY RESULT IS Daysonhire = 30
AND THE DATES FROM THE DATABASE ARE deliverydate 14/04/2020 collectiondate 16/06/2020
So the result should be 12 or 13 working days

Get the COUNT of data for last 4 years monthly by using CASE statement

I tried this:
SELECT DISTINCT
MONTH(ENCOUNTER_DATE) 'MONTH',
COUNT(CASE WHEN ENCOUNTER_DATE >= DATEADD(YEAR, -1, GETDATE()) THEN CUSTOMER_ID END) ,
COUNT(CASE WHEN ENCOUNTER_DATE >= DATEADD(YEAR, -2, GETDATE()) THEN CUSTOMER_ID END),
COUNT(CASE WHEN ENCOUNTER_DATE >= DATEADD(YEAR, -3, GETDATE()) THEN CUSTOMER_ID END),
COUNT(CASE WHEN ENCOUNTER_DATE >= DATEADD(YEAR, -4, GETDATE()) THEN CUSTOMER_ID END)
FROM
PATIENT_ENCOUNTERS
GROUP BY
MONTH(ENCOUNTER_DATE)
ORDER BY
MONTH(ENCOUNTER_DATE)
The count of every month data is getting added to the next year of the same month.
I cross checked with the below query where the data is not matching
SELECT
YEAR(ENCOUNTER_DATE), COUNT(CUSTOMER_ID)
FROM
PATIENT_ENCOUNTERS
WHERE
ENCOUNTER_DATE >= DATEADD(YEAR, -4, GETDATE())
GROUP BY
YEAR(ENCOUNTER_DATE)
ORDER BY
YEAR(ENCOUNTER_DATE) DESC
Can someone help me to find the data monthly in last 4 years by using case statement only.
Your problem is that you're setting a begin date but not an end date. Try something similar to the following.
COUNT(CASE WHEN ENCOUNTER_DATE >= DATEADD(YEAR, -4, GETDATE()) AND ENCOUNTER_DATE < DATEADD(YEAR, -3, GETDATE()) THEN CUSTOMER_ID END)
Try this:
SELECT DISTINCT MONTH(ENCOUNTER_DATE) 'MONTH',
COUNT(CASE WHEN year(ENCOUNTER_DATE) = YEAR(GETDATE()) THEN CUSTOMER_ID END) ,
COUNT(CASE WHEN year(ENCOUNTER_DATE)= YEAR(GETDATE())-1 THEN CUSTOMER_ID END),
COUNT(CASE WHEN year(ENCOUNTER_DATE)= YEAR(GETDATE())-2 THEN CUSTOMER_ID END),
COUNT(CASE WHEN year(ENCOUNTER_DATE)= YEAR(GETDATE())-3 THEN CUSTOMER_ID END)
FROM PATIENT_ENCOUNTERS
GROUP BY MONTH(ENCOUNTER_DATE)
ORDER BY MONTH(ENCOUNTER_DATE)
Here with YEAR(GETDATE()) I got the year of current year and with YEAR(GETDATE())-1 year part of last year and so on. Then I have compared this year with year of encounter_date as year(encounter_date) = YEAR(GETDATE()) to get the customer_id of that year which are grouped by later by month.
To get the year wise cumulative count:
SELECT DISTINCT MONTH(ENCOUNTER_DATE) 'MONTH',
COUNT(CASE WHEN year(ENCOUNTER_DATE) = YEAR(GETDATE()) THEN CUSTOMER_ID END) ,
COUNT(CASE WHEN year(ENCOUNTER_DATE)>= YEAR(GETDATE())-1 THEN CUSTOMER_ID END),
COUNT(CASE WHEN year(ENCOUNTER_DATE)>= YEAR(GETDATE())-2 THEN CUSTOMER_ID END),
COUNT(CASE WHEN year(ENCOUNTER_DATE)>= YEAR(GETDATE())-3 THEN CUSTOMER_ID END)
FROM PATIENT_ENCOUNTERS
GROUP BY MONTH(ENCOUNTER_DATE)
ORDER BY MONTH(ENCOUNTER_DATE)

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.

Showing Monthly Totals from Multiple Columns in PostgreSQL

I am looking to see the number of firstexam patients seen per month for a given date range this year vs last year, and compare that to the total number of patients seen per month for the same date range.
I am able to set up the firstexam patients as follows:
select case EXTRACT(month FROM patient_info.firstexam)
when 1 then '01 - January'
when 2 then '02 - February'
when 3 then '03 - March'
when 4 then '04 - April'
when 5 then '05 - May'
when 6 then '06 - June'
when 7 then '07 - July'
when 8 then '08 - August'
when 9 then '09 - September'
when 10 then '10 - October'
when 11 then '11 - November'
when 12 then '12 - December'
end as month,
sum(case when patient_info.firstexam >= '2013-01-01' AND patient_info.firstexam <= '2013-12-31' then 1 else 0 end) thisyear,
sum(case when patient_info.firstexam >= '2012-01-01' AND patient_info.firstexam <= '2012-12-31' then 1 else 0 end) lastyear
from patient_info WHERE (patient_info.firstexam >= '2013-01-01' AND patient_info.firstexam <= '2013-12-31' OR patient_info.firstexam >= '2012-01-01' AND patient_info.firstexam <= '2012-12-31')
GROUP BY month
ORDER BY month
This gives me three columns: month, thisyear, lastyear.
Please note: I entered numerical month before month name because I could not get the months to appear in chronological order otherwise. Any hints to not show the number before the month would be appreciated.
I would like to add two more columns for total patients - something like:
select case EXTRACT(month FROM patient_info.lastexam)
when 1 then '01 - January'
when 2 then '02 - February'
when 3 then '03 - March'
when 4 then '04 - April'
when 5 then '05 - May'
when 6 then '06 - June'
when 7 then '07 - July'
when 8 then '08 - August'
when 9 then '09 - September'
when 10 then '10 - October'
when 11 then '11 - November'
when 12 then '12 - December'
end as month,
sum(case when patient_info.lastexam >= '2013-01-01' AND patient_info.lastexam <= '2013-12-31' then 1 else 0 end) totalthisyear,
sum(case when patient_info.lastexam >= '2012-01-01' AND patient_info.lastexam <= '2012-12-31' then 1 else 0 end) totallastyear
from patient_info WHERE (patient_info.lastexam >= '2013-01-01' AND patient_info.lastexam <= '2013-12-31' OR patient_info.lastexam >= '2012-01-01' AND patient_info.lastexam <= '2012-12-31')
GROUP BY month
ORDER BY month
with the results in 5 columns: month, thisyear, totalthisyear, lastyear, totallastyear
but can't seem to figure out exactly how this could be done. The order of the columns is not important.
It could be: month, thisyear, lastyear, totalthisyear, totallastyear
SQL Fiddle
select
to_char(('2012-' || m || '-01')::date, 'Month'),
thisyear, lastyear, totalthisyear, totallastyear
from (
select
extract(month from m) as m,
sum(case
when firstexam between '2013-01-01' and '2013-12-31' then firstexam_count
else 0 end
) as thisyear,
sum(case
when firstexam between '2012-01-01' and '2012-12-31' then firstexam_count
else 0 end
) as lastyear,
sum(case
when lastexam between '2013-01-01' and '2013-12-31' then lastexam_count
else 0 end
) as totalthisyear,
sum(case
when lastexam between '2012-01-01' and '2012-12-31' then lastexam_count
else 0 end
) as totallastyear
from
generate_series (
'2012-01-01'::date, '2013-12-31', '1 month'
) g(m)
left join (
select count(*) as firstexam_count, date_trunc('month', firstexam) as firstexam
from patient_info
where firstexam between '2012-01-01' and '2013-12-31'
group by 2
) pif on firstexam = m
left join (
select count(*) as lastexam_count, date_trunc('month', lastexam) as lastexam
from patient_info
where lastexam between '2012-01-01' and '2013-12-31'
group by 2
) pil on lastexam = m
group by 1
) s
order by m

SQL Results group by month

I'm trying to return some results spread over a rolling 12 month period eg:
MONTH IN OUT
January 210 191
February 200 111
March 132 141
April 112 141
May 191 188
etc...
How do I spread the results over a date range, populating the first column with the month name?
IN MSSQL it would be something like:
SELECT COUNT(problem.problem_type = 'IN') AS IN,
COUNT(problem.problem_type = 'OUT') AS OUT,
DATEPART(year, DateTime) as Year,
DATEPART(month, DateTime) as Month
FROM problem
WHERE (DateTime >= dbo.FormatDateTime('2010-01-01'))
AND
(DateTime < dbo.FormatDateTime('2010-01-31'))
GROUP BY DATEPART(year, DateTime),
DATEPART(month, DateTime);
But this is against an Oracle database so DATEPART and DateTime are not available.
My Problem table is roughly:
problem_ID Problem_type IN_Date OUT_Date
1 IN 2010-01-23 16:34:29.0 2010-02-29 13:06:28.0
2 IN 2010-01-27 12:34:29.0 2010-01-29 12:01:28.0
3 OUT 2010-02-13 13:24:29.0 2010-09-29 15:04:28.0
4 OUT 2010-02-15 16:31:29.0 2010-07-29 11:03:28.0
Use:
SELECT SUM(CASE WHEN p.problem_type = 'IN' THEN 1 ELSE 0 END) AS IN,
SUM(CASE WHEN p.problem_type = 'OUT' THEN 1 ELSE 0 END) AS OUT,
TO_CHAR(datetime, 'YYYY') AS year,
TO_CHAR(datetime, 'MM') AS month
FROM PROBLEM p
WHERE p.DateTime >= TO_DATE('2010-01-01', 'YYYY-MM-DD')
AND p.DateTime < TO_DATE('2010-01-31', 'YYYY-MM-DD')
GROUP BY TO_CHAR(datetime, 'YYYY'), TO_CHAR(datetime, 'MM')
You could also use:
SELECT SUM(CASE WHEN p.problem_type = 'IN' THEN 1 ELSE 0 END) AS IN,
SUM(CASE WHEN p.problem_type = 'OUT' THEN 1 ELSE 0 END) AS OUT,
TO_CHAR(datetime, 'MM-YYYY') AS mon_year
FROM PROBLEM p
WHERE p.DateTime >= TO_DATE('2010-01-01', 'YYYY-MM-DD')
AND p.DateTime < TO_DATE('2010-01-31', 'YYYY-MM-DD')
GROUP BY TO_CHAR(datetime, 'MM-YYYY')
Reference:
TO_CHAR
TO_DATE
You probably want something like
SELECT SUM( (CASE WHEN problem_type = 'IN' THEN 1 ELSE 0 END) ) in,
SUM( (CASE WHEN problem_type = 'OUT' THEN 1 ELSE 0 END) ) out,
EXTRACT( year FROM DateTime ) year,
EXTRACT( month FROM DateTime ) month
FROM problem
WHERE DateTime >= date '2010-01-01'
AND DateTime < date '2010-01-31'
GROUP BY EXTRACT( year FROM DateTime ),
EXTRACT( month FROM DateTime )