SQL Union in Separate Columns - sql

I made a database to enter all my headache and migraine tracking data into. I'm pulling some queries that show counts of different headache severity by month for a certain year. I have one query that gets all headaches by month, another gets headaches under a certain severity, and the last gets headaches over a certain severity. There are two columns I'm using in the database: HeadacheDate and Severity. I'd like to do a query that would have the following columns as output:
Month, Count of All Headaches, Count of Headaches under 6 Severity,
Count of Headaches Over 5 Severity
I've made a union query that takes 3 queries and gives me the data I want but I just can't figure out how to do a query that will move the data around to give me the column format I want.
Here are my union queries:
SELECT
DateName(month, DateAdd(month, MONTH(HeadacheDate), -1)) AS
HeadacheMonth,
COUNT(Severity) as SeverityCount
FROM
Headaches
WHERE
Severity > 0 AND YEAR(HeadacheDate) = 2013
GROUP BY
MONTH(HeadacheDate)
UNION
SELECT
DateName(month, DateAdd(month, MONTH(HeadacheDate), -1)) AS HeadacheMonth,
COUNT(Severity) as SeverityCount
FROM
Headaches
WHERE
Severity > 0 AND Severity < 6 AND YEAR(HeadacheDate) = 2013
GROUP BY
MONTH(HeadacheDate)
UNION
SELECT
DateName(month, DateAdd(month, MONTH(HeadacheDate), -1)) AS HeadacheMonth,
COUNT(Severity) as SeverityCount
FROM
Headaches
WHERE
Severity > 5 AND YEAR(HeadacheDate) = 2013
GROUP BY
MONTH(HeadacheDate);
This returns results something like this:
April 3
April 11
April 14
August 5
August 10
August 15
December 2
December 11
December 13
July 5
July 6
July 11
June 4
June 10
June 14
March 1
March 2
March 3
May 5
May 8
May 13
November 1
November 13
November 14
October 4
October 9
October 13
September 4
September 10
September 14
What I want is this:
Month, Count of All Headaches, Count of Headaches under 6 Severity, Count of Headaches Over 5 Severity
January, 20, 15, 5
February, 18, 13, 5
and so on.
I'd also like to include months where one of the count fields could be zero.

You can use conditional grouping:
SELECT
[HeadacheMonth] = DATENAME(month, DateAdd(month , MONTH(HeadacheDate), -1))
,[SeverityCountTotal] = COUNT(CASE WHEN Severity > 0 THEN 1 END)
,[SeverityCount_1_5] = COUNT(CASE WHEN Severity > 0
AND Severity < 6 THEN 1 END)
,[SeverityCount_6] = COUNT(CASE WHEN Severity > 5 THEN 1 END)
FROM Headaches
WHERE YEAR(HeadacheDate) = 2013
GROUP BY MONTH(HeadacheDate);
YEAR(HeadacheDate) = 2013 is not SARGable so if index exits on that column query optimizer will skip it.You could consider using:
HeadacheDate >= '2013-01-01T00:00:00' AND HeadacheDate < '2014-01-01T00:00:00'

SELECT Month
,COUNT(Severity) AS ALL
,SUM(CASE WHEN Severity<6 THEN 1 ELSE 0 END) AS SevUn6
,SUM(CASE WHEN Severity>5 THEN 1 ELSE 0 END) AS SevOv5
FROM <table>
GROUP BY Month

Related

How to get data from date

Hi I would like to get data from date for users. I ve got a table with all months but i would like to get how much they earn on month
user
month
money
1
january
10
2
january
1
1
april
100
2
april
1000
1
march
0
2
march
1
And result should be:
user
money_on_april
money_on_march
1
100
0
2
1000
1
3
0
0
Assuming you want a column for every month, or a certain subset of months:
SELECT
user,
SUM(CASE month WHEN 'january' THEN money ELSE 0 END) As money_on_january,
SUM(CASE month WHEN 'february' THEN money ELSE 0 END) As money_on_february,
...
FROM
YourTable
GROUP BY
user
If you only want columns for the months which exist in the table, then you'll need to use dynamic SQL instead.
If you are using MS SQL, Try PIVOT
SELECT * FROM [Your Table]
PIVOT(
SUM([money])
FOR [month] IN ([january],[april],[march])
)pvt

SQL Showing Rolling 4 Months, Looking for Fiscal Year

