对于两个日期之间的每一天,添加一行,其中包含相同的信息但仅在开始/结束列中的那一天

时间:2014-12-15 17:23:32

标签: sql sql-server datetime insert

我有一个表格,类型为varchardatetimedatetime

NAME | START | END
Bob  | 10/30 | 11/2

我可以查看什么是SQL查询以了解如何使该表成为?:

NAME | START | END
Bob  | 10/30 | 10/30
Bob  | 10/31 | 10/31
Bob  | 11/01 | 11/01
Bob  | 11/02 | 11/02

这只运行一次,并且在一个非常小的数据集上运行。不需要优化。

4 个答案:

答案 0 :(得分:8)

您可能需要Recursive CTE

CREATE TABLE #dates(NAME  VARCHAR(50),START DATETIME,[END] DATETIME)

INSERT INTO #dates
VALUES      ('Bob','2014-10-30','2014-11-02')

DECLARE @maxdate DATETIME = (SELECT Max([end]) FROM   #dates);

WITH cte
     AS (SELECT NAME,
                START,
                [END]
         FROM   #dates
         UNION ALL
         SELECT NAME,
                Dateadd(day, 1, start),
                Dateadd(day, 1, start)
         FROM   cte
         WHERE  start < @maxdate)
SELECT *
FROM   cte 

输出:

name    START       END
----    ----------  ----------
Bob     2014-10-30  2014-10-30
Bob     2014-10-31  2014-10-31
Bob     2014-11-01  2014-11-01
Bob     2014-11-02  2014-11-02

答案 1 :(得分:8)

您可以使用递归cte:

执行此操作
;with cte AS (SELECT Name,Start,[End]
              FROM YourTable
              UNION  ALL
              SELECT Name
                    ,DATEADD(day,1,Start)
                    ,[End]
              FROM cte
              WHERE Start < [End])
SELECT Name, Start, Start AS [End]
FROM cte

但是,我建议创建一个日历表并加入它:

SELECT a.Name,b.CalendarDate AS Start, b.CalendarDate AS [End]
FROM YourTable a
JOIN tlkp_Calendar b
  ON b.CalendarDate BETWEEN a.[Start] AND a.[End]

两个查询的演示:SQL Fiddle

答案 2 :(得分:1)

;WITH dates
 AS (SELECT (SELECT MIN(start) from table) as date,
     UNION ALL
     SELECT
            Dateadd(day, 1, date),
     FROM   dates
     WHERE  date < (SELECT MAX(end) from table))

SELECT name, date as start, date as end
from table
RIGHT JOIN dates on date between start and end

答案 3 :(得分:0)

我在此问题/答案中遇到的问题是仅用于一条记录。我在此答案中找到了一个简单有效的解决方案-SQL how to convert row with date range to many rows with each date

“ RichardTheKiwi”的解决方案涉及基于整数表(列表)添加新的日期记录,并通过使用datediff函数评估日期范围来加入源表。您可以直接从SQL Server主数据库(SELECT master..spt_values WHERE v.type='P')中提取整数列表。

Google搜索词sql spt_values,关于此表有很多有趣的博客文章。例如...

完整解决方案:

--NAME | START | END
--Bob  | 10/30 | 11/2

DECLARE @SampleData as table 
    (PersonName nvarchar(50), StartDate date, EndDate date)
INSERT INTO @SampleData
    (PersonName, StartDate, EndDate)
VALUES
    ('Bob', '2019-10-30', '2019-11-02')
    , ('Joe', '2019-10-30', '2019-11-05')
;

WITH 
cteSampleData_RecordAdded AS
-- NOTE: Range record converted to daily records for 'SampleData'
(
    SELECT 
        T1.PersonName
        , T1.StartDate
        , T1.EndDate
        , DATEADD(d,v.number,T1.StartDate) AS [NewRecordDate]
        , DATEDIFF(day, T1.StartDate, T1.EndDate)+1 AS [QDaysActive]
    FROM 
        @SampleData T1
        -- Adds a record for each date in the range
        JOIN MASTER..spt_values v 
            ON v.type='P'AND v.number BETWEEN 0 AND datediff(d, T1.StartDate, T1.EndDate)
)

select * from cteSampleData_RecordAdded

结果:

+------------+------------+-----------+---------------+-------------+
| PersonName | StartDate  | EndDate   | NewRecordDate | QDaysActive |
+------------+------------+-----------+---------------+-------------+
| Bob        | 10/30/2019 | 11/2/2019 | 10/30/2019    | 4           |
+------------+------------+-----------+---------------+-------------+
| Bob        | 10/30/2019 | 11/2/2019 | 10/31/2019    | 4           |
+------------+------------+-----------+---------------+-------------+
| Bob        | 10/30/2019 | 11/2/2019 | 11/1/2019     | 4           |
+------------+------------+-----------+---------------+-------------+
| Bob        | 10/30/2019 | 11/2/2019 | 11/2/2019     | 4           |
+------------+------------+-----------+---------------+-------------+
| Joe        | 10/30/2019 | 11/5/2019 | 10/30/2019    | 7           |
+------------+------------+-----------+---------------+-------------+
| Joe        | 10/30/2019 | 11/5/2019 | 10/31/2019    | 7           |
+------------+------------+-----------+---------------+-------------+
| Joe        | 10/30/2019 | 11/5/2019 | 11/1/2019     | 7           |
+------------+------------+-----------+---------------+-------------+
| Joe        | 10/30/2019 | 11/5/2019 | 11/2/2019     | 7           |
+------------+------------+-----------+---------------+-------------+
| Joe        | 10/30/2019 | 11/5/2019 | 11/3/2019     | 7           |
+------------+------------+-----------+---------------+-------------+
| Joe        | 10/30/2019 | 11/5/2019 | 11/4/2019     | 7           |
+------------+------------+-----------+---------------+-------------+
| Joe        | 10/30/2019 | 11/5/2019 | 11/5/2019     | 7           |
+------------+------------+-----------+---------------+-------------+