Multiple PIVOTS? Need to count by Hour Per Month - sql-server

This should be pretty simple. I have other PIVOT SQL queries working fine. I want to count logins: by hour, by month. I am thinking two PIVOTs or UNPIVOT and then PIVOT? Yes, I have dug around here, other sites, Google, etc. I am pretty stuck.
SELECT
loginid
,DATEPART(MONTH,logtime) Month
, DATEPART(HOUR, logtime) Hour
FROM somelog (nolock)
) temp
PIVOT (
COUNT(loginid)
FOR Month in (JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC)
) AS Pvt
What I want the results to be..
HOUR,JAN,FEB,MAR
00
01
02
..
23
and I don't need 8760 (365 x 24) of them
I have tried GROUP BY HOUR
I have tried GROUP BY temp.hour
I have also tried this as well.. It does seem to work, but I get Hour 00 for example 365 times.. Again, the GROUP BY issue..
SELECT
TimeOfDay
, [1] JAN
, [2] FEB
, [3] MAR
, [4] APR
, [5] MAY
, [6] JUN
, [7] JUL
, [8] AUG
, [9] SEP
, [10] OCT
, [11] NOV
, [12] DEC
FROM (SELECT logintime
, loginid
, datepart(month, logintime) [month]
, DatePart(hour, logintime) TimeOfDay
FROM sometable (nolock)) x
PIVOT (
COUNT(loginid)
for [month] in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
) AS pvt
ORDER BY 1, 2
Thanks,
Kent