I have been provided the below SQL query and am looking to modify it. Currently this is only pulling the last 4 months worth of data. I am trying to modify it to run from December 1 through the current month. If anyone is able to guide me through this, that would be greatly appreciated.
Select NVL(x.COUNT, 0) + z.COUNT As "Number of RMAs",
Case z.MONTH When 1 Then 'Jan.' When 2 Then 'Feb.' When 3 Then 'Mar.'
When 4 Then 'Apr.' When 5 Then 'May' When 6 Then 'Jun.' When 7 Then 'Jul.'
When 8 Then 'Aug.' When 9 Then 'Sep.' When 10 Then 'Oct.'
When 11 Then 'Nov.' When 12 Then 'Dec.' Else 'error' End As "Month",
z.YEAR,
'28.00' As GOAL,
Round(Avg(NVL(x.COUNT, 0) + z.COUNT) Over (Order By z.YEAR, z.MONTH Rows
Between 2 Preceding And Current Row), 2) As ROLL3MOAVG
From (Select Count(RMA.ID) As count,
Extract(Month From RMA.RMA_DATE) As month,
Extract(Year From RMA.RMA_DATE) As year
From RMA,
(Select Unique RMA_DETAIL.RMA_ID
From RMA_DETAIL
Where RMA_DETAIL.RETURN_CODE_ID > 0 And RMA_DETAIL.RETURN_CODE_ID <
100) RMA_DETAIL
Where RMA.ID = RMA_DETAIL.RMA_ID And RMA.RMA_DATE >= SysDate - 400
Group By Extract(Month From RMA.RMA_DATE),
Extract(Year From RMA.RMA_DATE)) x,
(Select 0 As count,
Extract(Month From Add_Months(SysDate - 120, (Level - 1))) As month,
Extract(Year From Add_Months(SysDate - 120, (Level - 1))) As year
From dual
Connect By Level <= 13) z
Where z.MONTH = x.MONTH(+) And z.YEAR = x.YEAR(+)
Order By z.YEAR,
z.MONTH
Don't have access to any sample data, so I would try the following: The correlated subquery aliased as "z" calculates your date boundaries:
SELECT 0 AS count,
EXTRACT(MONTH FROM Add_Months(SysDate - 120, (LEVEL - 1))) AS month,
EXTRACT(YEAR FROM Add_Months(SysDate - 120, (LEVEL - 1))) AS year
FROM dual
CONNECT BY LEVEL <= 13
COUNT MONTH YEAR
---------- ---------- ----------
0 2 2020
0 3 2020
0 4 2020
0 5 2020
0 6 2020
0 7 2020
0 8 2020
0 9 2020
0 10 2020
0 11 2020
0 12 2020
0 1 2021
0 2 2021
It starts with the month 120 days ago (SysDate - 120) and adds 12 month rows. Run this query in sqldeveloper to check what it does. You'll see it starts in feb 2020 and ends in feb 2021.
If you replace that query with a query that starts on dec 1st up till now it should work:
SELECT 0 AS count,
EXTRACT(MONTH FROM ADD_MONTHS(TO_DATE('01-DEC-2019','DD-MON-YYYY'), (LEVEL - 1))) As month,
EXTRACT(YEAR FROM ADD_MONTHS(TO_DATE('01-DEC-2019','DD-MON-YYYY'), (LEVEL - 1))) As year
FROM dual
CONNECT BY LEVEL <= ROUND(MONTHS_BETWEEN(SYSDATE,TO_DATE('01-DEC-2019','DD-MON-YYYY'))) + 1
COUNT MONTH YEAR
---------- ---------- ----------
0 12 2019
0 1 2020
0 2 2020
0 3 2020
0 4 2020
0 5 2020
0 6 2020
explanation:
start with ADD_MONTHS(TO_DATE('01-DEC-2019','DD-MON-YYYY'), (LEVEL - 1)). Your first row will be LEVEL 1 so this will return December.
CONNECT BY LEVEL <= ROUND(MONTHS_BETWEEN(SYSDATE,TO_DATE('01-DEC-2019','DD-MON-YYYY'))) + 1: add a month up til current month so calculate the number of months between now and dec 1st and add 1.
For getting a query that works for every year (there must be cleaner ways to write this but I can't think of any now), use the following:
SELECT 0 AS count,
EXTRACT(MONTH FROM ADD_MONTHS(TO_DATE('01-DEC-'||TO_CHAR(ADD_MONTHS(SYSDATE,-11),'YYYY'),'DD-MON-YYYY'), (LEVEL - 1))) As month,
EXTRACT(YEAR FROM ADD_MONTHS(TO_DATE('01-DEC-'||TO_CHAR(ADD_MONTHS(SYSDATE,-11),'YYYY'),'DD-MON-YYYY'), (LEVEL - 1))) As year
FROM dual
CONNECT BY LEVEL <= ROUND(MONTHS_BETWEEN(SYSDATE,TO_DATE('01-DEC-'||TO_CHAR(ADD_MONTHS(SYSDATE,-11),'YYYY'),'DD-MON-YYYY'))) + 1

more than one AVG column with diffrent conditions

I have a table as follows:
id year value
1 2012 10
2 2013 7
3 2013 7
4 2014 8
5 2014 10
6 2015 6
7 2011 12
I need to write a query which gives the AVG value of the last 4 years from today. Meaning that if today is 2016 then the AVG is on 2015,2014,2013.
Basicly this could be done with 3 queries:
Select avg(value) as a
from tab
where year=2015
and
Select avg(value) as b
from tab
where year=2014
and
Select avg(value) as c
from tab
where year=2013
The results based on the given values should be:
2013 7
2014 9
2015 6
Since all of them is on the same table... How can I do that in one query (postgresql)?
it should be without a WHERE.
Something like:
Select avg(with condition) as a, avg(with condition) as b, avg(with condition) as c
from tab
You can group by year and constrict to the years you want in your where clause
select avg(value), year
from tab
where year in (2013,2014,2015)
group by year
The query above will give you 3 separate rows. If you prefer a single row then you can use conditional aggregation instead of a group by
select
avg(case when year = 2013 then value end) as avg_2013,
avg(case when year = 2014 then value end) as avg_2014,
avg(case when year = 2015 then value end) as avg_2015,
from tab
where year in (2013,2014,2015)
select
avg(case when year = date_part('year', NOW()) then value end) as avg_2016,
avg(case when year = ((date_part('year', NOW())) - 1 ) then value end) as avg_2015,
avg(case when year = ((date_part('year', NOW())) - 2 ) then value end) as avg_2014,
avg(case when year = ((date_part('year', NOW())) - 3 ) then value end) as avg_2013
from tab

Row as column in SQL Server 2008

I am working with SQL Server 2008. I have a temp table which returns the this result
Location Month value
US January 10
US February 10
US March 10
US April 10
US May 10
US June 10
UK January 10
UK January 10
UK February 10
UK February 10
UK March 10
UK March 10
UK April 10
UK April 10
UK May 10
UK May 10
UK June 10
UK June 10
I want to get the result as below
Location January February March Q1 April May June Q2
US 10 10 10 30 10 10 10 30
UK 20 20 20 60 20 20 20 60
How to query to get the above result using SQL Server 2008?
You can use this query, you have to complete it to fit your needs with all missing months/quarters:
select Location
,sum(case when [Month] = 'January' then value else 0 end) as January
,sum(case when [Month] = 'February' then value else 0 end) as February
,sum(case when [Month] = 'March' then value else 0 end) as March
,sum(case when [Month] in ( 'January', 'February', 'March')
then value else 0 end) as Q1
...
-- Repeat months...
...
,sum(value) as AllMonthTotal
from myTempTable
group by Location
-- UNION to get rowwise total
union
select 'TOTAL'
,sum(case when [Month] = 'January' then value else 0 end) as January
,sum(case when [Month] = 'February' then value else 0 end) as February
,sum(case when [Month] = 'March' then value else 0 end) as March
,sum(case when [Month] in ( 'January', 'February', 'March')
then value else 0 end) as Q1
...
-- Repeat months...
...
,sum(value) as AllMonthTotal
from myTempTable
There's also the PIVOT method:
Using PIVOT in SQL Server 2008
MSSQL dynamic pivot column values to column header

SQL Table UPDATE by row with days per month

SQL Server 2005:
I'm attempting to create a table that looks like this:
JAN | FEB | March .......Dec | YTD
Total Volume:
Days in Month:
Gallons per day AVG:
Three rows with description on left, 13 columns (one for each month and year to date total).
I know how to populate the total volume per month. What would I use for days per month and average? I'd like the days per month to show either the complete number of days if it is a past month or current completed days if its the current month.
You are pivoting the data, so you want the results in columns. You can do this by using direct calculation. Here is an example for the first three months:
select 'Days In Month' as col1,
(case when month(getdate()) < 1 then 0
when month(getdate()) = 1 then day(getdate())
else 31
end) as Jan,
(case when month(getdate()) < 2 then 0
when month(getdate()) = 2 then day(getdate())
when year(getdate()) % 4 = 0 then 29
else 28
end) as Feb,
(case when month(getdate()) < 3 then 0
when month(getdate()) = 3 then day(getdate())
else 31
end) as Mar,