Rewrite the query to get output for cross years? - sql

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.

Related

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

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;

User Attendance Date Year and Month Wise

I've a requirement to show user attendance year and month wise. Here is a sample
how it would look - Very basic:
Year - Jan - Feb
2018 - 26 - 20
2019 - 20 - 22
The data is retrieved from a single table and I tried the following query
to do so:
SELECT EXTRACT(YEAR FROM M.DATE) "YEAR",
COUNT(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '1' THEN M.Id ELSE '-' END) "Jan",
COUNT(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '2' THEN M.Id ELSE '-' END) "Feb"
FROM TABLE m
WHERE M.STATUS = 'P' AND M.Id = '12345678'
GROUP BY EXTRACT(YEAR FROM M.DATE) ORDER BY EXTRACT(YEAR FROM M.DATE);
Unfortunately this doesn't return the expected data, instead it shows the yearly
attendance of a user for each month as follows:
Year - Jan - Feb
2018 - 292 - 292
2019 - 100 - 100
Did I miss something here? Any ideas would be appreciated.
Try this-
SELECT EXTRACT(YEAR FROM M.DATE) "YEAR",
COUNT(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '1' THEN M.Id ELSE NULL END) "Jan",
COUNT(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '2' THEN M.Id ELSE NULL END) "Feb"
FROM TABLE m
WHERE M.STATUS = 'P' AND M.Id = '12345678'
GROUP BY EXTRACT(YEAR FROM M.DATE) ORDER BY EXTRACT(YEAR FROM M.DATE);
OR-
SELECT EXTRACT(YEAR FROM M.DATE) "YEAR",
SUM(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '1' THEN 1 ELSE 0 END) "Jan",
SUM(CASE WHEN EXTRACT(MONTH FROM M.DATE) = '2' THEN 1 ELSE 0 END) "Feb"
FROM TABLE m
WHERE M.STATUS = 'P' AND M.Id = '12345678'
GROUP BY EXTRACT(YEAR FROM M.DATE) ORDER BY EXTRACT(YEAR FROM M.DATE);
I prefer using SUM() for this. But more importantly, your code is mixing types. EXTRACT() returns a number so the comparison should be to a number. I recommend:
SELECT EXTRACT(YEAR FROM M.DATE) as "YEAR",
SUM(CASE WHEN EXTRACT(MONTH FROM M.DATE) = 1 THEN 1 ELSE 0 END) as "Jan",
SUM(CASE WHEN EXTRACT(MONTH FROM M.DATE) = 2 THEN 1 ELSE 0 END) as "Feb"
FROM TABLE m
WHERE M.STATUS = 'P' AND
M.Id = 12345678 -- I am guessing that `id` is also a number
GROUP BY EXTRACT(YEAR FROM M.DATE)
ORDER BY EXTRACT(YEAR FROM M.DATE);
You should be careful mixing types. Conversions can impede the ability of the optimizer to find the best query plan.

Re-Ordering the Months By Federal Fiscal Year

When running the following query I am trying to find a way to display the returned months by federal fiscal year instead of normal sequential value.
(ie I want to display months in the following order Oct, Nov, Dec, Jan, Feb, Mar, Apr, May Jun, Jul, Aug, Sept instead of Jan thru Dec.) Thanks
select wrkgrp,
sum (case when extract(month from reportdate) = 1 then 1 else 0 end) as January,
sum (case when extract(month from reportdate) = 2 then 1 else 0 end) as February,
sum (case when extract(month from reportdate) = 3 then 1 else 0 end) as March,
sum (case when extract(month from reportdate) = 4 then 1 else 0 end) as April,
sum (case when extract(month from reportdate) = 5 then 1 else 0 end) as May,
sum (case when extract(month from reportdate) = 6 then 1 else 0 end) as June,
sum (case when extract(month from reportdate) = 7 then 1 else 0 end) as July,
sum (case when extract(month from reportdate) = 8 then 1 else 0 end) as August,
sum (case when extract(month from reportdate) = 9 then 1 else 0 end) as September,
sum (case when extract(month from reportdate) = 10 then 1 else 0 end) as October,
sum (case when extract(month from reportdate) = 11 then 1 else 0 end) as November,
sum (case when extract(month from reportdate) = 12 then 1 else 0 end) as December,
from workorder
where reportdate between to_date ('2014-10-01 00:00:00', 'yyyy/mm/dd hh24:mi:ss')
and to_date ('2015-09-30 00:00:00', 'yyyy/mm/dd hh24:mi:ss')
and wrkgrp = 'PublicWorks'
group by 'wrkgrp;'
The fields will display in your results (horizontally) in the order you list them in your select statement. Structure your statement with Oct listed first like this:
select wrkgrp,
sum (case when extract(month from reportdate) = 10 then 1 else 0 end) as October,
sum (case when extract(month from reportdate) = 11 then 1 else 0 end) as November,
sum (case when extract(month from reportdate) = 12 then 1 else 0 end) as December,
sum (case when extract(month from reportdate) = 1 then 1 else 0 end) as January,
sum (case when extract(month from reportdate) = 2 then 1 else 0 end) as February,
sum (case when extract(month from reportdate) = 3 then 1 else 0 end) as March,
sum (case when extract(month from reportdate) = 4 then 1 else 0 end) as April,
sum (case when extract(month from reportdate) = 5 then 1 else 0 end) as May,
sum (case when extract(month from reportdate) = 6 then 1 else 0 end) as June,
sum (case when extract(month from reportdate) = 7 then 1 else 0 end) as July,
sum (case when extract(month from reportdate) = 8 then 1 else 0 end) as August,
sum (case when extract(month from reportdate) = 9 then 1 else 0 end) as September
from workorder
where reportdate between to_date ('2014-10-01 00:00:00', 'yyyy/mm/dd hh24:mi:ss') ad to_date ('2015-09-30 00:00:00', 'yyyy/mm/dd hh24:mi:ss') and
wrkgrp = 'PublicWorks'
group by 'wrkgrp;'
Add case statements in your order by clause to get the desired sort.
ORDER BY
CASE WHEN extract(month from reportdate) = 10 THEN 1
CASE WHEN extract(month from reportdate) = 11 THEN 2
ASC