One way to do it
WITH hour_list AS (
SELECT 0 hour
UNION ALL
SELECT hour + 1 FROM hour_list WHERE hour < 23
)
SELECT h.hour,
COALESCE(jan, 0) jan,
COALESCE(feb, 0) feb,
COALESCE(mar, 0) mar,
COALESCE(apr, 0) apr,
COALESCE(may, 0) may,
COALESCE(jun, 0) jun,
COALESCE(jul, 0) jul,
COALESCE(aug, 0) aug,
COALESCE(sep, 0) sep,
COALESCE(oct, 0) oct,
COALESCE(nov, 0) nov,
COALESCE(dec, 0) dec
FROM hour_list h LEFT JOIN
(
SELECT DATEPART(HOUR, logtime) hour,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 1 THEN 1 END) jan,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 2 THEN 1 END) feb,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 3 THEN 1 END) mar,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 4 THEN 1 END) apr,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 5 THEN 1 END) may,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 6 THEN 1 END) jun,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 7 THEN 1 END) jul,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 8 THEN 1 END) aug,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 9 THEN 1 END) sep,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 10 THEN 1 END) oct,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 11 THEN 1 END) nov,
SUM(CASE WHEN DATEPART(MONTH, logtime) = 12 THEN 1 END) dec
FROM somelog (NOLOCK)
GROUP BY DATEPART(HOUR, logtime)
) l
ON h.hour = l.hour
or with PIVOT
WITH hour_list AS (
SELECT 0 hour
UNION ALL
SELECT hour + 1 FROM hour_list WHERE hour < 23
)
SELECT h.hour,
COALESCE([1], 0) jan,
COALESCE([2], 0) feb,
COALESCE([3], 0) mar,
COALESCE([4], 0) apr,
COALESCE([5], 0) may,
COALESCE([6], 0) jun,
COALESCE([7], 0) jul,
COALESCE([8], 0) aug,
COALESCE([9], 0) sep,
COALESCE([10], 0) oct,
COALESCE([11], 0) nov,
COALESCE([12], 0) dec
FROM hour_list h LEFT JOIN
(
SELECT DATEPART(MONTH, logtime) month,
DATEPART(HOUR, logtime) hour,
COUNT(*) log_count
FROM somelog (NOLOCK)
GROUP BY DATEPART(MONTH, logtime), DATEPART(HOUR, logtime)
) s
PIVOT
(
SUM(log_count) FOR month IN([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
) p
ON h.hour = p.hour
Sample output for both queries:
| HOUR | JAN | FEB | MAR | APR | MAY | JUN | JUL | AUG | SEP | OCT | NOV | DEC |
|------|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|
| 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 3 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 4 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
...
Here is SQLFiddle demo (using CASE)
Here is SQLFiddle demo (using PIVOT)

Related

IBM DB2 PIVOT A TABLE FULL OF DATES

I have this table in DB2:
DATE
----------
09/11/2021
06/10/2021
28/11/2021
17/11/2021
11/10/2021
24/11/2021
07/11/2021
30/11/2021
I want to count how many times a date appeared in the table and group it by year and month, and display it like this:
| YEAR | OCTOBER | NOVEMBER |
----------------------------
| 2021 | 2 | 6 |
As months are a known quantity you could use a sum of a case statement:
select year(datecol) as year
,sum(case when month(datecol) = 1 then 1 else 0 end) as jan
,sum(case when month(datecol) = 2 then 1 else 0 end) as feb
,sum(case when month(datecol) = 3 then 1 else 0 end) as mar
,sum(case when month(datecol) = 4 then 1 else 0 end) as apr
,sum(case when month(datecol) = 5 then 1 else 0 end) as may
,sum(case when month(datecol) = 6 then 1 else 0 end) as jun
,sum(case when month(datecol) = 7 then 1 else 0 end) as jul
,sum(case when month(datecol) = 8 then 1 else 0 end) as aug
,sum(case when month(datecol) = 9 then 1 else 0 end) as sep
,sum(case when month(datecol) = 10 then 1 else 0 end) as oct
,sum(case when month(datecol) = 11 then 1 else 0 end) as nov
,sum(case when month(datecol) = 12 then 1 else 0 end) as dec
from datetest
group by year(datecol)
order by 1;
That will give you output similar to this:
YEAR JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
2018 0 0 0 0 0 0 0 0 0 0 3 0
2019 0 0 0 0 0 0 0 0 0 1 2 0
2020 0 0 0 0 0 0 0 0 0 1 1 0
2021 0 0 0 0 0 0 0 0 0 2 6 0
You may use a generic routine described at the link dynamic pivot SQL Query in Db2.
Use the following call to get the desired result set for your case:
CALL PIVOT
(
'SELECT YEAR (DATE) AS YEAR, TO_CHAR (DATE, ''MONTH'') AS MONTH FROM DATES'
, 'YEAR'
, 'MONTH'
, 'MONTH'
, 'count'
, 'SESSION.PIVOT'
, '-'
, ?, ?, ?
);
The result is:
YEAR
NOVEMBER
OCTOBER
2021
6
2

Get data month wise(previous six months from current month) in oracle sql

Table:
Id Month Value
T101 02/2020 3
T101 01/2020 5
T101 05/2020 4
T103 03/2020 7
T103 12/2020 10
T103 11/2019 16
Required:
Id DEC'19 JAN'20 FEB'20 MAR'20 APR'20 MAY'20
T101 0 5 3 0 0 4
T103 10 0 0 7 0 0
I need to get 6 months data (DEC'19-MAY'20)......Thanks in advance!!
You can use the conditional aggregation as follows:
SELECT id,
COALESCE(CASE WHEN MONTH = ADD_MONTHS(TRUNC(SYSDATE,'MON'), - 5)
THEN value END), 0) as MONTH6,
COALESCE(CASE WHEN MONTH = ADD_MONTHS(TRUNC(SYSDATE,'MON'), - 4)
THEN value END), 0) as MONTH5,
....
COALESCE(CASE WHEN MONTH = TRUNC(SYSDATE,'MON')
THEN value END), 0) as CURRENT_MONTH,
FROM your_table
GROUP BY id
Note that I am considering that the MONTH is the date column
You can use a PIVOT (with COALESCE to get the zero values):
SELECT ID,
COALESCE( "MAY'20", 0 ) AS "MAY'20",
COALESCE( "APR'20", 0 ) AS "APR'20",
COALESCE( "MAR'20", 0 ) AS "MAR'20",
COALESCE( "FEB'20", 0 ) AS "FEB'20",
COALESCE( "JAN'20", 0 ) AS "JAN'20",
COALESCE( "DEC'19", 0 ) AS "DEC'19"
FROM data
PIVOT (
SUM( value )
FOR Month IN (
DATE '2020-05-01' AS "MAY'20",
DATE '2020-04-01' AS "APR'20",
DATE '2020-03-01' AS "MAR'20",
DATE '2020-02-01' AS "FEB'20",
DATE '2020-01-01' AS "JAN'20",
DATE '2019-12-01' AS "DEC'19"
)
)
However, you will need to hardcode the date values.
So, for your sample data (assuming you are storing your Month date values as dates; if not then convert the literals to strings):
CREATE TABLE data ( Id, Month, Value ) AS
SELECT 'T101', DATE '2020-02-01', 3 FROM DUAL UNION ALL
SELECT 'T101', DATE '2020-01-01', 5 FROM DUAL UNION ALL
SELECT 'T101', DATE '2020-05-01', 4 FROM DUAL UNION ALL
SELECT 'T103', DATE '2020-03-01', 7 FROM DUAL UNION ALL
SELECT 'T103', DATE '2020-12-01', 10 FROM DUAL UNION ALL
SELECT 'T103', DATE '2019-11-01', 16 FROM DUAL;
This outputs:
ID | MAY'20 | APR'20 | MAR'20 | FEB'20 | JAN'20 | DEC'19
:--- | -----: | -----: | -----: | -----: | -----: | -----:
T103 | 0 | 0 | 7 | 0 | 0 | 0
T101 | 4 | 0 | 0 | 3 | 5 | 0
db<>fiddle here

