Beispieldaten
DECLARE @StartDate date = '2016-06-01';
DECLARE @EndDate date = '2016-07-01';
DECLARE @Table_One TABLE (
Staff_ID int,
dt date,
First_Name nvarchar(50),
Last_Name nvarchar(50),
Section nvarchar(50),
Time_Worked datetime);
INSERT INTO @Table_One(Staff_ID, dt, First_Name, Last_Name, Section, Time_Worked)
VALUES
(1001, '2016-06-01', 'Bill', 'Price ', 'Level 1', '2016-06-01 8:30:00.000'),
(1001, '2016-06-05', 'Bill', 'Price ', 'Level 1', '2016-06-05 8:30:00.000'),
(1001, '2016-06-09', 'Bill', 'Price ', 'Level 1', '2016-06-09 8:30:00.000'),
(1001, '2016-06-12', 'Bill', 'Price ', 'Level 1', '2016-06-12 8:30:00.000'),
(1002, '2016-06-01', 'Mary', 'Somers', 'Level 1', '2016-06-01 8:30:00.000'),
(1002, '2016-06-05', 'Mary', 'Somers', 'Level 1', '2016-06-05 8:30:00.000'),
(1002, '2016-06-08', 'Mary', 'Somers', 'Level 1', '2016-06-08 8:30:00.000'),
(1003, '2016-06-03', 'Mark', 'Jones ', 'Level 1', '2016-06-03 8:30:00.000'),
(1003, '2016-06-05', 'Mark', 'Jones ', 'Level 1', '2016-06-05 8:30:00.000');
Abfrage
Abfrage verwendet CROSS APPLY
zum "Einfügen" von Zeilen bei Datumslücken. Es dupliziert die aktuelle Zeile mithilfe Ihres Tally
so oft wie nötig Zahlentabelle.
Es gibt eine Sonderbehandlung für den Fall, dass @StartDate
vor dem Datum der ersten Zeile liegt. Deshalb gibt es zwei SELECTs
zusammengeschlossen.
Das CTE.PrevDate IS NULL
filtert nur solche Zeilen und sie werden so oft wie nötig wiederholt.
WITH
CTE
AS
(
SELECT *
,LAG(dt) OVER (PARTITION BY Staff_ID ORDER BY dt) AS PrevDate
,LEAD(dt) OVER (PARTITION BY Staff_ID ORDER BY dt) AS NextDate
FROM @Table_One AS T
)
SELECT
Staff_ID
,NewDate
,First_Name
,Last_Name
,Section
,CASE WHEN NewDate = dt THEN Time_Worked ELSE NULL END AS Time_Worked
FROM
CTE
CROSS APPLY
(
SELECT DATEADD(day, Tally.ID - 1, CTE.dt) AS NewDate
FROM dbo.Tally
WHERE Tally.ID <= DATEDIFF(day, CTE.dt, ISNULL(CTE.NextDate, @EndDate))
) AS CA_Next
UNION ALL
SELECT
Staff_ID
,NewDate
,First_Name
,Last_Name
,Section
,CASE WHEN NewDate = dt THEN Time_Worked ELSE NULL END AS Time_Worked
FROM
CTE
CROSS APPLY
(
SELECT DATEADD(day, - Tally.ID, CTE.dt) AS NewDate
FROM dbo.Tally
WHERE Tally.ID <= DATEDIFF(day, @StartDate, CTE.dt)
) AS CA_Prev
WHERE
CTE.PrevDate IS NULL
ORDER BY Staff_ID, NewDate;
Ergebnis
+----------+------------+------------+-----------+---------+-------------------------+
| Staff_ID | NewDate | First_Name | Last_Name | Section | Time_Worked |
+----------+------------+------------+-----------+---------+-------------------------+
| 1001 | 2016-06-01 | Bill | Price | Level 1 | 2016-06-01 08:30:00.000 |
| 1001 | 2016-06-02 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-03 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-04 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-05 | Bill | Price | Level 1 | 2016-06-05 08:30:00.000 |
| 1001 | 2016-06-06 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-07 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-08 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-09 | Bill | Price | Level 1 | 2016-06-09 08:30:00.000 |
| 1001 | 2016-06-10 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-11 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-12 | Bill | Price | Level 1 | 2016-06-12 08:30:00.000 |
| 1001 | 2016-06-13 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-14 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-15 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-16 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-17 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-18 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-19 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-20 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-21 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-22 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-23 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-24 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-25 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-26 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-27 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-28 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-29 | Bill | Price | Level 1 | NULL |
| 1001 | 2016-06-30 | Bill | Price | Level 1 | NULL |
| 1002 | 2016-06-01 | Mary | Somers | Level 1 | 2016-06-01 08:30:00.000 |
| 1002 | 2016-06-02 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-03 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-04 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-05 | Mary | Somers | Level 1 | 2016-06-05 08:30:00.000 |
| 1002 | 2016-06-06 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-07 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-08 | Mary | Somers | Level 1 | 2016-06-08 08:30:00.000 |
| 1002 | 2016-06-09 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-10 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-11 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-12 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-13 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-14 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-15 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-16 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-17 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-18 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-19 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-20 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-21 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-22 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-23 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-24 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-25 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-26 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-27 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-28 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-29 | Mary | Somers | Level 1 | NULL |
| 1002 | 2016-06-30 | Mary | Somers | Level 1 | NULL |
| 1003 | 2016-06-01 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-02 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-03 | Mark | Jones | Level 1 | 2016-06-03 08:30:00.000 |
| 1003 | 2016-06-04 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-05 | Mark | Jones | Level 1 | 2016-06-05 08:30:00.000 |
| 1003 | 2016-06-06 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-07 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-08 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-09 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-10 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-11 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-12 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-13 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-14 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-15 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-16 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-17 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-18 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-19 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-20 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-21 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-22 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-23 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-24 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-25 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-26 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-27 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-28 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-29 | Mark | Jones | Level 1 | NULL |
| 1003 | 2016-06-30 | Mark | Jones | Level 1 | NULL |
+----------+------------+------------+-----------+---------+-------------------------+
Einfügen der generierten Zeilen zurück in die ursprüngliche Tabelle
Zuerst war mir nicht klar, dass Sie die ursprüngliche Tabelle ändern möchten, also habe ich ein SELECT
geschrieben Abfrage, die eine benötigte Ergebnismenge zurückgibt. Es ist einfach, es auf INSERT
einzustellen Abfrage, die der ursprünglichen Tabelle neue Zeilen hinzufügen würde.
Ich habe lediglich einen Filter WHERE NewDate <> dt
hinzugefügt , wodurch sichergestellt wird, dass nur neue Zeilen eingefügt werden, die vorher nicht existierten.
WITH
CTE
AS
(
SELECT
Staff_ID
,dt
,First_Name
,Last_Name
,Section
,Time_Worked
,LAG(dt) OVER (PARTITION BY Staff_ID ORDER BY dt) AS PrevDate
,LEAD(dt) OVER (PARTITION BY Staff_ID ORDER BY dt) AS NextDate
FROM @Table_One AS T
)
INSERT INTO @Table_One(Staff_ID, dt, First_Name, Last_Name, Section, Time_Worked)
SELECT
Staff_ID
,NewDate
,First_Name
,Last_Name
,Section
,NULL AS Time_Worked
FROM
CTE
CROSS APPLY
(
SELECT DATEADD(day, Tally.ID - 1, CTE.dt) AS NewDate
FROM dbo.Tally
WHERE Tally.ID <= DATEDIFF(day, CTE.dt, ISNULL(CTE.NextDate, @EndDate))
) AS CA_Next
WHERE
NewDate <> dt
UNION ALL
SELECT
Staff_ID
,NewDate
,First_Name
,Last_Name
,Section
,NULL AS Time_Worked
FROM
CTE
CROSS APPLY
(
SELECT DATEADD(day, - Tally.ID, CTE.dt) AS NewDate
FROM dbo.Tally
WHERE Tally.ID <= DATEDIFF(day, @StartDate, CTE.dt)
) AS CA_Prev
WHERE
CTE.PrevDate IS NULL
ORDER BY Staff_ID, NewDate;
Ergebnis
Um das Ergebnis zu überprüfen, einfach SELECT
alles aus der Originaltabelle.
SELECT * FROM @Table_One ORDER BY Staff_ID, dt;
Das Ergebnis ist das gleiche wie oben gezeigt.