I need to count cumulative count in T-SQL. This can be done as:
WITH DATASET AS (SELECT '2014-01-28' AS [DATE], 1 AS [COUNT]
UNION
SELECT '2014-01-29' AS [DATE], 5 AS [COUNT]
UNION
SELECT '2014-01-30' AS [DATE], 15 AS [COUNT]
UNION
SELECT '2014-01-31' AS [DATE], 4 AS [COUNT]
UNION
SELECT '2014-02-01' AS [DATE], 7 AS [COUNT]
UNION
SELECT '2014-02-02' AS [DATE], 1 AS [COUNT]
)
, CTE AS (SELECT *
,ROW_NUMBER() OVER (ORDER BY [DATE]) ROWNUM
FROM DATASET
)
SELECT CTE1.[DATE]
,CTE1.[COUNT]
,SUM(CTE2.[COUNT]) AS CUM_CNT
FROM CTE CTE1
JOIN CTE CTE2 ON CTE2.ROWNUM <= CTE1.ROWNUM
GROUP BY CTE1.[DATE]
,CTE1.[COUNT]
That returns:
DATE COUNT CUM_CNT
2014-01-28 1 1
2014-01-29 5 6
2014-01-30 15 21
2014-01-31 4 25
2014-02-01 7 32
2014-02-02 1 33
But I want to reset the cumulative count per each month so the data returned should be:
DATE COUNT CUM_CNT
2014-01-28 1 1
2014-01-29 5 6
2014-01-30 15 21
2014-01-31 4 25
2014-02-01 7 7
2014-02-02 1 8
Is it possible to achieve this in T-SQL? How?
As of SQL Server 2012+ you can use window version of SUM to calculate running totals. You just have to PARTITION by YEAR([DATE]), MONTH([DATE]) to get the expected result:
WITH DATASET AS (
SELECT '2014-01-28' AS [DATE], 1 AS [COUNT]
UNION
SELECT '2014-01-29' AS [DATE], 5 AS [COUNT]
UNION
SELECT '2014-01-30' AS [DATE], 15 AS [COUNT]
UNION
SELECT '2014-01-31' AS [DATE], 4 AS [COUNT]
UNION
SELECT '2014-02-01' AS [DATE], 7 AS [COUNT]
UNION
SELECT '2014-02-02' AS [DATE], 1 AS [COUNT]
)
SELECT [DATE], [COUNT],
SUM([COUNT]) OVER (PARTITION BY YEAR([DATE]), MONTH([DATE])
ORDER BY [DATE]) AS CUM_CNT
FROM DATASET
SQL Fiddle Demo
SELECT '2014-01-28' AS [DATE], 1 AS [COUNT]
UNION
SELECT '2014-01-29' AS [DATE], 5 AS [COUNT]
UNION
SELECT '2014-01-30' AS [DATE], 15 AS [COUNT]
UNION
SELECT '2014-01-31' AS [DATE], 4 AS [COUNT]
UNION
SELECT '2014-02-01' AS [DATE], 7 AS [COUNT]
UNION
SELECT '2014-02-02' AS [DATE], 1 AS [COUNT]
)
Select C2.date,sum(c1.count) as COUNT, sum(distinct c2.count) AS CUML_COUNT from DATASET C1
JOIN DATASET C2 ON month(C1.date) = month(C2.date) and C1.Date <= C2.Date
group by C2.date
Related
I want to find the missing NON-consecutive dates between two consecutive date.
I am posting my SQL query and temp tables to find out the results.
But I am not getting the proper results
Here is my SQL Query
drop table #temp
create table #temp(an varchar(20),dt date)
insert into #temp
select '2133783715' , '2016-10-16' union all
select '5107537880' , '2016-10-15' union all
select '6619324250' , '2016-10-15' union all
select '7146586717' , '2016-10-15' union all
select '7472381321' , '2016-10-12' union all
select '7472381321' , '2016-10-13' union all
select '7472381321' , '2016-10-14' union all
select '7472381321' , '2016-10-24' union all
select '8186056340' , '2016-10-15' union all
select '9099457123' , '2016-10-12' union all
select '9099457123' , '2016-10-13' union all
select '9099457123' , '2016-10-14' union all
select '9099457123' , '2016-10-23' union all
select '9099457123' , '2016-11-01' union all
select '9099457123' , '2016-11-02' union all
select '9099457123' , '2016-11-03' union all
select '9165074784' , '2016-10-16'
drop table #final
SELECT an,MIN(dt) AS MinDate,MAX(dt) AS MaxDate, COUNT(*) AS ConsecutiveUsage
--DateDiff(Day,LAG(MAX(dt)) OVER (partition by an ORDER BY an),MAX(dt)) nonusageDate
into #final
FROM(
SELECT an,dt,
DATEDIFF(D, ROW_NUMBER() OVER(partition by an ORDER BY dt),dt) AS Diff
FROM #temp c
)P
GROUP BY an,diff
select * from #final order by 1
an MinDate MaxDate ConsecutiveUsage
2133783715 2016-10-16 2016-10-16 1
5107537880 2016-10-15 2016-10-15 1
6619324250 2016-10-15 2016-10-15 1
7146586717 2016-10-15 2016-10-15 1
7472381321 2016-10-12 2016-10-14 3
7472381321 2016-10-24 2016-10-24 1
7472381321 2016-10-27 2016-10-28 1
8186056340 2016-10-15 2016-10-15 1
9099457123 2016-10-12 2016-10-14 3
9099457123 2016-10-23 2016-10-23 1
9165074784 2016-10-16 2016-10-16 1
But I want results of non-usage date.
I want to get those AN which has not been used continuously since 10 days.
So here output should be like this:-
an minusagesdate maxusagedate ConsecutiveNotUseddays
7472381321 2016-10-15 2016-10-23 9
7472381321 2016-10-25 2016-10-26 2
9099457123 2016-10-15 2016-10-22 8
So I just want to find out only consecutive not used dates count and their min and max dates .
try this :
with ranked as (
select f1.*,
ROW_NUMBER() over(partition by an order by dt) rang
from #temp f1
where exists
(select * from #temp f2
where f1.an=f2.an and datediff( day, f2.dt, f1.dt) >1
)
)
select an, minusagesdate, maxusagesdate, ConsecutiveNotUseddays
from (
select f1.*,
DATEADD(DAY,1, (select f2.dt from ranked f2 where f1.an=f2.an and f2.rang+1=f1.rang)) minusagesdate ,
DATEADD(DAY,-1, f1.dt) maxusagesdate ,
datediff( day, (select f2.dt from ranked f2 where f1.an=f2.an and f2.rang+1=f1.rang), f1.dt) - 1 ConsecutiveNotUseddays
from ranked f1
) tmp
where tmp.ConsecutiveNotUseddays>0
or like this
with ranked as (
select f1.*,
ROW_NUMBER() over(partition by an order by dt) rang
from #temp f1
where exists
(select * from #temp f2
where f1.an=f2.an and datediff( day, f2.dt, f1.dt) >1
)
)
select f1.an,
DATEADD(DAY,1, f3.dtbefore) minusagesdate ,
DATEADD(DAY,-1, f1.dt) maxusagesdate ,
datediff( day, f3.dtbefore, f1.dt) - 1 ConsecutiveNotUseddays
from ranked f1
outer apply
(
select top 1 f2.dt as dtbefore from ranked f2
where f1.an=f2.an and f2.rang+1=f1.rang
) f3
where datediff( day, f3.dtbefore, f1.dt) - 1>0
It looks like you're trying to count the number of days not used between the mindate and the maxdate for each an. If that's the case, then this should do the trick:
select an, min(dt) as min_dt, max(dt) as max_dt
, count(distinct dt) as daysused --this counts each day used, but only once
, datediff(day,min(dt),max(dt)) as totaldays --this is the total number of days between min and max date
, datediff(day,min(dt),max(dt)) - count(distinct dt) as daysnotused
--This takes total days - used days to give non-used days
from #temp c
group by an
having datediff(day,min(dt),max(dt)) - count(distinct dt) >= 10
As I understood you need this:
;WITH cte AS (
SELECT an,
dt,
ROW_NUMBER() OVER (PARTITION BY an ORDER BY dt) as rn
FROM #temp
)
SELECT c1.an,
c1.dt MinDate,
c2.dt MaxDate,
DATEDIFF(day,c1.dt,c2.dt) as ConsecutiveNotUseddays
FROM cte c1
INNER JOIN cte c2
ON c1.an = c2.an AND c1.rn = c2.rn-1
WHERE DATEDIFF(day,c1.dt,c2.dt) >= 10
Output:
an MinDate MaxDate ConsecutiveNotUseddays
7472381321 2016-10-14 2016-10-24 10
For 9099457123 I got two rows with 9 in ConsecutiveNotUseddays. You can check results removing WHERE statement.
On any newer version of SQL Server this should be easy:
with x as (
select *, lag(dt) over(partition by an order by dt) dt_lag
from #temp
)
select *, datediff(day, dt_lag, dt)
from x
where datediff(day, dt_lag, dt) >= 10
I have a table that stores budget quantities for a company whose fiscal year begins 1st April and ends on 31st March the next year.
I have this query to extract figures for a particular month.
SELECT SUM(T1.U_Quantity) AS 'YTDBOwnMadeTea'
FROM [SL_NTEL_DB_LIVE].[dbo].[#U_BUDG_MADETEA] T0
INNER JOIN [SL_NTEL_DB_LIVE].[dbo].[#U_BUDG_MADETEA_ROW] T1
ON T0.DocEntry = T1.DocEntry
WHERE T1.U_Month = DATENAME(MONTH, '2015-04-01') AND T0.U_Source = 'NTEL'
There is an existing report that takes two parameters, a Start and End Date. (type datetime)
Table below: The month column is of type nvarchar.
How do I modify the query such when a user enters StartDate and EndDate e.g.
1st May 2015 and 31st July 2015, I will get a quantity result of 12640.
You can use couple of ways to do this.
One way would be to use PARSE. Like this.
SELECT SUM(T1.U_Quantity) AS 'YTDBOwnMadeTea'
FROM [SL_NTEL_DB_LIVE].[dbo].[#U_BUDG_MADETEA] T0
INNER JOIN [SL_NTEL_DB_LIVE].[dbo].[#U_BUDG_MADETEA_ROW] T1
ON T0.DocEntry = T1.DocEntry
WHERE PARSE((T1.U_Month + CONVERT(VARCHAR(4),YEAR(CURRENT_TIMESTAMP))) as datetime) BETWEEN #StartDate AND #EndDate
AND T0.U_Source = 'NTEL'
Another way would be to use a numbers table to map your month name to a month number and use it in your query.
;WITH CTE AS (
SELECT 1 as rn UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
),
MonthMap AS
(
SELECT ROW_NUMBER()OVER(ORDER BY rn ASC) as monthnumber FROM CTE
)
SELECT monthnumber,DATENAME(MONTH,DATEFROMPARTS(2016,monthnumber,1)) FROM MonthMap;
and then join it with your month table like this.
;WITH CTE AS (
SELECT 1 as rn UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
),
MonthMap AS
(
SELECT ROW_NUMBER()OVER(ORDER BY rn ASC) as monthnumber FROM CTE
)
SELECT SUM(T1.U_Quantity) AS 'YTDBOwnMadeTea'
FROM [SL_NTEL_DB_LIVE].[dbo].[#U_BUDG_MADETEA] T0
INNER JOIN [SL_NTEL_DB_LIVE].[dbo].[#U_BUDG_MADETEA_ROW] T1
ON T0.DocEntry = T1.DocEntry
INNER JOIN MonthMap M ON T1.U_Month = DATENAME(MONTH,DATEFROMPARTS(2016,monthnumber,1))
WHERE M.monthnumber BETWEEN DATEPART(MONTH,#StartDate) AND DATEPART(MONTH,#EndDate)
AND T0.U_Source = 'NTEL';
You should compare both the approaches for performance. PARSE is simpler to use but would be difficult to index properly.
On a Separate note, you should avoid storing dates or date parts as month names as these take up more storage(even more since you are using NVARCHAR), and are difficult to use efficiently.
I am using SQL Server 2008. I have data by each employee for each day. Below is the sample data.
WITH RawData as
(
SELECT '10001' AS EmpNo,'2015-01-01' as AttendanceDate,'FS' AS ShiftCode UNION
SELECT '10001','2015-01-02','WO' UNION
SELECT '10001','2015-01-03','FS' UNION
SELECT '10001','2015-01-04','FS' UNION
SELECT '10001','2015-01-05','FS' UNION
SELECT '10001','2015-01-06','FS' UNION
SELECT '10001','2015-01-07','FS' UNION
SELECT '10001','2015-01-08','FS' UNION
SELECT '10001','2015-01-09','WO' UNION
SELECT '10001','2015-01-10','FS' UNION
SELECT '10001','2015-01-11','FS' UNION
SELECT '10001','2015-01-12','FS' UNION
SELECT '10001','2015-01-13','FS' UNION
SELECT '10001','2015-01-14','FS' UNION
SELECT '10001','2015-01-15','FS' UNION
SELECT '10001','2015-01-16','WO' UNION
SELECT '10001','2015-01-17','FS' UNION
SELECT '10001','2015-01-18','FS' UNION
SELECT '10001','2015-01-19','FS' UNION
SELECT '10001','2015-01-20','FS' UNION
SELECT '10001','2015-01-21','FS' UNION
SELECT '10001','2015-01-22','FS' UNION
SELECT '10001','2015-01-23','WO' UNION
SELECT '10001','2015-01-24','FS' UNION
SELECT '10001','2015-01-25','FS' UNION
SELECT '10001','2015-01-26','FS' UNION
SELECT '10001','2015-01-27','FS' UNION
SELECT '10001','2015-01-28','FS' UNION
SELECT '10001','2015-01-29','FS' UNION
SELECT '10001','2015-01-30','WO' UNION
SELECT '10001','2015-01-31','FS' UNION
SELECT '10002','2015-01-01','FS' UNION
SELECT '10002','2015-01-02','WO' UNION
SELECT '10002','2015-01-03','WO' UNION
SELECT '10002','2015-01-04','FS' UNION
SELECT '10002','2015-01-05','FS' UNION
SELECT '10002','2015-01-06','FS' UNION
SELECT '10002','2015-01-07','FS' UNION
SELECT '10002','2015-01-08','FS' UNION
SELECT '10002','2015-01-09','WO' UNION
SELECT '10002','2015-01-10','WO' UNION
SELECT '10002','2015-01-11','FS' UNION
SELECT '10002','2015-01-12','FS' UNION
SELECT '10002','2015-01-13','FS' UNION
SELECT '10002','2015-01-14','FS' UNION
SELECT '10002','2015-01-15','FS' UNION
SELECT '10002','2015-01-16','WO' UNION
SELECT '10002','2015-01-17','WO' UNION
SELECT '10002','2015-01-18','FS' UNION
SELECT '10002','2015-01-19','FS' UNION
SELECT '10002','2015-01-20','FS' UNION
SELECT '10002','2015-01-21','FS' UNION
SELECT '10002','2015-01-22','FS' UNION
SELECT '10002','2015-01-23','WO' UNION
SELECT '10002','2015-01-24','WO' UNION
SELECT '10002','2015-01-25','FS' UNION
SELECT '10002','2015-01-26','FS' UNION
SELECT '10002','2015-01-27','FS' UNION
SELECT '10002','2015-01-28','FS' UNION
SELECT '10002','2015-01-29','FS' UNION
SELECT '10002','2015-01-30','WO' UNION
SELECT '10002','2015-01-31','WO')
SELECT * FROM RawData Order By EmpNo,AttendanceDate
How to write SQL Query to get following output based on this sample data ? The workweek of each employee starts on a Day after weekly off and it can be any day (mon, tue etc). The shift code denotes WO: weekly off, FS: First Shift, SS: Second Shift.
EmpNo WeekFrom WeekTo
10001 2015-01-01 2015-01-02
10001 2015-01-03 2015-01-09
10001 2015-01-10 2015-01-16
10001 2015-01-17 2015-01-23
10001 2015-01-24 2015-01-30
10001 2015-01-31 2015-01-31
10002 2015-01-01 2015-01-03
10002 2015-01-04 2015-01-10
10002 2015-01-11 2015-01-17
10002 2015-01-18 2015-01-24
10002 2015-01-25 2015-01-31
Got a solution. But its taking quite a long time on live table with 1 Million rows. Have I done something wrong in a query ? Or there is a better way of doing this.
WITH RawData as
(
-- Insert above data here.
)
,ProcessData AS (
SELECT EmpNo,AttendanceDate,ShiftCode,RowID = ROW_NUMBER() OVER (
ORDER BY EmpNo, AttendanceDate
), WeekNo = 1 FROM RawData
)
,FinalData
AS (
SELECT EmpNo, AttendanceDate, ShiftCode, RowID, WeekNo = 1
FROM ProcessData DA
WHERE RowID = 1
UNION ALL
SELECT DA.EmpNo, DA.AttendanceDate, DA.ShiftCode, DA.RowID,
WeekNo = (CASE WHEN FinalData.EmpNo != DA.EmpNo THEN 1 ELSE FinalData.WeekNo + (CASE WHEN (FinalData.ShiftCode = 'WO' AND DA.ShiftCode != 'WO') THEN 1 ELSE 0 END) END)
FROM FinalData
INNER JOIN ProcessData DA ON DA.RowID = FinalData.RowID + 1
)
SELECT EmpNo, MIN(AttendanceDate) AS StartDate, MAX(AttendanceDate) AS EndDate, WeekNo
FROM FinalData
GROUP BY EmpNo, WeekNo
ORDER BY EmpNo, WeekNo
Try this:
SQL Fiddle
;WITH RawData AS (
-- Your insert statements here
),
Cte AS(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY EmpNo, grp ORDER BY AttendanceDate DESC)
FROM (
SELECT *,
grp = DATEADD(DAY, -ROW_NUMBER() OVER(PARTITION BY EmpNo ORDER BY AttendanceDate), AttendanceDate)
FROM RawData
WHERE ShiftCode = 'WO'
)t
),
CteWeekOff AS(
SELECT EmpNo, AttendanceDate, ShiftCode FROM cte WHERE RN = 1
),
CteFinal AS(
SELECT
EmpNo,
WeekFrom = MIN(AttendanceDate),
Weekto = MAX(AttendanceDate)
FROM (
SELECT *,
grp = DATEADD(DAY, - ROW_NUMBER() OVER(PARTITION BY EmpNo ORDER BY AttendanceDate), AttendanceDate)
FROM RawData
WHERE ShiftCode <> 'WO'
)t
GROUP BY EmpNo, grp
)
SELECT
EmpNo,
WeekFrom = x.WeekFrom,
WeekTo = w.AttendanceDate
FROM CteWeekOff w
CROSS APPLY(
SELECT TOP 1 WeekFrom
FROM CteFinal r
WHERE
r.EmpNo = w.EmpNo
AND r.WeekFrom <= w.AttendanceDate
ORDER BY r.WeekFrom DESC
)x(WeekFrom)
UNION ALL
SELECT
EmpNo,
WeekFrom = x.WeekFrom,
WeekTo = t.AttendanceDate
FROM (
SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY EmpNo ORDER BY AttendanceDate DESC)
FROM RawData
)t
CROSS APPLY(
SELECT TOP 1 AttendanceDate
FROM CteFinal r
WHERE
r.EmpNo = t.EmpNo
AND r.WeekFrom < t.AttendanceDate
ORDER BY r.WeekFrom DESC
)x(WeekFrom)
WHERE
RN = 1
AND ShiftCode <> 'WO'
ORDER BY EmpNo, WeekFrom
Finally this worked. 5 seconds on 230,000 records. I will go ahead with my solution. Thanks for your time. Hope this solution helps someone.
-- Step 1 : Save it to temp table
SELECT EmpNo,AttendanceDate,ShiftCode,RowID = ROW_NUMBER() OVER (
ORDER BY EmpNo, AttendanceDate
), WeekNo = 1 into #RawData FROM -- My table
-- Step 2 : Use temp table
;WITH FinalData
AS (
SELECT EmpNo, AttendanceDate, ShiftCode, RowID, WeekNo = 1
FROM #RawData DA
WHERE RowID = 1
UNION ALL
SELECT DA.EmpNo, DA.AttendanceDate, DA.ShiftCode, DA.RowID,
WeekNo = (CASE WHEN FinalData.EmpNo != DA.EmpNo THEN 1 ELSE FinalData.WeekNo + (CASE WHEN (FinalData.ShiftCode = 'WO' AND DA.ShiftCode != 'WO') THEN 1 ELSE 0 END) END)
FROM FinalData
INNER JOIN #RawData DA ON DA.RowID = FinalData.RowID + 1
)
SELECT EmpNo, MIN(AttendanceDate) AS StartDate, MAX(AttendanceDate) AS EndDate, WeekNo
FROM FinalData
GROUP BY EmpNo, WeekNo
ORDER BY EmpNo, WeekNo
OPTION (MAXRECURSION 0)
For example there is some table with dates:
2015-01-01
2015-01-02
2015-01-03
2015-01-06
2015-01-07
2015-01-11
I have to write ms sql query, which will return count of consecutive dates starting from every date in the table. So the result will be like:
2015-01-01 1
2015-01-02 2
2015-01-03 3
2015-01-06 1
2015-01-07 2
2015-01-11 1
It seems to me that I should use LAG and LEAD functions, but now I even can not imagine the way of thinking.
CREATE TABLE #T ( MyDate DATE) ;
INSERT #T VALUES ('2015-01-01'),('2015-01-02'),('2015-01-03'),('2015-01-06'),('2015-01-07'),('2015-01-11')
SELECT
RW=ROW_NUMBER() OVER( PARTITION BY GRP ORDER BY MyDate) ,MyDate
FROM
(
SELECT
MyDate, DATEDIFF(Day, '1900-01-01' , MyDate)- ROW_NUMBER() OVER( ORDER BY MyDate ) AS GRP
FROM #T
) A
DROP TABLE #T;
You can use this CTE:
;WITH CTE AS (
SELECT [Date],
ROW_NUMBER() OVER(ORDER BY [Date]) AS rn,
CASE WHEN DATEDIFF(Day, PrevDate, [Date]) IS NULL THEN 0
WHEN DATEDIFF(Day, PrevDate, [Date]) > 1 THEN 0
ELSE 1
END AS flag
FROM (
SELECT [Date], LAG([Date]) OVER (ORDER BY [Date]) AS PrevDate
FROM #Dates ) d
)
to produce the following result:
Date rn flag
===================
2015-01-01 1 0
2015-01-02 2 1
2015-01-03 3 1
2015-01-06 4 0
2015-01-07 5 1
2015-01-11 6 0
All you have to do now is to calculate a running total of flag up to the first occurrence of a preceding zero value:
;WITH CTE AS (
... cte statements here ...
)
SELECT [Date], b.cnt + 1
FROM CTE AS c
OUTER APPLY (
SELECT TOP 1 COALESCE(rn, 1) AS rn
FROM CTE
WHERE flag = 0 AND rn < c.rn
ORDER BY rn DESC
) a
CROSS APPLY (
SELECT COUNT(*) AS cnt
FROM CTE
WHERE c.flag <> 0 AND rn < c.rn AND rn >= a.rn
) b
OUTER APPLY calculates the rn value of the first zero-valued flag that comes before the current row. CROSS APPLY calculates the number of records preceding the current record up to the first occurrence of a preceding zero valued flag.
I'm assuming this table:
SELECT *
INTO #Dates
FROM (VALUES
(CAST('2015-01-01' AS DATE)),
(CAST('2015-01-02' AS DATE)),
(CAST('2015-01-03' AS DATE)),
(CAST('2015-01-06' AS DATE)),
(CAST('2015-01-07' AS DATE)),
(CAST('2015-01-11' AS DATE))) dates(d);
Here's a recursive solution with explanations:
WITH
dates AS (
SELECT
d,
-- This checks if the current row is the start of a new group by using LAG()
-- to see if the previous date is adjacent
CASE datediff(day, d, LAG(d, 1) OVER(ORDER BY d))
WHEN -1 THEN 0
ELSE 1 END new_group,
-- This will be used for recursion
row_number() OVER(ORDER BY d) rn
FROM #Dates
),
-- Here, the recursion happens
groups AS (
-- We initiate recursion with rows that start new groups, and calculate "GRP"
-- numbers
SELECT d, new_group, rn, row_number() OVER(ORDER BY d) grp
FROM dates
WHERE new_group = 1
UNION ALL
-- We then recurse by the previously calculated "RN" until we hit the next group
SELECT dates.d, dates.new_group, dates.rn, groups.grp
FROM dates JOIN groups ON dates.rn = groups.rn + 1
WHERE dates.new_group != 1
)
-- Finally, we enumerate rows within each group
SELECT d, row_number() OVER (PARTITION BY grp ORDER BY d)
FROM groups
ORDER BY d
SQLFiddle
I am having following output of query
Query:
SELECT DATENAME(mm, date) [Month], sum(braekTime) [TotalBreakTime],
sum(DATEPART(hh,totalTime) * 60 + DATEPART(mi,totalTime) + DATEPART(ss,totalTime) * 0.017) [Minute],firstName
FROM employeeAttendance,employee
where FK_employeeId = employee.employeeId
GROUP BY DATENAME(mm, date),firstName
ORDER BY [Month]
but I want each n every month record with null/ 0 value
like June and July record is not available then it should display like following
Month TotalBreakTime Minute firstName
----- -------------- ------ ---------
January 0 0 NULL
February 0 0 NULL
March 0 0 NULL
April 0 0 NULL
May 50 1015.000 foramaa
June 0 0 NULL
July 0 0 NULL
.... Like till Dec
You should create a virtual table or subquery for the months, and left join it to the totals query.
eg
select * from
(
select number, datename(m,DATEADD(m, number-1, 0)) as monthname
from master..spt_values
where type='p' and number between 1 and 12
) months
left join
(your totals query) totals
on months.monthname = totals.month
try this:
;with cte as(
select 1 as rn union all select 2 union all select 3),
cte1 as (select ROW_NUMBER() over(order by c1.rn) as row_num
from cte cross join cte c1 cross join cte c2)
select * from cte1
left join
(SELECT DATENAME(mm, date) [Month],
sum(braekTime) [TotalBreakTime],
sum(DATEPART(hh,totalTime) * 60 + DATEPART(mi,totalTime) + DATEPART(ss,totalTime) * 0.017) [Minute],
firstName
FROM employeeAttendance join employee
on FK_employeeId = employee.employeeId
GROUP BY DATENAME(mm, date),firstName
ORDER BY [Month])B
on B.[Month]=DateName( month , DateAdd( month ,cte1.row_num , 0 ) - 1 )
and cte1.row_num <=12