Date counts to be display in specific conditions in the stored proc like [0-6 days],[7-14 days] etc

I am creating a ssrs report and SP. so i have requirement like this below.
I have table called management in that we have a column description so the data under the
description are only 'Open' and 'Closed'.
I have parameter called User, Start Date and End Date
I need to display the user who all have the count of open cases which are falls under between the start date and
end date in the below conditions.
The conditions are
0-5 days
6-11 days
12-18 days.
For ex:
If i enter start date(MM/DD/YYYY) as 12-1-2019 and end date as 12-31-2019
So i need to display users who has the open case count between the 0-5 days,6-11 days and 12-18 days.
how about something like that?
select [0-5] = SUM(IIF(DATEDIFF(day,OpenDate, CloseDate) >= 0 and DATEDIFF(day,OpenDate, CloseDate) <= 5,1,0))
,[6-11] = SUM(IIF(DATEDIFF(day,OpenDate, CloseDate) >= 6 and DATEDIFF(day,OpenDate, CloseDate) <= 11,1,0))
,[12-18] = SUM(IIF(DATEDIFF(day,OpenDate, CloseDate) >= 12 and DATEDIFF(day,OpenDate, CloseDate) <= 18,1,0))
from tblOpenClose
With a bit of conditional aggregation.
Combined with a Cross Apply for the ranges.
SELECT t.UserId, a.DateDiffRange
, COUNT(CASE WHEN t.Description LIKE 'Open%' THEN 1 END) AS [Open]
, COUNT(CASE WHEN t.Description LIKE 'Closed%' THEN 1 END) AS [Closed]
, COUNT(*) AS [Total]
FROM management AS t
CROSS APPLY
(
SELECT
(CASE
WHEN DATEDIFF(day, t.[Start Date], t.[End Date]) BETWEEN 0 AND 5 THEN '00-05'
WHEN DATEDIFF(day, t.[Start Date], t.[End Date]) BETWEEN 6 AND 11 THEN '06-11'
WHEN DATEDIFF(day, t.[Start Date], t.[End Date]) BETWEEN 12 AND 18 THEN '12-18'
WHEN DATEDIFF(day, t.[Start Date], t.[End Date]) BETWEEN 19 AND 30 THEN '19-30'
END) AS DateDiffRange
) AS a
WHERE t.[Start Date] >= CAST('2019-12-01' AS DATE)
AND t.[End Date] BETWEEN t.[Start Date] AND EOMONTH(t.[Start Date])
GROUP BY YEAR(t.[Start Date]), MONTH(t.[Start Date]), t.UserId, a.DateDiffRange
ORDER BY t.UserId, a.DateDiffRange;
And for more metrics per user?
Check this out for inspiration:
SELECT (YEAR(t.[Start Date])*100+MONTH(t.[Start Date])) AS YearMonth, t.UserId
, SUM(CASE WHEN a.DateDiff BETWEEN 0 AND 5 THEN a.IsOpen END) AS [Opened Within 0-5]
, SUM(CASE WHEN a.DateDiff BETWEEN 6 AND 11 THEN a.IsOpen END) AS [Opened Within 6-11]
, SUM(CASE WHEN a.DateDiff BETWEEN 12 AND 18 THEN a.IsOpen END) AS [Opened Within 12-18]
, SUM(CASE WHEN a.DateDiff BETWEEN 19 AND 30 THEN a.IsOpen END) AS [Opened Within 19-30]
, SUM(CASE WHEN a.DateDiff BETWEEN 0 AND 5 THEN a.IsClosed END) AS [Closed Within 0-5]
, SUM(CASE WHEN a.DateDiff BETWEEN 6 AND 11 THEN a.IsClosed END) AS [Closed Within 6-11]
, SUM(CASE WHEN a.DateDiff BETWEEN 12 AND 18 THEN a.IsClosed END) AS [Closed Within 12-18]
, SUM(CASE WHEN a.DateDiff BETWEEN 19 AND 30 THEN a.IsClosed END) AS [Closed Within 19-30]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 1 AND 5 THEN a.IsOpen END) AS [Opened Start 1-5]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 6 AND 11 THEN a.IsOpen END) AS [Opened Start 6-11]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 12 AND 18 THEN a.IsOpen END) AS [Opened Start 12-18]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 19 AND 30 THEN a.IsOpen END) AS [Opened Start 19-31]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 1 AND 5 THEN a.IsClosed END) AS [Closed Start 0-5]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 6 AND 11 THEN a.IsClosed END) AS [Closed Start 6-11]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 12 AND 18 THEN a.IsClosed END) AS [Closed Start 12-18]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 19 AND 31 THEN a.IsClosed END) AS [Closed Start 19-31]
, COUNT(*) AS [Total]
FROM management AS t
CROSS APPLY
(
SELECT
DATEDIFF(day, t.[Start Date], t.[End Date]) AS [DateDiff],
CASE WHEN t.Description LIKE 'Open%' THEN 1 END AS [IsOpen],
CASE WHEN t.Description LIKE 'Closed%' THEN 1 END AS [IsClosed]
) AS a
WHERE t.[Start Date] >= CAST('2019-12-01' AS DATE)
AND t.[End Date] BETWEEN t.[Start Date] AND EOMONTH(t.[Start Date])
GROUP BY YEAR(t.[Start Date]), MONTH(t.[Start Date]), t.UserId
ORDER BY YearMonth, t.UserId;
YearMonth | UserId | Opened Within 0-5 | Opened Within 6-11 | Opened Within 12-18 | Opened Within 19-30 | Closed Within 0-5 | Closed Within 6-11 | Closed Within 12-18 | Closed Within 19-30 | Opened Start 1-5 | Opened Start 6-11 | Opened Start 12-18 | Opened Start 19-31 | Closed Start 0-5 | Closed Start 6-11 | Closed Start 12-18 | Closed Start 19-31 | Total
--------: | -----: | ----------------: | -----------------: | ------------------: | ------------------: | ----------------: | -----------------: | ------------------: | ------------------: | ---------------: | ----------------: | -----------------: | -----------------: | ---------------: | ----------------: | -----------------: | -----------------: | ----:
201912 | 101 | 4 | 4 | 3 | 1 | null | 1 | 3 | 1 | 10 | null | 2 | null | 5 | null | null | null | 17
201912 | 102 | 3 | 2 | null | null | null | null | null | null | 5 | null | null | null | null | null | null | null | 5
Test on db<>fiddle here

