Get months between two dates in TSQL - sql

I have a function that returns the following:
Title Start End
Task A 2015-01-02 2015-03-31
Task B 2015-02-12 2015-04-01
Task C 2014-11-01 2015-02-05
....
I want to return a column for each month and 1 if its within the Start and End period 0 otherwise
Title Start End Jan Feb Mar Apr May Jun ....
Task A 2015-01-02 2015-03-31 1 1 1 0 0 0
Task B 2015-02-12 2015-04-01 0 1 1 1 0 0
Task C 2014-11-01 2015-02-05 1 1 0 0 0 0
....
Anyone have an idea on how to do this?

You would do this with basic case statements:
select title, start, end,
(case when 1 between month(start) and month(end) then 1 else 0 end) as jan,
(case when 2 between month(start) and month(end) then 1 else 0 end) as feb,
. . .
(case when 12 between month(start) and month(end) then 1 else 0 end) as dec
from table t;
Note: I am leaving your column names as in the query, even though some are reserved words and should be escaped (if that is the real name of the columns).
Also note that in your sample data, the dates change between the first table and the second.

If you only wanted to check 1 date, this would work. You should be able to adapt this sample to meet your needs.
SELECT c.CreateDateUTC, DATEPART(MONTH, c.CreateDateUTC) 'MONTH',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 1 THEN 1
END 'JAN',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 2 THEN 1
END 'FEB',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 3 THEN 1
END 'MAR',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 4 THEN 1
END 'APR',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 5 THEN 1
END 'MAY',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 6 THEN 1
END 'JUN',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 7 THEN 1
END 'JUL',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 8 THEN 1
END 'AUG',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 9 THEN 1
END 'SEP',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 10 THEN 1
END 'OCT',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 11 THEN 1
END 'NOV',
CASE DATEPART(MONTH, c.CreateDateUTC)
WHEN 12 THEN 1
END 'DEC'
FROM dbo.Code c
Result:

To expand, make sure you check for null, and you can use ISNULL(StartDate,GetDate()) which will give you today if that fits your range needs.
select *,
case when StartDate is not null and EndDate is not null and 1 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Jan,
case when StartDate is not null and EndDate is not null and 2 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Feb,
case when StartDate is not null and EndDate is not null and 3 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Mar,
case when StartDate is not null and EndDate is not null and 4 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Apr,
case when StartDate is not null and EndDate is not null and 5 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end May,
case when StartDate is not null and EndDate is not null and 6 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Jun,
case when StartDate is not null and EndDate is not null and 7 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Jul,
case when StartDate is not null and EndDate is not null and 8 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Aug,
case when StartDate is not null and EndDate is not null and 9 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Sep,
case when StartDate is not null and EndDate is not null and 10 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Oct,
case when StartDate is not null and EndDate is not null and 11 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Nov,
case when StartDate is not null and EndDate is not null and 12 between MONTH(StartDate) and Month(EndDate) then 1 else 0 end Dec
from Foo

Related

Sum of particular column with month and year with fiscal year from custom date

