I have a table that gives me the details of the employees check-in and check-out details.
+------------+-------------------------+----------+
| EmployeeId | PunchTime | Category |
+------------+-------------------------+----------+
| 201 | 2015-10-14 23:30:00.000 | SHIFT |
| 201 | 2015-10-14 23:30:00.000 | TIN |
| 201 | 2015-10-15 01:17:00.000 | CBRK |
| 201 | 2015-10-15 01:30:00.000 | PBRK1 |
| 201 | 2015-10-15 07:43:00.000 | CBRK |
| 201 | 2015-10-15 23:30:00.000 | SHIFT |
| 201 | 2015-10-15 23:30:00.000 | TIN |
| 201 | 2015-10-16 02:47:00.000 | CBRK |
| 201 | 2015-10-16 03:45:00.000 | UBRK |
| 201 | 2015-10-16 07:44:00.000 | CBRK |
| 201 | 2015-10-16 23:30:00.000 | SHIFT |
| 201 | 2015-10-16 23:30:00.000 | TIN |
| 201 | 2015-10-17 00:30:00.000 | CBRK |
| 201 | 2015-10-17 01:00:00.000 | UISP |
| 201 | 2015-10-17 01:30:00.000 | PBRK1 |
| 201 | 2015-10-17 03:30:00.000 | PBRK2 |
+------------+-------------------------+----------+
Here the category value "SHIFT" would determine that the employee's first check-in of his/her shift for the day. At times there can be shifts that span across days.(i.e that beings at 23:30 on 14th to 07:43 on the 15th).
So a particular days shift would be from the First Shift row up to the next shift row. (i.e The shift of the user on the 14th would be from row 1 to row 5)
So I need to project out the Shift Date w.r.t to the first check-in date irrespective of the day the shift is ending.
This would be my desired output.
+-------------+-------------------------+----------+------------------+
| EmpoloyeeId | PunchTime | Category | Shift Date |
+-------------+-------------------------+----------+------------------+
| 201 | 2015-10-14 23:30:00.000 | SHIFT | 2015-10-14 |
| 201 | 2015-10-14 23:30:00.000 | TIN | 2015-10-14 |
| 201 | 2015-10-15 01:17:00.000 | CBRK | 2015-10-14 |
| 201 | 2015-10-15 01:30:00.000 | PBRK1 | 2015-10-14 |
| 201 | 2015-10-15 07:43:00.000 | CBRK | 2015-10-14 |
| 201 | 2015-10-15 23:30:00.000 | SHIFT | 2015-10-15 |
| 201 | 2015-10-15 23:30:00.000 | TIN | 2015-10-15 |
| 201 | 2015-10-15 23:32:00.000 | LCV | 2015-10-15 |
| 201 | 2015-10-16 02:47:00.000 | CBRK | 2015-10-15 |
| 201 | 2015-10-16 03:45:00.000 | UBRK | 2015-10-15 |
| 201 | 2015-10-16 07:44:00.000 | CBRK | 2015-10-15 |
| 201 | 2015-10-16 23:30:00.000 | SHIFT | 2014-10-16 |
| 201 | 2015-10-16 23:30:00.000 | TIN | 2014-10-16 |
| 201 | 2015-10-17 00:30:00.000 | CBRK | 2014-10-16 |
| 201 | 2015-10-17 01:00:00.000 | UISP | 2014-10-16 |
| 201 | 2015-10-17 01:30:00.000 | PBRK1 | 2014-10-16 |
| 201 | 2015-10-17 03:30:00.000 | PBRK2 | 2014-10-16 |
+-------------+-------------------------+----------+------------------+
I tried to project out a column that would group my shifts w.r.t to the row-number (using case then when) but i will be only able to assign value to the row where the Shift starts. the rest of my columns would be the value of the else case. like
+-------------+-------------------------+----------+--------+
| EmpoloyeeId | PunchTime | Category | row |
+-------------+-------------------------+----------+--------+
| 201 | 2015-10-14 23:30:00.000 | SHIFT | 1 |
| 201 | 2015-10-14 23:30:00.000 | TIN | 0 |
| 201 | 2015-10-15 01:17:00.000 | CBRK | 0 |
| 201 | 2015-10-15 01:30:00.000 | PBRK1 | 0 |
| 201 | 2015-10-15 07:43:00.000 | CBRK | 0 |
| 201 | 2015-10-15 23:30:00.000 | SHIFT | 6 |
| 201 | 2015-10-15 23:30:00.000 | TIN | 0 |
| 201 | 2015-10-15 23:32:00.000 | LCV | 0 |
| 201 | 2015-10-16 02:47:00.000 | CBRK | 0 |
| 201 | 2015-10-16 03:45:00.000 | UBRK | 0 |
| 201 | 2015-10-16 07:44:00.000 | CBRK | 0 |
| 201 | 2015-10-16 23:30:00.000 | SHIFT | 11 |
| 201 | 2015-10-16 23:30:00.000 | TIN | 0 |
| 201 | 2015-10-17 00:30:00.000 | CBRK | 0 |
| 201 | 2015-10-17 01:00:00.000 | UISP | 0 |
| 201 | 2015-10-17 01:30:00.000 | PBRK1 | 0 |
| 201 | 2015-10-17 03:30:00.000 | PBRK2 | 0 |
+-------------+-------------------------+----------+--------+
I have added the sample data in sql fiddle
The query i have reached so far is
SELECT *, CASE WHEN Category = 'Shift' THEN (
ROW_NUMBER() OVER (
ORDER BY EmployeeId, PunchTime
)
) ELSE '0' END AS Spearator
FROM [zzzEmpShift]
WHERE EmployeeId = 201
答案 0 :(得分:2)
这适用于2008年和2012年
<强> SQL Fiddle Demo 强>
WITH row_id as (
SELECT *, ROW_NUMBER() over (partition by [EmployeeId] order by [PunchTime]) rn
FROM zzzEmpShift
), shift as (
SELECT [EmployeeId], rn, cast([PunchTime] As Date) as [Shift Date]
FROM row_id
WHERE [Category] = 'SHIFT'
)
SELECT *
FROM row_id R
JOIN shift S
ON R.[EmployeeId] = S.[EmployeeId]
WHERE S.rn = (SELECT MAX(T.rn) FROM shift T WHERE T.rn <= R.rn)
<强>输出强>
╔═════╦═════════════════════════╦═══════╦════╦════╦════════════╗
║ 201 ║ 2015-10-14 23:30:00.000 ║ SHIFT ║ 1 ║ 1 ║ 2015-10-14 ║
║ 201 ║ 2015-10-14 23:30:00.000 ║ TIN ║ 2 ║ 1 ║ 2015-10-14 ║
║ 201 ║ 2015-10-15 01:17:00.000 ║ CBRK ║ 3 ║ 1 ║ 2015-10-14 ║
║ 201 ║ 2015-10-15 01:30:00.000 ║ PBRK1 ║ 4 ║ 1 ║ 2015-10-14 ║
║ 201 ║ 2015-10-15 07:43:00.000 ║ CBRK ║ 5 ║ 1 ║ 2015-10-14 ║
║ 201 ║ 2015-10-15 23:30:00.000 ║ SHIFT ║ 6 ║ 6 ║ 2015-10-15 ║
║ 201 ║ 2015-10-15 23:30:00.000 ║ TIN ║ 7 ║ 6 ║ 2015-10-15 ║
║ 201 ║ 2015-10-16 02:47:00.000 ║ CBRK ║ 8 ║ 6 ║ 2015-10-15 ║
║ 201 ║ 2015-10-16 03:45:00.000 ║ UBRK ║ 9 ║ 6 ║ 2015-10-15 ║
║ 201 ║ 2015-10-16 07:44:00.000 ║ CBRK ║ 10 ║ 6 ║ 2015-10-15 ║
║ 201 ║ 2015-10-16 23:30:00.000 ║ SHIFT ║ 11 ║ 11 ║ 2015-10-16 ║
║ 201 ║ 2015-10-16 23:30:00.000 ║ TIN ║ 12 ║ 11 ║ 2015-10-16 ║
║ 201 ║ 2015-10-17 00:30:00.000 ║ CBRK ║ 13 ║ 11 ║ 2015-10-16 ║
║ 201 ║ 2015-10-17 01:00:00.000 ║ UISP ║ 14 ║ 11 ║ 2015-10-16 ║
║ 201 ║ 2015-10-17 01:30:00.000 ║ PBRK1 ║ 15 ║ 11 ║ 2015-10-16 ║
║ 201 ║ 2015-10-17 03:30:00.000 ║ PBRK2 ║ 16 ║ 11 ║ 2015-10-16 ║
╚═════╩═════════════════════════╩═══════╩════╩════╩════════════╝
这是2012 + SqlFiddleDemo
的版本WITH group_id as (
SELECT *, SUM(case when Category ='Shift' then 1 else 0 end)
OVER (partition by [EmployeeId] order by [PunchTime]) rn
FROM zzzEmpShift
)
SELECT *, MIN(cast([PunchTime] As Date)) OVER (partition by rn) as [Shift Date]
FROM group_id
答案 1 :(得分:1)
To get the rows for the same shift grouped together, you can use a running total of this:
(case when Category ='Shift' then 1 else 0 end)
If you're using SQL Server 2012 (or newer) you can just use sum with over clause. With older versions, it might be easiest (and maybe even fastest) just to use temp table + cursor. Other option is to do a query back to the table to calculate the rows with "Shift" that have smaller time, but that causes quite a lot of IO.