sql >> データベース >  >> RDS >> Sqlserver

2つの日付の間に欠落している日付を挿入するための集計表? SQL

    サンプルデータ

    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');
    

    クエリ

    クエリはCROSS APPLYを使用します 日付にギャップがある場合に行を「挿入」します。 Tallyを使用して、現在の行を必要な回数だけ複製します 数字の表。

    @StartDateの場合、特別な処理が行われます。 最初の行の日付の前です。そのため、2つのSELECTsがあります 一緒に結合しました。

    CTE.PrevDate IS NULL そのような行のみをフィルタリングし、必要な回数だけ繰り返されます。

    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;
    

    結果

    +----------+------------+------------+-----------+---------+-------------------------+
    | 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                    |
    +----------+------------+------------+-----------+---------+-------------------------+
    

    生成された行を元のテーブルに挿入し直します

    最初は元のテーブルを変更したいと思っていなかったので、SELECTを作成しました。 必要な結果セットを返すクエリ。 INSERTに調整するのは簡単です 元のテーブルに新しい行を追加するクエリ。

    私がしたのは、フィルターWHERE NewDate <> dtを追加することだけです。 、これにより、以前は存在しなかった新しい行のみが挿入されます。

    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;
    

    結果

    結果を確認するには、SELECTだけです。 元のテーブルのすべて。

    SELECT * FROM @Table_One ORDER BY Staff_ID, dt;
    

    結果は上記と同じです。



    1. 下位バージョンでのSQLServerデータベースのバックアップの復元

    2. SQLiteConnectionオブジェクトのリークを防ぐことができません

    3. MySQLバージョンを確認する方法

    4. SQL Serverで動的SQLをクレンジング(SQLインジェクションを防止)する方法は?