Can I use pivot to add columns in the sum?

I have a query where i get the ave of a rating for different question q1-q5.
Would it possible to add the q1-q5 and divide it by the count using pivot?
I have try to make a query below:
SELECT
employeedept,YEAR_cse,csedept_name,
SUM(January) as January, SUM(February) as February,
SUM(March) as March, SUM(April) as April,
SUM(May) as May, SUM(June) as June,
SUM(July) as July, SUM(August) as August,
SUM(September) as September, SUM(October) as October,
SUM(November) as November, SUM(December) as December
FROM
(SELECT
CAST(employeedept AS INT) as dept,
ROUND(AVG(case when rating1 > 0 THEN CAST(rating1 AS FLOAT) ELSE null END), 2) as q1,
ROUND(AVG(case when rating2 > 0 THEN CAST(rating2 AS FLOAT) ELSE null END), 2) as q2,
ROUND(AVG(case when rating3 > 0 THEN CAST(rating3 AS FLOAT) ELSE null END), 2) as q3,
ROUND(AVG(case when rating4 > 0 THEN CAST(rating4 AS FLOAT) ELSE null END), 2) as q4,
ROUND(AVG(case when rating5 > 0 THEN CAST(rating5 AS FLOAT) ELSE null END), 2) as q5,
count(*) as 'totalstars',
month_cse = datename(month, approveddate),
YEAR_cse = YEAR(approveddate)
FROM
CSEReduxResponses
WHERE
execoffice_status = 1
and YEAR ([approveddate]) =2014
GROUP BY
month(approveddate), YEAR(approveddate),
DATENAME(month,approveddate), employeedept) AS r
JOIN
CSEReduxDepts d ON d.csedept_id = r.employeedept
AND YEAR_cse is NOT NULL
PIVOT( SUM(q1+q2+q3+q4+q5/totalstars)
FOR [month_cse] IN (
[January],[February],[March],[April],[May],[June],[July],[August], [September],[October],[November],[December]
)) AS pvt
Group BY employeedept,YEAR_cse,csedept_name
With this query I get this error:
Msg 102, Level 15, State 1, Line 21
Incorrect syntax near '+'.'
What I would like to do is be able to sum the q1-q5/totalstars, Would something like this be possible using pivot?
If I run the second select statement it gives me the correct results.
I think this should be your final query that you need.
I have done wrote the count function to do the average if your value is null then it will return 0 for the particular column
Lets say
rating1 = null then ISNULL(COUNT(rating1),0) = 0
rating2 = 2 then ISNULL(COUNT(rating1),0) = 1
rating3 = 3 then ISNULL(COUNT(rating1),0) = 1
so on....
Here's the query. I hope this will help you.
SELECT
employeedept,
YEAR_cse,
csedept_name,
SUM(January) as January,
SUM(February) as February,
SUM(March) as March,
SUM(April) as April,
SUM(May) as May,
SUM(June) as June,
SUM(July) as July,
SUM(August) as August,
SUM(September) as September,
SUM(October) as October,
SUM(November) as November,
SUM(December) as December
FROM
(
SELECT employeedept,
(
ROUND(AVG(case when rating1>0 THEN CAST(rating1 AS FLOAT) ELSE 0 END), 2) +
ROUND(AVG(case when rating2>0 THEN CAST(rating2 AS FLOAT) ELSE 0 END), 2) +
ROUND(AVG(case when rating3>0 THEN CAST(rating3 AS FLOAT) ELSE 0 END), 2) +
ROUND(AVG(case when rating4>0 THEN CAST(rating4 AS FLOAT) ELSE 0 END), 2) +
ROUND(AVG(case when rating5>0 THEN CAST(rating5 AS FLOAT) ELSE 0 END), 2))
/(
ISNULL(COUNT(rating1),0) +
ISNULL(COUNT(rating2),0) +
ISNULL(COUNT(rating3),0) +
ISNULL(COUNT(rating4),0)+
ISNULL(COUNT(rating5),0)) as AG,
count(*) as 'totalstars',month_cse= datename(month,approveddate),YEAR_cse =YEAR(approveddate)
FROM
CSEReduxResponses
Where
YEAR(approveddate) =2014
and execoffice_status=1
group by
employeedept,
month(approveddate),
YEAR(approveddate),
DATENAME(month,approveddate)
)AS r
JOIN CSEReduxDepts d ON d.csedept_id = r.employeedept
AND YEAR_cse is NOT NULL
PIVOT(
SUM(AG)
FOR [month_cse] IN (
[January],[February],[March],[April],[May],[June],[July],[August], [September],[October],[November],[December]
)) AS pvt
Group BY employeedept,YEAR_cse,csedept_name