I have following data in my table:
uniqueId d_date amount
1 2018-02-01 100.25
2 2019-03-01 456.5
3 2018-02-01 455
4 2019-05-01 200.48
5 2018-06-01 100
6 2019-07-01 200
7 2018-12-01 6950
8 2019-02-01 60
9 2020-01-20 100
Now when I enter start date = '2018-03-12' then my fiscal year must start with march 2018 to feb 2019 and so on.
If i enter start date = '2019-05-12' then my fiscal year must start with May 2019 to April 2020
I have tried below query but it is not working properly and also it calculate past year which is 2017 I do not want any data from past year from my entered custom date. So if entered start date = '2018-03-12' then is must start calculation for 2018 and above years only. No past year.
Declare #startdate as date
Declare #monthDate as int
Declare #ownmonth as int
set #startdate = '2018-03-12'
set #monthDate = month(#startdate)
set #ownmonth = 1
select
year(dateadd(month, -#monthDate, d_date)) year,
sum(case when month(d_date) = case when #monthDate+1 > 12 then #ownmonth else #monthDate+1 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+2 > 12 then #ownmonth+1 else #monthDate+2 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+3 > 12 then #ownmonth+2 else #monthDate+3 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+4 > 12 then #ownmonth+3 else #monthDate+4 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+5 > 12 then #ownmonth+4 else #monthDate+5 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+6 > 12 then #ownmonth+5 else #monthDate+6 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+7 > 12 then #ownmonth+6 else #monthDate+7 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+8 > 12 then #ownmonth+7 else #monthDate+8 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+9 > 12 then #ownmonth+8 else #monthDate+9 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+10 > 12 then #ownmonth+9 else #monthDate+10 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+11 > 12 then #ownmonth+10 else #monthDate+11 End then amount end) ,
sum(case when month(d_date) = case when #monthDate+12 > 12 then #ownmonth+11 else #monthDate+12 End then amount end) ,
sum(amount) total
from mytable
group by year(dateadd(month, -#monthDate, amount))
order by year
But above query does not show proper year & month wise data
Now I want output with fiscal year calculation:
Year Mar Apr May Jun July Aug Sept Oct Nov Dec Jan Feb Total
2018 - - - 100 - - - - - 6950 - 60 7110
2019 456.5 - 200.48 - 200 - - - - - 100 - 956.98
I can not use PIVOT as it is not supported in my compact SQL Server version.
How can I do this?
Your rule for a fiscal year is the year's March until the following year's February:
date | fiscal year
... | ...
2018-02-28 | 2017
2018-03-01 | 2018
... | 2018
2019-02-28 | 2018
2019-03-01 | 2019
... | ...
That means when we subtract two months from a date, we get a date the year of which is the fiscal year:
date | date - 2 months | fiscal year
... | ... | ...
2018-02-28 | 2017-12-28 | 2017
2018-03-01 | 2018-01-01 | 2018
... | ... | 2018
2019-02-28 | 2018-12-28 | 2018
2019-03-01 | 2019-01-01 | 2019
... | ... | ...
select
year(dateadd(month, -2, d_date)) as fiscal_year,
sum(case when month(d_date) = 3 then amount else 0 end) as mar,
sum(case when month(d_date) = 4 then amount else 0 end) as apr,
sum(case when month(d_date) = 5 then amount else 0 end) as may,
sum(case when month(d_date) = 6 then amount else 0 end) as jun,
sum(case when month(d_date) = 7 then amount else 0 end) as jul,
sum(case when month(d_date) = 8 then amount else 0 end) as aug,
sum(case when month(d_date) = 9 then amount else 0 end) as sep,
sum(case when month(d_date) = 10 then amount else 0 end) as oct,
sum(case when month(d_date) = 11 then amount else 0 end) as nov,
sum(case when month(d_date) = 12 then amount else 0 end) as dec,
sum(case when month(d_date) = 1 then amount else 0 end) as jan,
sum(case when month(d_date) = 2 then amount else 0 end) as feb,
sum(amount) as total
from mytable
group by year(dateadd(month, -2, d_date))
order by year(dateadd(month, -2, d_date));
If you want to limit this to the fiscal year a given date resides in, add:
where year(dateadd(month, -2, d_date)) = year(dateadd(month, -2, #given_date))
And well, if you want to limit this to the fiscal years beginning with that year, that would of course be:
where year(dateadd(month, -2, d_date)) >= year(dateadd(month, -2, #given_date))
UPDATE: You want a fiscal year to start with the first day of the month of a given date. I.e. If the given date is 1990-04-23, then a fiscal year starts with April. This changes above query only slightly, because rather than subtracting 2 months (for March), we must generalize this to subtracting one month less than the given month.
I am using a modulo operation when comparing months in order not to end up with months 13, 14, etc.
select
year(dateadd(month, - month(#startdate) + 1, d_date)) as fiscal_year,
sum(case when month(d_date) = (month(#startdate) + 0) % 12 then amount else 0 end) as first,
sum(case when month(d_date) = (month(#startdate) + 1) % 12 then amount else 0 end) as second,
sum(case when month(d_date) = (month(#startdate) + 2) % 12 then amount else 0 end) as third,
sum(case when month(d_date) = (month(#startdate) + 3) % 12 then amount else 0 end) as fourth,
sum(case when month(d_date) = (month(#startdate) + 4) % 12 then amount else 0 end) as fith,
sum(case when month(d_date) = (month(#startdate) + 5) % 12 then amount else 0 end) as sixth,
sum(case when month(d_date) = (month(#startdate) + 6) % 12 then amount else 0 end) as seventh,
sum(case when month(d_date) = (month(#startdate) + 7) % 12 then amount else 0 end) as eighth,
sum(case when month(d_date) = (month(#startdate) + 8) % 12 then amount else 0 end) as nineth,
sum(case when month(d_date) = (month(#startdate) + 9) % 12 then amount else 0 end) as tenth,
sum(case when month(d_date) = (month(#startdate) + 10) % 12 then amount else 0 end) as eleventh,
sum(case when month(d_date) = (month(#startdate) + 11) % 12 then amount else 0 end) as twelfth,
sum(amount) as total
from mytable
group by year(dateadd(month, - month(#startdate) + 1, d_date))
order by year(dateadd(month, - month(#startdate) + 1, d_date));
And again, if we want our results start from the fiscal year of the given date, we'd add:
where year(dateadd(month, - month(#startdate) + 1, d_date)) >= year(#startdate)

SQL Server : how to group by value, multiple columns for n days

I couldn't find a solution for this and also my SQL skills are very poor, so maybe someone can advise if the following is possible.
Environment: Microsoft SQL Server 2008 R2
The current query is very simple, selecting the values of error codes, counting the number of errors and grouping on the error codes:
EC - ErrorCode (there are arround 200 different error codes)
NoEr - count(*) as NoEr (some days the error count can be empty)
Query:
SELECT
ErrorCode AS EC, COUNT(*) as NoEr
FROM
[DB].[dbo].[Table]
WHERE
ERRORTIME > '2018-12-30 00:00:00'
AND ERRORTIME < '2018-12-30 23:59:59'
GROUP BY
errorcode
ORDER BY
ERRORCODE ASC
Output:
+----+-------+
| EC | NoEr |
+----+-------+
| A9 | 3333 |
| E0 | 1505 |
| G9 | 1233 |
| X1 | 2 |
+----+-------+
I would like to obtain the count of errors for the last 5 days displayed as per below:
+----+-------+-------+-------+-------+-------+
| EC | MON | TUE | WED | THU | FRI |
+----+-------+-------+-------+-------+-------+
| A9 | 1505 | 2333 | | 1555 | 9999 |
| E0 | 3333 | | 2311 | 5555 | 14 |
| G9 | 2222 | 1505 | 123 | 1233 | |
| X1 | 1212 | 1233 | 1155 | 3 | |
+----+-------+-------+-------+-------+-------+
Thank you & have a great new year !
You can us CASE expression along with aggregate SUM to calculate the count for each weekday like below -
Select
ErrorCode as EC,
SUM(CASE WHEN Datename(w, ErrorTime) = 'Monday' THEN 1 ELSE 0 END) as MON,
SUM(CASE WHEN Datename(w, ErrorTime) = 'Tuesday' THEN 1 ELSE 0 END) as TUE,
SUM(CASE WHEN Datename(w, ErrorTime) = 'Wednesday' THEN 1 ELSE 0 END) as WED,
SUM(CASE WHEN Datename(w, ErrorTime) = 'Thursday' THEN 1 ELSE 0 END) as THU,
SUM(CASE WHEN Datename(w, ErrorTime) = 'Friday' THEN 1 ELSE 0 END) as FRI
From
[DB].[dbo].[Table]
where
ERRORTIME > '2018-12-30 00:00:00' and ERRORTIME < '2018-12-30 23:59:59'
group by errorcode
order by ERRORCODE ASC
You could use pivot operator to achieve your goal.
SELECT
EC,[MON],[TUE],[WED],[THU],[FRI]
FROM
(
SELECT
ErrorCode AS EC,UPPER(LEFT(DATENAME(DW,ERRORTIME),3)) AS D_W, 1 AS NUMBER FROM [DB].[dbo].[Table]
WHERE DATEDIFF(DAY,ERRORTIME,GETDATE())<=5
) SRC
PIVOT
(
SUM(NUMBER) FOR D_W IN ([MON],[TUE],[WED],[THU],[FRI])
) PVT
Best Regards,
Will
Like Will he said the best option is to use the PIVOT:
SELECT
*
FROM
(
SELECT
ErrorCode AS EC,
UPPER(LEFT(DATENAME(DW, ERRORTIME), 3)) AS DayW,
1 AS Number
FROM
table_name
WHERE
ERRORTIME > = DATEADD(day, -5, GetDate())
) AS Source PIVOT(SUM(Number) FOR DayW IN(
[MON],
[TUE],
[WED],
[THU],
[FRI])) PVT
You want the results for the last five days, not for a single day, so I think you want:
SELECT ErrorCode as EC,
SUM(CASE WHEN datename(weekday, ErrorTime) = 'Monday' THEN 1 ELSE 0 END) as MON,
SUM(CASE WHEN datename(weekday, ErrorTime) = 'Tuesday' THEN 1 ELSE 0 END) as TUE,
SUM(CASE WHEN datename(weekday, ErrorTime) = 'Wednesday' THEN 1 ELSE 0 END) as WED,
SUM(CASE WHEN datename(weekday, ErrorTime) = 'Thursday' THEN 1 ELSE 0 END) as THU,
SUM(CASE WHEN datename(weekday, ErrorTime) = 'Friday' THEN 1 ELSE 0 END) as FRI
FROM [DB].[dbo].[Table] t
WHERE ERROR_TIME >= DATEADD(DAY, -5, CAST(GETDATE() as DATE)) AND
ERROR_TIME >= CAST(GETDATE() as DATE)
GROUP BY errorcode
ORDER BY ERRORCODE ASC;
Note that when you use functions such as DATEADD() and DATENAME() you should not use abbreviations. That is just a bad query-writing habit. No one want to have to remember whether w means "week" or "weekday" or whether m means "minute" or "month". Use the full name and eschew ambiguity.
If you like you can also simplify this to:
SELECT ErrorCode as EC,
SUM(CASE WHEN ErrorTime_weekday = 'Monday' THEN 1 ELSE 0 END) as MON,
SUM(CASE WHEN ErrorTime_weekday = 'Tuesday' THEN 1 ELSE 0 END) as TUE,
SUM(CASE WHEN ErrorTime_weekday = 'Wednesday' THEN 1 ELSE 0 END) as WED,
SUM(CASE WHEN ErrorTime_weekday = 'Thursday' THEN 1 ELSE 0 END) as THU,
SUM(CASE WHEN ErrorTime_weekday = 'Friday' THEN 1 ELSE 0 END) as FRI
FROM [DB].[dbo].[Table] t CROSS APPLY
(VALUES (datename(weekday, ErrorTime) = 'Thursday' THEN 1 ELSE 0 END))
) v(ErrorTime_weekday)
WHERE ERROR_TIME >= DATEADD(DAY, -5, CAST(GETDATE() as DATE)) AND
ERROR_TIME >= CAST(GETDATE() as DATE)
GROUP BY errorcode
ORDER BY ERRORCODE ASC;

Group by day from a certain hour of the day

SQLServer 2008r2. I have a table which is populated with a record at 10 mins past every hour of every day. Every hour the job is run it also enters 48 records which represent a forecast of what is likely to happen for the next 48 hours. Note - Just before it enters the 48 hour forecast it deletes the forecast which was entered last time. So although it enters a 48 hour forecast every hour there is only ever one forecast in the system. The relevant fields in the table look like this:
currentScore obsDate
9 2017-06-22 08:10:00
9 2017-06-22 07:10:00
9 2017-06-22 06:10:00
10 2017-06-22 05:10:00
... ...
How can I query this table and group by day from a certain time of day? I would like the day to start at 6am the day before and finish at 6am on the day. I only need five records from the table, the day, two before and two in the future. So if its Jun 20 I want June 18, 19, 20, 21 and 22. Here is the query which gets the correct results by calendar day.
SELECT cast(obsDate AS DATE) AS theDate
,sum(CASE
WHEN currentScore < 8
THEN 1
ELSE 0
END) AS currentscore_low
,sum(CASE
WHEN currentScore >= 8
AND currentScore < 17
THEN 1
ELSE 0
END) AS currentscore_medium
,sum(CASE
WHEN currentScore >= 17
THEN 1
ELSE 0
END) AS currentscore_high
FROM diseaseScores
WHERE siteID = 8315
AND obsDate >= cast(getdate() - 2 AS DATE)
GROUP BY cast(obsDate AS DATE)
ORDER BY cast(obsDate AS DATE);
which returns this result:
theDAte low med high
2017-06-18 23 0 0
2017-06-19 22 0 0
2017-06-20 5 19 0
2017-06-21 0 24 0
2017-06-22 0 9 0
There is a new requirement to get the same result but the group by and the subsequent counts need to be from 6am to 6am. e.g
the first rec should be from 2017-06-17 06:00am to 2017-06-18 06:00am
the second rec should be from 2017-06-18 06:00am to 2017-06-19 06:00am
....etc
How can I do this? Thanks in advance
UPDATE, I have done two things:
1..introduce Tims idea
2..I also add an extra field 'numOfScores' to show how many hours worth of data
each line represent
select
cast(dateadd(hour, -6, obsDate) as date) as theDate, count(currentScore) as numOfScores,
sum(case when currentScore < 8 then 1 else 0 end) as currentscore_low,
sum(case when currentScore >= 8 and currentScore < 17
then 1 else 0 end) as currentscore_medium,
sum(case when currentScore >= 17 then 1 else 0 end) as currentscore_high
from diseaseScores
where siteID = 8315 and
obsDate >= cast(getdate() - 2 as date)
group by cast(dateadd(hour, -6, obsDate) as date)
order by cast(dateadd(hour, -6, obsDate) as date);
I now get this result:
2017-06-18 5 5 0 0
2017-06-19 24 23 1 0
2017-06-20 24 1 23 0
2017-06-21 24 8 16 0
2017-06-22 24 1 23 0
2017-06-23 9 0 9 0
This tells me that that there is only 5 hours worth of scores on the 2017-06-18. I want this first line to be 24 hours worth. From 6am on the 17th until 6am on the 18th. This makes me think I am not getting the result I wish
The 23rd only having 9 hours is ok because this is the most recent forecast
UPDATED:
I dont think its easily done in one query (if even possible) so I will just use five queries and specifically state the dates&times to get my outcome. e.g here are the first two:
select
sum(case when currentScore < 9 then 1 else 0 end) as numOfLOWRecs,
sum(case when currentScore > 8 and currentScore < 17 then 1 else 0 end) as currentscore_medium,
sum(case when currentScore >= 17 then 1 else 0 end) as currentscore_high
from diseaseScores where siteID = 9999
and obsDate >= '2017-06-18 06:00' and obsDate < '2017-06-19 06:00'
select
sum(case when currentScore < 9 then 1 else 0 end) as numOfLOWRecs,
sum(case when currentScore > 8 and currentScore < 17 then 1 else 0 end) as currentscore_medium,
sum(case when currentScore >= 17 then 1 else 0 end) as currentscore_high
from diseaseScores where siteID = 9999
and obsDate >= '2017-06-19 06:00' and obsDate < '2017-06-20 06:00'
One trick which might work here would be to simply shift each observation backwards by 6 hours. This would shift 2017-06-17 06:00:00 to 2017-06-17 00:00:00, i.e. now 6am becomes the start of that actual day.
select
cast(dateadd(hour, -6, obsDate) as date) as theDate,
sum(case when currentScore < 8 then 1 else 0 end) as currentscore_low,
sum(case when currentScore >= 8 and currentScore < 17
then 1 else 0 end) as currentscore_medium,
sum(case when currentScore >= 17 then 1 else 0 end) as currentscore_high
from diseaseScores
where siteID = 8315 and
obsDate >= cast(getdate() - 2 as date)
group by cast(dateadd(hour, -6, obsDate) as date)
order by cast(dateadd(hour, -6, obsDate) as date);

SQL query to count incidents by year by month

I have one table called Incidents. I want a SQL query that returns the count of incidents split out by year, by month. The start year is 2010, however, the end year will be variable.
Example Incidents table:
DateLogged IncidentRef
----------- ------------
2015-04-05 1
2014-06-04 2
2013-01-01 3
2012-12-10 4
2011-10-15 5
2010-10-01 6
2012-12-11 7
2011-10-10 8
2010-10-10 9
Query Returns:
Year Jan Fev Mar Abr Mai Jun Jul Ago Set Out Nov Dez
2010 0 0 0 0 0 0 0 0 0 2 0 0
2011 0 0 0 0 0 0 0 0 0 2 0 0
2012 0 0 0 0 0 0 0 0 0 0 0 2
2013 1 0 0 0 0 0 0 0 0 0 0 0
2014 0 0 0 0 0 1 0 0 0 0 0 0
2015 0 0 0 1 0 0 0 0 0 0 0 0
How can I do that query? Where do I start?
One option is to use conditional aggregation:
select year(datelogged),
sum(case when month(datelogged) = 1 then 1 else 0 end) Jan,
sum(case when month(datelogged) = 2 then 1 else 0 end) Feb,
...,
sum(case when month(datelogged) = 12 then 1 else 0 end) Dec
from yourtable
group by year(datelogged)
SQL Fiddle Demo
With pivoting:
;with cte as(select year(date) y, month(date) m, ref from table)
select * from cte
pivot(count(ref) for m in([1],[2],...,[12]))p
Another way to do without a pivot you could use a join:
with years as
(
SELECT 2010 as y
UNION ALL
SELECT 2011
UNION ALL
SELECT 2012
UNION ALL
SELECT 2013
UNION ALL
SELECT 2014
UNION ALL
SELECT 2015
)
select years.y,
sum(case when month(DateLogged) = 1 then 1 else 0) as jan,
sum(case when month(DateLogged) = 2 then 1 else 0) as feb,
sum(case when month(DateLogged) = 3 then 1 else 0) as mar,
sum(case when month(DateLogged) = 4 then 1 else 0) as apr,
-- ...
sum(case when month(DateLogged) = 12 then 1 else 0) as dec,
from years y
left join incidents i on y.y = year(i.DateLogged)
group by y.DateLogged
If you want year to be "dynamic" you have the CTE like this
with years as
(
SELECT DISTINCT year(i.DateLogged) FROM incidents
)
but this has the same drawback as the sgeddes solution -- years with no values don't show up.
Using classic PIVOT:
Data:
CREATE TABLE #Incidents(
DateLogged DATE NOT NULL PRIMARY KEY
,IncidentRef INTEGER NOT NULL );
INSERT INTO #Incidents(DateLogged,IncidentRef) VALUES
('2015-04-05',1),('2014-06-04',2),('2013-01-01',3),
('2012-12-10',4),('2011-10-15',5),('2010-10-01',6),
('2012-12-11',7),('2011-10-10',8),('2010-10-10',9);
Query:
;WITH cte AS
(
SELECT [year] = YEAR(DateLogged),
[month] = CASE MONTH(DateLogged)
WHEN 1 THEN 'Jan' WHEN 2 THEN 'Fev'
WHEN 3 THEN 'Mar' WHEN 4 THEN 'Abr'
WHEN 5 THEN 'Mai' WHEN 6 THEN 'Jun'
WHEN 7 THEN 'Jul' WHEN 8 THEN 'Ago'
WHEN 9 THEN 'Set' WHEN 10 THEN 'Out'
WHEN 11 THEN 'Nov' WHEN 12 THEN 'Dez'
END,
IncidentRef
FROM #Incidents
)
SELECT [Year],Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, [Set], Out, Nov, Dez
FROM cte
PIVOT (
COUNT(IncidentRef)
FOR [month] IN (Jan, Fev, Mar, Abr, Mai, Jun,Jul, Ago, [Set], Out, Nov,Dez)
) AS piv;
LiveDemo
SQL Server 2012+
Using CHOOSE added UNION to cte to ensure to get zeros for missing years:
;WITH cte AS
(
SELECT [year] = YEAR(DateLogged),
[month] = CHOOSE(MONTH(DateLogged),'Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'),
IncidentRef
FROM #Incidents
UNION ALL
SELECT [year], NULL, NULL
FROM (VALUES (2010),(2011),(2012),(2013),(2014),(2015)) AS t([year])
)
SELECT [Year],Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, [Set], Out, Nov, Dez
FROM cte
PIVOT (
COUNT(IncidentRef)
FOR [month] IN (Jan, Fev, Mar, Abr, Mai, Jun,Jul, Ago, [Set], Out, Nov,Dez)
) AS piv
ORDER BY [Year];
LiveDemo2

SQL count and group by date and type

I have a quality system table. There are 2 types of quality points NCR and RMA.
RMA is external and NCR is internal. We log transactions to the table either as a NCR or a RMA. I would like to have a query that will count all of the RMA's and all of the NCR's then group them by monthly count. For example:
MONTH RMA NCR
JANUARY 10 54
FEBRUARY 48 22
MARCH 25 55
If the value is zero for the month or the month has not yet come up, I don't want to see it on the report.
the table. this is what I have.
SELECT MONTH(QualityControl.CreateDate) MONTH, COUNT(*) AS 'NCR'
FROM QualityControl
WHERE YEAR(QualityControl.CreateDate)=2015
and
QualityControl.NCR is not null
GROUP BY MONTH(QualityControl.CreateDate)
This only gives me the month number (1=January) and the NCR count for that month.
Then I tried the following:
SELECT
SUM(CASE datepart(month,CreateDate) WHEN 1 THEN 1 ELSE 0 END) AS 'January',
SUM(CASE datepart(month,CreateDate) WHEN 2 THEN 1 ELSE 0 END) AS 'February',
SUM(CASE datepart(month,CreateDate) WHEN 3 THEN 1 ELSE 0 END) AS 'March',
SUM(CASE datepart(month,CreateDate) WHEN 4 THEN 1 ELSE 0 END) AS 'April',
SUM(CASE datepart(month,CreateDate) WHEN 5 THEN 1 ELSE 0 END) AS 'May',
SUM(CASE datepart(month,CreateDate) WHEN 6 THEN 1 ELSE 0 END) AS 'June',
SUM(CASE datepart(month,CreateDate) WHEN 7 THEN 1 ELSE 0 END) AS 'July',
SUM(CASE datepart(month,CreateDate) WHEN 8 THEN 1 ELSE 0 END) AS 'August',
SUM(CASE datepart(month,CreateDate) WHEN 9 THEN 1 ELSE 0 END) AS 'September',
SUM(CASE datepart(month,CreateDate) WHEN 10 THEN 1 ELSE 0 END) AS 'October',
SUM(CASE datepart(month,CreateDate) WHEN 11 THEN 1 ELSE 0 END) AS 'November',
SUM(CASE datepart(month,CreateDate) WHEN 12 THEN 1 ELSE 0 END) AS 'December',
SUM(CASE datepart(year,CreateDate) WHEN 2015 THEN 1 ELSE 0 END) AS 'TOTAL'
FROM
QualityControl
WHERE
CreateDate BETWEEN '2015/01/01' AND '2015/12/30'
And it gave me the count for NCR and RMA
Let's go with your first attempt, which is one row per value. You want to count the valid "NCR" and "RMA" values. You can use a COUNT() like this:
SELECT MONTH(qc.CreateDate) as MON, COUNT(NCR) as NCR, COUNT(RMA) as RMA
FROM QualityControl qc
WHERE CreateDate >= '2015-01-01' AND CreateDate < '2016-01-01'
GROUP BY MONTH(qc.CreateDate)
ORDER BY MON;
With a column (or other expression), COUNT() counts the number of non-NULL values. That seems to be exactly what you want.
If you wanted the SUM() of the values, then you would use SUM() instead of COUNT().
Note about the dates:
The version using comparisons is better than the one using YEAR(), because it can make use of indexes.
I changed the BETWEEN to >= and <. This version works correctly, if your date/time column has a time component. It also works for dates.
December has 31 days.
in sql server you can do all of these :
SELECT
CASE datepart(month,getdate()) WHEN 1 THEN 1 ELSE 0 END AS January,
CASE datepart(month,getdate()) WHEN 2 THEN 1 ELSE 0 END AS "February",
CASE datepart(month,getdate()) WHEN 3 THEN 1 ELSE 0 END AS [March]
the best method would be
SELECT datename(month, getdate())