Calculate Median of a column (Days on Shelf) for different ranges of another column (Price)

I am trying to find the Median number of Carats of Gold for each day of the year. And I need to segregate these as per the price range of Gold in different columns.
The data:
Create table Daily_Gold_Rate
( S_No int, Dt datetime, Carat int, Gold_Rate numeric(18,2))
Insert into Daily_Gold_Rate values(1,'2013-01-03',18,155.00)
Insert into Daily_Gold_Rate values(2,'2013-01-03',22,190.50)
Insert into Daily_Gold_Rate values(3,'2013-01-03',24,202.23)
Insert into Daily_Gold_Rate values(4,'2013-01-03',18,400.00)
Insert into Daily_Gold_Rate values(5,'2013-01-03',22,480.50)
Insert into Daily_Gold_Rate values(6,'2013-01-03',24,671.23)
Insert into Daily_Gold_Rate values(7,'2013-01-04',18,153.00)
Insert into Daily_Gold_Rate values(8,'2013-01-04',22,191.00)
Insert into Daily_Gold_Rate values(9,'2013-01-04',24,202.25)
Insert into Daily_Gold_Rate values(10,'2013-01-04',18,351.00)
Insert into Daily_Gold_Rate values(11,'2013-01-04',22,892.00)
Insert into Daily_Gold_Rate values(12,'2013-01-04',24,1003.25)
Insert into Daily_Gold_Rate values(13,'2013-01-05',18,150.00)
Insert into Daily_Gold_Rate values(14,'2013-01-05',22,190.00)
Insert into Daily_Gold_Rate values(15,'2013-01-05',24,203.25)
Insert into Daily_Gold_Rate values(16,'2013-01-05',18,773.00)
Insert into Daily_Gold_Rate values(17,'2013-01-05',22,542.00)
Insert into Daily_Gold_Rate values(18,'2013-01-05',24,182.25)
Insert into Daily_Gold_Rate values(19,'2013-01-06',18,158.00)
Insert into Daily_Gold_Rate values(20,'2013-01-06',22,189.50)
Insert into Daily_Gold_Rate values(21,'2013-01-06',24,201.50)
Insert into Daily_Gold_Rate values(22,'2013-01-06',18,624.00)
Insert into Daily_Gold_Rate values(23,'2013-01-06',
Insert into Daily_Gold_Rate values(24,'2013-01-06',24,411.50)
Simple PERCENTILE_CONT shown below:
Select Dt, Carat, Gold_Rate, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY
Carat) OVER (PARTITION BY Carat) AS MedianCont
from Daily_Gold_Rate
order by Dt;Expected output is like this:
Returns this Data:
Dt | Carat | Gold_Rate | MedianCont
2013-01-03 00:00:00.000 | 18 | 155.00 | 18
2013-01-03 00:00:00.000 | 18 | 400.00 | 18
2013-01-03 00:00:00.000 | 22 | 480.50 | 22
2013-01-03 00:00:00.000 | 22 | 190.50 | 22
2013-01-03 00:00:00.000 | 24 | 202.23 | 24
2013-01-03 00:00:00.000 | 24 | 671.23 | 24
2013-01-04 00:00:00.000 | 24 | 202.25 | 24
2013-01-04 00:00:00.000 | 24 | 1003.25 | 24
2013-01-04 00:00:00.000 | 18 | 153.00 | 18
2013-01-04 00:00:00.000 | 18 | 351.00 | 18
2013-01-04 00:00:00.000 | 22 | 892.00 | 22
2013-01-04 00:00:00.000 | 22 | 191.00 | 22
2013-01-05 00:00:00.000 | 22 | 542.00 | 22
2013-01-05 00:00:00.000 | 22 | 190.00 | 22
2013-01-05 00:00:00.000 | 18 | 150.00 | 18
2013-01-05 00:00:00.000 | 18 | 773.00 | 18
2013-01-05 00:00:00.000 | 24 | 203.25 | 24
2013-01-05 00:00:00.000 | 24 | 182.25 | 24
2013-01-06 00:00:00.000 | 24 | 201.50 | 24
2013-01-06 00:00:00.000 | 24 | 411.50 | 24
2013-01-06 00:00:00.000 | 18 | 158.00 | 18
2013-01-06 00:00:00.000 | 18 | 624.00 | 18
2013-01-06 00:00:00.000 | 22 | 735.50 | 22
2013-01-06 00:00:00.000 | 22 | 189.50 | 22
I need to pivot on Gold Price Range. So, I am trying through this query:
with a as (
select year(Dt) as "year", month(Dt) as "month", day(Dt) as "day",
case when Gold_Rate / 200 < 5 then Gold_Rate / 200 else 5 end as
price_bucket,
PERCENTILE_CONT(.50) WITHIN GROUP (ORDER BY Carat) over (PARTITION BY
day(Dt), month(Dt)) as MED_days
from Daily_Gold_Rate
group by year(Dt), month(Dt), day(Dt), Gold_Rate / 200, Carat)
select "year", "month", "day",
[1] as "less than 400", [2] as "400-599", [3] as "600-799", [4] as "800-
999", [5] as "Over 1000"
from a pivot (max(MED_days) for price_bucket in ([1], [2], [3], [4], [5])) p
order by "year", "month", "day";
But, this is what I am getting, instead. :(
Year | Month | Day | 1-399 | 400-599 | 600-799| 800-999| Over 1000
2013 | 1 | 3 | NULL | 22 | NULL | NULL | NULL
2013 | 1 | 4 | NULL | NULL | NULL | NULL | 22
2013 | 1 | 5 | NULL | NULL | NULL | NULL | NULL
2013 | 1 | 6 | NULL | NULL | NULL | NULL | NULL
Pivoting before the percentile calculation:
select distinct
dt
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ratelt400) OVER (PARTITION BY dt) ratelt400
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ratebtwn400599) OVER (PARTITION BY dt) ratebtwn400599
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ratebtwn600799) OVER (PARTITION BY dt) ratebtwn600799
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ratebtwn800999) OVER (PARTITION BY dt) ratebtwn800999
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY rateovr1000) OVER (PARTITION BY dt) rateovr1000
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY caratlt400) OVER (PARTITION BY dt) caratlt400
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY caratbtwn400599) OVER (PARTITION BY dt) caratbtwn400599
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY caratbtwn600799) OVER (PARTITION BY dt) caratbtwn600799
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY caratbtwn800999) OVER (PARTITION BY dt) caratbtwn800999
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY caratovr1000) OVER (PARTITION BY dt) caratovr1000
from (
SELECT
DATEADD(day, DATEDIFF(day, 0, dt), 0) dt
, CASE WHEN Gold_Rate < 400 THEN Gold_Rate END ratelt400
, CASE WHEN Gold_Rate BETWEEN 400 AND 599 THEN Gold_Rate END ratebtwn400599
, CASE WHEN Gold_Rate BETWEEN 600 AND 799 THEN Gold_Rate END ratebtwn600799
, CASE WHEN Gold_Rate BETWEEN 800 AND 999 THEN Gold_Rate END ratebtwn800999
, CASE WHEN Gold_Rate >= 1000 THEN Gold_Rate END rateovr1000
, CASE WHEN Gold_Rate < 400 THEN carat END caratlt400
, CASE WHEN Gold_Rate BETWEEN 400 AND 599 THEN carat END caratbtwn400599
, CASE WHEN Gold_Rate BETWEEN 600 AND 799 THEN carat END caratbtwn600799
, CASE WHEN Gold_Rate BETWEEN 800 AND 999 THEN carat END caratbtwn800999
, CASE WHEN Gold_Rate >= 1000 THEN carat END caratovr1000
FROM Daily_Gold_Rate
) d
GO
dt | ratelt400 | ratebtwn400599 | ratebtwn600799 | ratebtwn800999 | rateovr1000 | caratlt400 | caratbtwn400599 | caratbtwn600799 | caratbtwn800999 | caratovr1000
:------------------ | --------: | -------------: | -------------: | -------------: | ----------: | ---------: | --------------: | --------------: | --------------: | -----------:
03/01/2013 00:00:00 | 190.5 | 440.25 | 671.23 | null | null | 22 | 20 | 24 | null | null
04/01/2013 00:00:00 | 196.625 | null | null | 892 | 1003.25 | 20 | null | null | 22 | 24
05/01/2013 00:00:00 | 186.125 | 542 | 773 | null | null | 23 | 22 | 18 | null | null
06/01/2013 00:00:00 | 189.5 | 411.5 | 624 | null | null | 22 | 24 | 18 | null | null
dbfiddle here
Below are some working queries for values by either carats or rates:
revised answer:
Rates by Day
SELECT DISTINCT
DATEADD(day, DATEDIFF(day, 0, dt), 0) dt
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate < 400 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) lt400
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate BETWEEN 400 AND 599 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) btwn400599
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate BETWEEN 600 AND 799 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) btwn600799
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate BETWEEN 800 AND 999 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) btwn800999
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate >= 1000 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) ovr1000
FROM Daily_Gold_Rate
GO
dt | lt400 | btwn400599 | btwn600799 | btwn800999 | ovr1000
:------------------ | ------: | ---------: | ---------: | ---------: | ------:
03/01/2013 00:00:00 | 190.5 | 440.25 | 671.23 | null | null
04/01/2013 00:00:00 | 196.625 | null | null | 892 | 1003.25
05/01/2013 00:00:00 | 186.125 | 542 | 773 | null | null
06/01/2013 00:00:00 | 189.5 | 411.5 | 624 | null | null
Carats by Day
SELECT DISTINCT
DATEADD(day, DATEDIFF(day, 0, dt), 0) dt
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate < 400 THEN carat END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) lt400
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate BETWEEN 400 AND 599 THEN carat END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) btwn400599
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate BETWEEN 600 AND 799 THEN carat END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) btwn600799
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate BETWEEN 800 AND 999 THEN carat END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) btwn800999
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate >= 1000 THEN carat END) OVER (PARTITION BY DATEADD(day, DATEDIFF(day, 0, dt), 0)) ovr1000
FROM Daily_Gold_Rate
GO
dt | lt400 | btwn400599 | btwn600799 | btwn800999 | ovr1000
:------------------ | ----: | ---------: | ---------: | ---------: | ------:
03/01/2013 00:00:00 | 22 | 20 | 24 | null | null
04/01/2013 00:00:00 | 20 | null | null | 22 | 24
05/01/2013 00:00:00 | 23 | 22 | 18 | null | null
06/01/2013 00:00:00 | 22 | 24 | 18 | null | null
dbfiddle here
By Month: FYI only
SELECT DISTINCT
DATEADD(MONTH, DATEDIFF(MONTH, 0, dt), 0) dt
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate < 400 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(MONTH, DATEDIFF(MONTH, 0, dt), 0)) lt400
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate BETWEEN 400 AND 599 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(MONTH, DATEDIFF(MONTH, 0, dt), 0)) btwn400599
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate BETWEEN 600 AND 799 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(MONTH, DATEDIFF(MONTH, 0, dt), 0)) btwn600799
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate BETWEEN 800 AND 999 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(MONTH, DATEDIFF(MONTH, 0, dt), 0)) btwn800999
, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Gold_Rate >= 1000 THEN Gold_Rate END) OVER (PARTITION BY DATEADD(MONTH, DATEDIFF(MONTH, 0, dt), 0)) ovr1000
FROM Daily_Gold_Rate
GO
dt | lt400 | btwn400599 | btwn600799 | btwn800999 | ovr1000
:------------------ | -----: | ---------: | ---------: | ---------: | ------:
01/01/2013 00:00:00 | 190.25 | 446 | 671.23 | 892 | 1003.25
dbfiddle here