How can I accomplish this? Would a cursor be appropriate?

I am trying to use TOAD and T-SQL to approximate a user's spreadsheet. Here are the basics of what they want:
Order Number Customer Name June July Aug Sept Oct Nov Dec
12345 Bleh Company 1000
800 200
The first row represents when the order value was received and the second represents the projected ship date of said order.
The following SQL Script delivers this, but it does not alternate between Order Date and Receiving Date.
SELECT 'O', -- For Order Date
(SOM.[fcustno] + ' - ' + SOM.[fcompany]) AS [Customer],
sum(CASE month (SOM.forderdate)
WHEN 6 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [June],
sum(CASE month (SOM.forderdate)
WHEN 7 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [July],
sum(CASE month (SOM.forderdate)
WHEN 8 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Aug],
sum(CASE month (SOM.forderdate)
WHEN 9 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Sept],
sum(CASE month (SOM.forderdate)
WHEN 10 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Oct],
sum(CASE month (SOM.forderdate)
WHEN 11 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Nov],
sum(CASE month (SOM.forderdate)
WHEN 12 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Dec]
FROM SORELS SOR
JOIN SOMAST SOM
ON SOM.FSONO = SOR.FSONO
JOIN SOITEM SOI
ON SOI.FSONO = SOR.FSONO AND SOI.FINUMBER = SOR.FINUMBER
WHERE FMASTERREL = 0
AND SOM.forderdate >= CONVERT (DATETIME, '05/29/2009')
AND SOM.forderdate < CONVERT (DATETIME, '08/04/2009')
AND SOI.fduedate < CONVERT (DATETIME, '01/01/2010')
GROUP BY (SOM.[fcustno] + ' - ' + SOM.[fcompany])
UNION
SELECT 'S', -- For Ship Date
(SOM.[fcustno] + ' - ' + SOM.[fcompany]) AS [Customer],
sum(CASE month (SOI.fduedate)
WHEN 6 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [June],
sum(CASE month (SOI.fduedate)
WHEN 7 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [July],
sum(CASE month (SOI.fduedate)
WHEN 8 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Aug],
sum(CASE month (SOI.fduedate)
WHEN 9 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Sept],
sum(CASE month (SOI.fduedate)
WHEN 10 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Oct],
sum(CASE month (SOI.fduedate)
WHEN 11 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Nov],
sum(CASE month (SOI.fduedate)
WHEN 12 THEN (sor.forderqty * SOR.funetprice)
ELSE 0
END)
AS [Dec]
FROM SORELS SOR
JOIN SOMAST SOM
ON SOM.FSONO = SOR.FSONO
JOIN SOITEM SOI
ON SOI.FSONO = SOR.FSONO AND SOI.FINUMBER = SOR.FINUMBER
WHERE FMASTERREL = 0
AND SOM.forderdate >= CONVERT (DATETIME, '05/29/2009')
AND SOM.forderdate < CONVERT (DATETIME, '08/04/2009')
AND SOI.fduedate < CONVERT (DATETIME, '01/01/2010')
GROUP BY (SOM.[fcustno] + ' - ' + SOM.[fcompany])
Any suggestions?
Try adding the following:
ORDER BY 2, 1
to the end of your script. It seems as though you just need to sort - first by customer, then by Order / Ship
You should give a name to your 'O'/'S' column (maybe RowType). Then order by Customer, RowType.
Rob