Exemples de données
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');
Requête
La requête utilise CROSS APPLY
pour "insérer" des lignes lorsqu'il y a un écart dans les dates. Il duplique la ligne actuelle autant de fois que nécessaire en utilisant votre Tally
tableau des nombres.
Il y a un traitement spécial du cas où le @StartDate
est avant la date de la première ligne. C'est pourquoi il y a deux SELECTs
réunis.
Le CTE.PrevDate IS NULL
filtre uniquement ces lignes et elles sont répétées autant de fois que nécessaire.
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;
Résultat
+----------+------------+------------+-----------+---------+-------------------------+
| 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 |
+----------+------------+------------+-----------+---------+-------------------------+
Réinsérer les lignes générées dans la table d'origine
Au début, je n'avais pas réalisé que vous vouliez changer la table d'origine, alors j'ai écrit un SELECTs
requête qui renvoie un jeu de résultats nécessaire. Il est facile de l'ajuster à INSERT
requête qui ajouterait de nouvelles lignes dans la table d'origine.
Tout ce que j'ai fait est d'ajouter un filtre WHERE NewDate <> dt
, ce qui garantit que seules les nouvelles lignes qui n'existaient pas auparavant sont insérées.
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;
Résultat
Pour vérifier le résultat, il suffit de SELECTs
tout de la table d'origine.
SELECT * FROM @Table_One ORDER BY Staff_ID, dt;
Le résultat est le même que celui indiqué ci-dessus.