I have a table where I have been gathering user's clock in, clock out times and this gets displayed onto a calendar no problem. However, now I would like to see what hours all users are working.
Every time a user Clocks In, a new record is created. Every time a user clocks out, a new record is created also.
My SQL code below allows me to bring up Clock In and Clock Out times:
DECLARE #StartDate DateTime;
DECLARE #EndDate DateTime;
DECLARE #AssumedShiftStartTime DateTime;
DECLARE #AssumedShiftEndTime DateTime;
DECLARE #EmployeeName nvarchar(200);
DECLARE #ShiftStart DateTime
DECLARE #ShiftEnd DateTime
-- Date format: YYYY-MM-DD
SET #StartDate = '2014-07-01 00:00:00'
SET #EndDate = DATEADD (DAY, 1, #StartDate); -- Add one day
SET #AssumedShiftEndTime = '18:00:00'
SET #AssumedShiftStartTime = '09:00:00'
SET #EmployeeName = 'Paul';
-------------- Get Clock IN / OUT TIMES -----------------
SELECT EmployeeAttendance.LastUpdate, EmployeeAttendance.ClockInTime, EmployeeAttendance.ClockOutTime
FROM EmployeeAttendance INNER JOIN
Membership ON EmployeeAttendance.UserId = Membership.UserId
WHERE EmployeeAttendance.LastUpdate >= #StartDate AND EmployeeAttendance.LastUpdate <= #EndDate
AND Membership.Username = #EmployeeName
Which gives the following results:
LastUpdate ClockInTime ClockOutTime
2014-07-01 08:48:08.650 2014-07-01 08:48:08.650 NULL
2014-07-01 18:04:39.943 NULL 2014-07-01 18:04:39.923
2014-07-02 08:48:08.680 2014-07-01 09:00:08.340 NULL
2014-07-02 18:04:39.343 NULL 2014-07-01 18:00:39.623
2014-07-03 08:48:08.620 2014-07-01 08:58:08.860 NULL
2014-07-03 18:04:39.455 NULL 2014-07-01 18:05:39.985
What I am really trying to achieve is something that returns the following results.
EDIT: Where the results return a null, I want to use #AssumedShiftStartTime or #AssumedShiftEndTime to allow a result to be caluclated for total hours but gets difficult because two seperate records are recorded for Clock In and Clock Out:
DATE CLOCK-IN-TIME CLOCK-OUT-TIME TOTAL-HOURS
2014-07-01 08:49 18:04 9 Hours 15 Mins
2014-07-02 09:00 18:00 9 Hours 00 Mins
2014-07-03 08:58 18:05 9 Hours 07 Mins
Total-This-Month
27 Hours 15 Mins
EDIT: Thank you Sean Lange for your help. After applying the help from your reply I get the following output which shows two rows account for Clock In and Clock Out. I am trying to determine how would be the best way to get the results for a single day, calculate total hours, merge next two and calculate hours etc. I think this is more complicated than it needs to be and maybe time for a SQL logic recode?
2014-07-01 08:48:08.650 NULL NULL NULL
NULL 2014-07-01 18:04:39.923 NULL NULL
2014-07-02 08:54:03.483 NULL NULL NULL
NULL 2014-07-02 17:09:34.940 NULL NULL
2014-07-03 08:48:01.070 NULL NULL NULL
NULL 2014-07-03 18:12:11.487 NULL NULL
2014-07-04 08:48:07.983 NULL NULL NULL
NULL 2014-07-04 18:07:09.390 NULL NULL
2014-07-05 08:56:24.410 NULL NULL NULL
NULL 2014-07-05 14:19:12.800 NULL NULL
2014-07-08 08:44:56.727 NULL NULL NULL
NULL 2014-07-08 18:15:12.143 NULL NULL
2014-07-09 08:46:15.103 NULL NULL NULL
NULL 2014-07-09 17:10:46.327 NULL NULL
2014-07-10 08:57:14.733 NULL NULL NULL
NULL 2014-07-10 18:10:37.897 NULL NULL
2014-07-11 08:52:10.783 NULL NULL NULL
NULL 2014-07-11 18:08:58.580 NULL NULL
2014-07-12 08:56:20.073 NULL NULL NULL
NULL 2014-07-12 14:15:44.103 NULL NULL
2014-07-15 08:47:04.330 NULL NULL NULL
NULL 2014-07-15 18:10:05.800 NULL NULL
2014-07-16 08:56:34.490 NULL NULL NULL
NULL 2014-07-16 17:05:06.627 NULL NULL
2014-07-17 08:46:37.263 NULL NULL NULL
NULL 2014-07-17 18:06:08.840 NULL NULL
2014-07-18 08:52:56.200 NULL NULL NULL
NULL 2014-07-18 18:11:25.750 NULL NULL
2014-07-19 08:54:36.277 NULL NULL NULL
NULL 2014-07-19 14:15:09.620 NULL NULL
2014-07-22 08:56:30.623 NULL NULL NULL
NULL 2014-07-22 16:03:00.653 NULL NULL
2014-07-23 08:49:53.687 NULL NULL NULL
NULL 2014-07-23 17:07:37.943 NULL NULL
2014-07-24 08:52:08.690 NULL NULL NULL
2014-07-25 08:57:13.477 NULL NULL NULL
NULL 2014-07-25 18:09:01.793 NULL NULL
2014-07-26 08:53:42.597 NULL NULL NULL
NULL 2014-07-26 14:03:21.063 NULL NULL
Any help would be gratefully accepted.
Thank you
Here we make up some test data:
DECLARE #TimeSheet TABLE
(
EmpId INT,
LastUpdate DATETIME,
ClockInTime DATETIME,
ClockOutTime DATETIME
)
INSERT INTO #TimeSheet
VALUES
(201, '2014-07-01 08:48:08.650', '2014-07-01 08:48:08.650' ,NULL ),
(201, '2014-07-01 18:04:39.943', NULL ,'2014-07-01 18:04:39.923'),
(201, '2014-07-02 08:48:08.680', '2014-07-01 09:00:08.340' ,NULL ),
(201, '2014-07-02 18:04:39.343', NULL ,'2014-07-01 18:00:39.623'),
(201, '2014-07-03 08:48:08.620', '2014-07-01 08:58:08.860' ,NULL ),
(201, '2014-07-03 18:04:39.455', NULL ,'2014-07-01 18:05:39.985'),
(110, '2014-07-01 08:48:08.650', '2014-07-01 06:48:08.650' ,NULL ),
(110, '2014-07-01 18:04:39.943', NULL ,'2014-07-01 14:01:39.923'),
(110, '2014-07-02 08:48:08.680', '2014-07-01 07:10:08.340' ,NULL ),
(110, '2014-07-02 18:04:39.343', NULL ,'2014-07-01 14:00:39.623'),
(110, '2014-07-03 08:48:08.620', '2014-07-01 06:58:58.860' ,NULL ),
(110, '2014-07-03 18:04:39.455', NULL ,'2014-07-01 14:01:39.985');
Now lets create a CTE to number our data:
WITH TimeRows AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY EmpId, CAST(LastUpdate AS DATE) ORDER BY LastUpdate) RN
FROM #TimeSheet
)
Now we query the CTE against itself to find our clockin and clockout times:
SELECT T1.EmpId,
T1.ClockInTime,
T2.ClockOutTime,
DATEDIFF(HOUR, T1.ClockInTime, T2.ClockOutTime) AS DHour,
DATEDIFF(MINUTE, T1.ClockInTime, T2.ClockOutTime) % 60 AS DMinutes
FROM TimeRows T1
INNER JOIN TimeRows T2
ON T2.EmpId = T1.EmpId
AND T2.RN = T1.RN + 1
AND CAST(T2.LastUpdate AS DATE) = CAST(T1.LastUpdate AS DATE)
Here is the output:
EmpId ClockInTime ClockOutTime DHour DMinutes
110 2014-07-01 06:48:08.650 2014-07-01 14:01:39.923 8 13
110 2014-07-01 07:10:08.340 2014-07-01 14:00:39.623 7 50
110 2014-07-01 06:58:58.860 2014-07-01 14:01:39.987 8 3
201 2014-07-01 08:48:08.650 2014-07-01 18:04:39.923 10 16
201 2014-07-01 09:00:08.340 2014-07-01 18:00:39.623 9 0
201 2014-07-01 08:58:08.860 2014-07-01 18:05:39.987 10 7
Something like this help?
declare #Times table(ClockIn datetime, ClockOut datetime)
insert #Times
select '2014-07-01 08:49', '2014-07-01 18:04' union all
select '2014-07-01 09:00', '2014-07-01 18:00'
select *
, datediff(hour, ClockIn, ClockOut) - case when datediff(minute, ClockIn, ClockOut) % 60 > 0 then 1 else 0 end as MyHours
,datediff(minute, ClockIn, ClockOut) % 60 as MyMinutes
from #Times
Related
My question involves how to identify an index discharge.
The index discharge is the earliest discharge. On that date, the 30 day window starts. Any admissions during that time period are considered readmissions, and they should be ignored. Once the 30 day window is over, then any subsequent discharge is considered an index and the 30 day window begins again.
I can't seem to work out the logic for this. I've tried different windowing functions, I've tried cross joins and cross applies. The issue I keep encountering is that a readmission cannot be an index admission. It must be excluded.
I have successfully written a while loop to solve this problem, but I'd really like to get this in a set based format, if it's possible. I haven't been successful so far.
Ultimate goal is this -
id
AdmitDate
DischargeDate
MedicalRecordNumber
IndexYN
1
2021-03-03 00:00:00.000
2021-03-09 13:20:00.000
X0090362
1
4
2021-03-05 00:00:00.000
2021-03-10 16:00:00.000
X0012614
1
6
2021-05-18 00:00:00.000
2021-05-21 22:20:00.000
X0012614
1
7
2021-06-21 00:00:00.000
2021-07-08 13:30:00.000
X0012614
1
8
2021-02-03 00:00:00.000
2021-02-09 17:00:00.000
X0019655
1
10
2021-03-23 00:00:00.000
2021-03-26 16:40:00.000
X0019655
1
11
2021-03-15 00:00:00.000
2021-03-18 15:53:00.000
X4135958
1
13
2021-05-17 00:00:00.000
2021-05-23 14:55:00.000
X4135958
1
15
2021-06-24 00:00:00.000
2021-07-13 15:06:00.000
X4135958
1
Sample code is below.
CREATE TABLE #Admissions
(
[id] INT,
[AdmitDate] DATETIME,
[DischargeDateTime] DATETIME,
[UnitNumber] VARCHAR(20),
[IndexYN] INT
)
INSERT INTO #Admissions
VALUES( 1 ,'2021-03-03' ,'2021-03-09 13:20:00.000' ,'X0090362', NULL)
,(2 ,'2021-03-27' ,'2021-03-30 19:59:00.000' ,'X0090362', NULL)
,(3 ,'2021-03-31' ,'2021-04-04 05:57:00.000' ,'X0090362', NULL)
,(4 ,'2021-03-05' ,'2021-03-10 16:00:00.000' ,'X0012614', NULL)
,(5 ,'2021-03-28' ,'2021-04-16 13:55:00.000' ,'X0012614', NULL)
,(6 ,'2021-05-18' ,'2021-05-21 22:20:00.000' ,'X0012614', NULL)
,(7 ,'2021-06-21' ,'2021-07-08 13:30:00.000' ,'X0012614', NULL)
,(8 ,'2021-02-03' ,'2021-02-09 17:00:00.000' ,'X0019655', NULL)
,(9 ,'2021-02-17' ,'2021-02-22 17:25:00.000' ,'X0019655', NULL)
,(10 ,'2021-03-23' ,'2021-03-26 16:40:00.000' ,'X0019655', NULL)
,(11 ,'2021-03-15' ,'2021-03-18 15:53:00.000' ,'X4135958', NULL)
,(12 ,'2021-04-08' ,'2021-04-13 19:42:00.000' ,'X4135958', NULL)
,(13 ,'2021-05-17' ,'2021-05-23 14:55:00.000' ,'X4135958', NULL)
,(14 ,'2021-06-09' ,'2021-06-14 12:45:00.000' ,'X4135958', NULL)
,(15 ,'2021-06-24' ,'2021-07-13 15:06:00.000' ,'X4135958', NULL)
You can use a recursive CTE to identify all rows associated with each "index" discharge:
with a as (
select a.*, row_number() over (order by dischargedatetime) as seqnum
from admissions a
),
cte as (
select id, admitdate, dischargedatetime, unitnumber, seqnum, dischargedatetime as index_dischargedatetime
from a
where seqnum = 1
union all
select a.id, a.admitdate, a.dischargedatetime, a.unitnumber, a.seqnum,
(case when a.dischargedatetime > dateadd(day, 30, cte.index_dischargedatetime)
then a.dischargedatetime else cte.index_dischargedatetime
end) as index_dischargedatetime
from cte join
a
on a.seqnum = cte.seqnum + 1
)
select *
from cte;
You can then incorporate this into an update:
update admissions
set indexyn = (case when admissions.dischargedatetime = cte.index_dischargedatetime then 'Y' else 'N' end)
from cte
where cte.id = admissions.id;
Here is a db<>fiddle. Note that I changed the type of IndexYN to a character to assign 'Y'/'N', which makes sense given the column name.
Table 1: Daily attendance data:
att_date emp_code emp_name in_time out_time
2018-10-21 9999 Test 2018-10-21 08:00:00.000 2018-10-22 06:00:00.000
Table 2: Trnevents
emp_readr_id DT EVENTID
9999 2018-10-24 07:00:00.000 0
9999 2018-10-24 05:00:00.000 0
9999 2018-10-24 03:00:00.000 0
9999 2018-10-23 21:00:00.000 0
9999 2018-10-23 19:00:00.000 0
9999 2018-10-23 06:00:00.000 0
9999 2018-10-22 06:00:00.000 0
9999 2018-10-21 08:00:00.000 0
I used this query to get all times in between in time and out time ,below query works fine but i try to make in row by using pivot. While using pivot out time shows in next row.
declare #tempProcesstable as table(
[id] [nvarchar](200) NULL,
[time_stamp] datetime NULL,
[AccessType] varchar(3) NULL)
insert into #tempProcesstable
select distinct t1.emp_Reader_id, t1.DT,t1.eventid from daily_attendance_data t2 join trnevents t1
on t1.emp_reader_id=t2.emp_reader_id where (CONVERT(VARCHAR(26), t2.att_Date, 23) >=CONVERT(VARCHAR(26), '2018-10-20', 23)
and CONVERT(VARCHAR(26), t2.att_date, 23) <=CONVERT(VARCHAR(26), '2018-10-21', 23))
and
(t1.DT >=t2.in_time
and t1.DT <=t2.out_time)
-- and t1.emp_reader_id=1000
group by t1.emp_Reader_id,t1.dt,t1.eventid order by t1.emp_reader_id,DT asc
; With CheckIns
As (Select Rowemp_reader_id = Row_Number() Over (Partition by id, Cast(time_stamp As Date) Order By time_stamp),
id, time_stamp,
[Date] = Cast(time_stamp As Date),
[Time] = Cast(time_stamp As Time(0))
From #tempProcesstable)
Select Pvt.id,B.emp_name , [Date], CHECK1, CHECK2,Cast(dateadd(ss,datediff(ss,CHECK1,CHECK2),0) As Time(0)) Total1,
CHECK3, CHECK4,Cast(dateadd(ss,datediff(ss,CHECK3,CHECK4),0) As Time(0)) Total2
From (Select id, [Date], [Time],
CHECKNum = 'CHECK' + Cast(Rowemp_reader_id As varchar(11))
From CheckIns) As P
Pivot (Min([Time])
For CheckNum In (Check1, [Check2], Check3, Check4)
) As Pvt
LEFT OUTER JOIN
dbo.employee AS B ON Pvt.id= B.emp_reader_id
My output:
id emp_name Date CHECK1 CHECK2 Total1 CHECK3 CHECK4 Total2
1048 Singh 2018-10-21 07:06:07 17:34:05 10:27:58 NULL NULL NULL
9999 Test 2018-10-21 08:00:00 NULL NULL NULL NULL NULL NULL
9999 Test 2018-10-22 06:00:00 NULL NULL NULL NULL NULL NULL
Expected output:
I want all times between in time and out time in night to morning also.
can any one help me to rectify this.
id emp_name Date CHECK1 CHECK2 Total1 CHECK3 CHECK4 Total2
1048 Singh 2018-10-21 07:06:07 17:34:05 10:27:58 NULL NULL NULL
9999 Test 2018-10-21 08:00:00 06:00:00 NULL NULL NULL NULL NULL
You can try to use ROW_NUMBER() window function make row number by each date.
then use condition aggregate function to do pivot
SELECT emp_readr_id,
emp_name,
[Date],
MAX(CASE WHEN RN = 1 THEN time END) CHECK1,
MAX(CASE WHEN RN = 2 THEN time END) CHECK2,
MAX(CASE WHEN RN = 3 THEN time END) CHECK3,
MAX(CASE WHEN RN = 4 THEN time END) CHECK4
FROM (
SELECT emp_readr_id,
emp_name,
CONVERT(VARCHAR(10),DT,120) 'Date',
ROW_NUMBER() OVER(PARTITION BY CONVERT(VARCHAR(10),DT,120) ORDER BY DT) rn,
CONVERT(VARCHAR(10),DT,108) time
FROM Daily d
JOIN Trnevents t on t.DT between d.in_time and d.out_time
) t1
group by emp_readr_id,
emp_name,
[Date]
sqlifddle
I have the following data shown below. It was produced by the following query:
;with noms as
(
select DateS, Region, Sales from tblSalesRegion
where Id = 'B2PM'
)
select * from
noms as source pivot (max(Sales) for Region in ([UK],[US],[EUxUK],[JAP],[Brazil])) as pvt
order by DateS
Data:
DateS UK US EUxUK JAP Brazil
2015-11-24 23634 22187 NULL NULL NULL
2015-11-30 23634 22187 NULL NULL NULL
2015-12-01 23634 22187 NULL NULL NULL
2015-12-02 23634 22187 NULL NULL NULL
2015-12-03 23634 22187 NULL NULL NULL
2015-12-04 56000 22187 NULL NULL NULL
2015-12-07 56000 22187 NULL NULL NULL
2015-12-08 56000 22187 NULL NULL NULL
2015-12-09 56000 22187 NULL NULL NULL
2015-12-10 56000 10025 NULL NULL NULL
2015-12-11 56000 10025 NULL NULL NULL
2015-12-14 56000 10025 NULL NULL NULL
Below is the result I'm after. So basically when one of the values changes in one of the five columns (excluding the dateS column) I want that to be shown. Is there a way to do this in Sql? As I need the date I don't think a simple group by statement would work. Also be nice if I could change the NULL's to zeros
Result I'm looking for:
DateS UK US EUxUK JAP Brazil
2015-11-24 23634 22187 0 0 0
2015-12-04 56000 22187 0 0 0
2015-12-10 56000 10025 0 0 0
Seems like a simple GROUP BY is what you want:
;WITH noms AS
(
SELECT DateS, Region, Sales
FROM tblSalesRegion
WHERE Id = 'B2PM'
)
SELECT MIN(DateS), [UK],[US],[EUxUK],[JAP],[Brazil]
FROM (
SELECT DateS,
COALESCE([UK], 0) AS [UK],
COALESCE([US], 0) AS [US],
COALESCE([EUxUK], 0) AS [EUxUK],
COALESCE([JAP], 0) AS [JAP],
COALESCE([Brazil], 0) AS [Brazil]
FROM noms AS source
PIVOT (
MAX(Sales) FOR Region IN ([UK],[US],[EUxUK],[JAP],[Brazil])) AS pvt
) AS t
GROUP BY [UK],[US],[EUxUK],[JAP],[Brazil]
ORDER BY MIN(DateS)
here is the example table with data (rn column is ROW_NUMBER() for each UELN).
UELN OwnerID Date rn
191001180010389 017581 1989-06-30 00:00:00.000 1
191001180010389 017747 2011-06-02 00:00:00.000 2
191001180010389 017992 2014-03-25 00:00:00.000 3
191001180010389 117030 2015-02-03 00:00:00.000 4
191001250009303 018148 2004-06-30 00:00:00.000 1
191001250009303 018418 2013-10-16 00:00:00.000 2
I need to combine those rows to get result set like this:
UELN OwnerID DateFrom DateTo
191001180010389 017581 1989-06-30 00:00:00.000 2011-06-02 00:00:00.000
191001180010389 017747 2011-06-02 00:00:00.000 2014-03-25 00:00:00.000
191001180010389 017992 2014-03-25 00:00:00.000 2015-02-03 00:00:00.000
191001180010389 117030 2015-02-03 00:00:00.000 NULL
191001250009303 018148 2004-06-30 00:00:00.000 2013-10-16 00:00:00.000
191001250009303 018418 2013-10-16 00:00:00.000 NULL
NULL in DateTo column means that this is still valid.
Can anyone help me with the query?
select u1.*, u2.date as [date to]
from tabl u1
left join tabl u2
on u1.UELN = u2.UELN
and u2.rn = u1.rn + 1
You just need a left self join
The left part is what gets the null date for the no match
Using OUTER APPLY:
SELECT
t.UELN,
t.OwnerID,
DateFrom = t.[Date],
DateTo = x.DateTo
FROM tbl t
OUTER APPLY(
SELECT
DateTo = [Date]
FROM tbl
WHERE
UELN = t.UELN
AND rn = t.rn + 1
)x
You can try the following:
-- Create demo data
CREATE TABLE #temp(ueln bigint, ownerid nvarchar(20), date date, rn int)
INSERT INTO #temp(ueln, ownerid, date, rn)
VALUES (191001180010389,N'017581', N'1989-06-30 00:00:00.000', 1),
(191001180010389,N'017747', N'2011-06-02 00:00:00.000', 2),
(191001180010389,N'017992', N'2014-03-25 00:00:00.000', 3),
(191001180010389,N'117030', N'2015-02-03 00:00:00.000', 4),
(191001250009303,N'018148', N'2004-06-30 00:00:00.000', 1),
(191001250009303,N'018148', N'2013-10-16 00:00:00.000', 2)
-- your part
SELECT cur.ueln, cur.ownerid, cur.date as date_from, due.date as date_to
-- Maybe 1 day befor: DATEADD(day,-1,due.date) as date_to
FROM #temp as cur
LEFT JOIN #temp as due
ON cur.ueln = due.ueln
AND cur.rn = due.rn+1
DROP TABLE #temp
Which results in:
ueln ownerid date_from date_to
-------------------- -------------------- ---------- ----------
191001180010389 017581 1989-06-30 NULL
191001180010389 017747 2011-06-02 1989-06-30
191001180010389 017992 2014-03-25 2011-06-02
191001180010389 117030 2015-02-03 2014-03-25
191001250009303 018148 2004-06-30 NULL
191001250009303 018148 2013-10-16 2004-06-30
If you want to be the date_to one day before the next data-row, you can use the commented date_to.
We can use the LEAD() function introduced in SQL 2012.
--setup
CREATE TABLE #temp(ueln bigint, ownerid nvarchar(20), [date] date)
INSERT INTO #temp(ueln, ownerid, [date])
VALUES (191001180010389, N'017581', N'1989-06-30 00:00:00.000'),
(191001180010389, N'017747', N'2011-06-02 00:00:00.000'),
(191001180010389, N'017992', N'2014-03-25 00:00:00.000'),
(191001180010389, N'117030', N'2015-02-03 00:00:00.000'),
(191001250009303, N'018148', N'2004-06-30 00:00:00.000'),
(191001250009303, N'018148', N'2013-10-16 00:00:00.000');
--actual query
SELECT [ueln] ,
[ownerid] ,
[date] AS [DateFrom]
, LEAD([date], 1) OVER (PARTITION BY ueln ORDER BY [date]) AS [DateTo]
FROM #temp
Thanks to #Ionic for the temp table definition!
I have Two Date in SQL sever which overlap in two month i want to find how many days over lap in each month.
For example:
Start date is : 26-Sep-2012
End Date is : 10-Oct-2012
Sept- 5 days
October - 10 days
along with the list of date of each month.
declare #start datetime;
declare #end datetime;
set #start = '20120926';
set #end = '20121010';
SELECT (DAY(DATEADD (m, 1, DATEADD(d, 1 - DAY(#start), #start))-1)
- DAY(#start) + 1) AS DaysLeftStart,
DAY(#end) AS DaysEnd
Fiddle: http://sqlfiddle.com/#!3/d41d8/4441/0
DECLARE #start DATETIME, #end DATETIME;
SELECT #start = '20120926', #end = '20121010';
;WITH c(d) AS
(
SELECT TOP (DATEDIFF(DAY, #start, #end)+1)
DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY name)-1, #start)
FROM sys.all_columns
)
SELECT
[date] = DATEADD(MONTH, DATEDIFF(MONTH, 0, d), 0),
[days] = COUNT(*)
FROM c GROUP BY DATEDIFF(MONTH, 0, d)
UNION ALL SELECT d, NULL FROM c;
Results:
date days
----------------------- -----
2012-09-01 00:00:00.000 5
2012-10-01 00:00:00.000 10
2012-09-26 00:00:00.000 NULL
2012-09-27 00:00:00.000 NULL
2012-09-28 00:00:00.000 NULL
2012-09-29 00:00:00.000 NULL
2012-09-30 00:00:00.000 NULL
2012-10-01 00:00:00.000 NULL
2012-10-02 00:00:00.000 NULL
2012-10-03 00:00:00.000 NULL
2012-10-04 00:00:00.000 NULL
2012-10-05 00:00:00.000 NULL
2012-10-06 00:00:00.000 NULL
2012-10-07 00:00:00.000 NULL
2012-10-08 00:00:00.000 NULL
2012-10-09 00:00:00.000 NULL
2012-10-10 00:00:00.000 NULL
Here you can find some detail about creating a calendar table. You can use it to perform such query:
SELECT CalendarMonth, count(*) day_num
FROM dbo.Calendar
WHERE CalendarDate between #start_date and #end_date;