Grouping SQL columns from one table

I am currently having difficulty getting the correct values from my table. Here is my table
NOTE: The column Status has 3 possible values (Cleaned, Unclean, Closed)
+-----------+-------------+--------+------------+
|ApplicantID|ApplicantName| Status | HireDate |
+-----------+-------------+--------+------------+
| 1 | John Smith |Cleaned |08/26/2015 |
| 2 | Alex Murphy |Closed |09/12/2015 |
| 3 | Oliver David|Cleaned |01/11/2015 |
| 4 | Max Payne |Unclean |03/18/2015 |
+-----------+-------------+--------+------------+
The output I'm expecting and it should also be sorted by year.
For example I call all these records for the year 2015 which I get using the variable #Year.
NOTE: The column Total is the SUM of Cleaned and Unclean
+---------+-----------+-----------+----------+---------+
| Month | Cleaned | Unclean | Closed | Total |
+---------+-----------+-----------+----------+---------+
| January| 1 | 0 | 0 | 1 |
| February| 0 | 0 | 0 | 0 |
| March | 0 | 1 | 0 | 1 |
| April | 0 | 0 | 0 | 0 |
| May | 0 | 0 | 0 | 0 |
| June | 0 | 0 | 0 | 0 |
| July | 0 | 0 | 0 | 0 |
| August | 1 | 0 | 0 | 1 |
|September| 0 | 0 | 1 | 0 |
| October| 0 | 0 | 0 | 0 |
| November| 0 | 0 | 0 | 0 |
| December| 0 | 0 | 0 | 0 |
+---------+-----------+-----------+----------+---------+
I can't seem to get the right code, for the sql this is my current code.
SELECT Month(HireDate) AS Month, COUNT(*)
FROM Hires
GROUP BY Month(HireDate)
I know my coding is wrong, because it is incomplete.
Generate a list of numbers from 1 to 12 first to hold all months. Then do a LEFT JOIN on Hires to make sure all missing months are accounted for. Then use conditional aggregation for the totals:
SQL Fiddle
;WITH CteMonths AS(
SELECT * FROM(VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
)t(N)
)
SELECT
Month = DATENAME(MONTH, DATEADD(MONTH, N-1,0)),
Cleaned = SUM(CASE WHEN h.Status = 'Cleaned' THEN 1 ELSE 0 END),
Closed = SUM(CASE WHEN h.Status = 'Closed' THEN 1 ELSE 0 END),
Unclean = SUM(CASE WHEN h.Status = 'Unclean' THEN 1 ELSE 0 END),
Total = SUM(CASE WHEN h.Status IN('Cleaned', 'Unclean') THEN 1 ELSE 0 END)
FROM CteMonths m
LEFT JOIN Hires h
ON m.N = MONTH(h.HireDate)
--AND YEAR(h.HireDate) = #year --uncomment this line to filter for year.
GROUP BY m.N
ORDER BY m.N
If you want to include the YEAR:
SQL Fiddle
;WITH CteMonths AS(
SELECT * FROM(VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
)t(N)
),
CteYears(yr) AS(
SELECT DISTINCT YEAR(HireDate) FROM Hires
),
CteAllDates(dt) AS(
SELECT
DATEADD(MONTH, m.N - 1, DATEADD(YEAR, y.yr - 1900, 0))
FROM CteMonths m
CROSS JOIN CteYears y
)
SELECT
Year = YEAR(d.dt),
Month = DATENAME(MONTH, d.dt),
Cleaned = SUM(CASE WHEN h.Status = 'Cleaned' THEN 1 ELSE 0 END),
Closed = SUM(CASE WHEN h.Status = 'Closed' THEN 1 ELSE 0 END),
Unclean = SUM(CASE WHEN h.Status = 'Unclean' THEN 1 ELSE 0 END),
Total = SUM(CASE WHEN h.Status IN('Cleaned', 'Unclean') THEN 1 ELSE 0 END)
FROM CteAllDates d
LEFT JOIN Hires h
ON MONTH(d.dt) = MONTH(h.HireDate)
AND YEAR(d.dt) = YEAR(h.HireDate)
GROUP BY YEAR(d.dt), MONTH(d.dt), DATENAME(MONTH, d.dt)
ORDER BY YEAR(d.dt), MONTH(d.dt)
If you want to filter for year, say #year = 2015, you can replace the previous ctes with:
;WITH CteMonths AS(
SELECT * FROM(VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
)t(N)
),
CteAllDates(dt) AS(
SELECT
DATEADD(MONTH, m.N - 1, DATEADD(YEAR, #year - 1900, 0))
FROM CteMonths m
)...
I suggest to create TEMP table with values from 1 to 12 (numbers of months) and JOIN your table with TEMP table. To achieve values as columns names you can use PIVOT or CASE. You can do It in following:
INSERT INTO #Months VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
SELECT DATENAME(MONTH, DATEADD(MONTH, m.Id-1, 0)) AS [Month]
, SUM(CASE WHEN [Status] = 'Cleaned' THEN 1 ELSE 0 END) AS [Cleaned]
, SUM(CASE WHEN [Status] = 'Closed' THEN 1 ELSE 0 END ) AS [Closed]
, SUM(CASE WHEN [Status] = 'Unclean' THEN 1 ELSE 0 END) AS [Unclean]
, SUM(CASE WHEN [Status] IN ('Unclean', 'Cleaned') THEN 1 ELSE 0 END) AS [Total]
FROM #Test t
RIGHT JOIN #Months m ON m.Id = MONTH(t.HireDate)
GROUP BY m.Id
OUTPUT
+---------+-----------+-----------+----------+---------+
| Month | Cleaned | Unclean | Closed | Total |
+---------+-----------+-----------+----------+---------+
| January | 1 | 0 | 0 | 1 |
| February| 0 | 0 | 0 | 0 |
| March | 0 | 1 | 0 | 1 |
| April | 0 | 0 | 0 | 0 |
| May | 0 | 0 | 0 | 0 |
| June | 0 | 0 | 0 | 0 |
| July | 0 | 0 | 0 | 0 |
| August | 1 | 0 | 0 | 1 |
|September| 0 | 0 | 1 | 0 |
| October | 0 | 0 | 0 | 0 |
| November| 0 | 0 | 0 | 0 |
| December| 0 | 0 | 0 | 0 |
+---------+-----------+-----------+----------+---------+
DEMO
You can test It at: SQL FIDDLE

Resources