将日期范围拆分为单独的记录

Far*_*jar 8 sql-server sql-server-2014

今天我在拆分日期范围时遇到了问题,因此它变成了两个单独的记录。

这是一个例子

----------------------------------------------------------------
| Record id | date_from               | date_to                |
----------------------------------------------------------------
|     A     | 2017-02-03 08:00:00.000 | 2017-02-04 17:00:00.000|
----------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

结果我想要这个

----------------------------------------------------------------
| Record id | date_from               | date_to                |
----------------------------------------------------------------
|     A     | 2017-02-03 08:00:00.000 | 2017-02-03 23:59:59.000|
----------------------------------------------------------------
|     A     | 2017-02-04 00:00:00.000 | 2017-02-04 17:00:00.000|
----------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

有什么可以启发我解决这个问题吗?非常感谢您的建议。

PS:这是动态的,持续时间没有限制。如果“从”日是 2017-02-02 的 17:00,“到”日是 2017-02-04 17:00,那么将有 3 条记录,其中一条是日期范围从 2017-02- 03 00:00:00 至 2017-02-03 23:59:59。

对于午夜,我猜它是基于日期时间默认值。对于真正的问题,我有这张表:

在此处输入图片说明

正如你所看到的,从播种邮箱数据库的细节来看,范围就像假设的某一天,所以我想它更像是那个例子:)

PS:我使用的是 SQL Server 2014。

Vla*_*nov 7

一种方法是使用数字表CROSS APPLY

样本数据

DECLARE @T TABLE (RecordID int, date_from datetime2(0), date_to datetime2(0));

INSERT INTO @T (RecordID, date_from, date_to) VALUES
(1, '2017-02-03 08:00:00' , '2017-02-04 17:00:00'),
(2, '2017-02-05 08:00:00' , '2017-02-05 17:00:00'),
(3, '2017-02-06 08:00:00' , '2017-02-10 17:00:00');
Run Code Online (Sandbox Code Playgroud)

询问

In this example I generated a table of 10 numbers on the fly (CTE_Numbers). In production I have a permanent table with 100K numbers.

WITH 
CTE_Numbers1(n)
AS
(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,CTE_Numbers
AS
(
    SELECT ROW_NUMBER() OVER (ORDER BY n) AS Number
    FROM CTE_Numbers1
)
SELECT
    T.RecordID
    ,CASE WHEN CA.Number0 = 0
    THEN date_from
    ELSE DATEADD(day, CA.Number0, CAST(T.date_from as date))
    END AS new_date_from
    ,CASE WHEN CA.Number0 = DATEDIFF(day, T.date_from, T.date_to)
    THEN date_to
    ELSE DATEADD(day, CA.Number0 + 1, CAST(T.date_from as date))
    END AS new_date_to
FROM
    @T AS T
    CROSS APPLY
    (
        SELECT CTE_Numbers.Number - 1 AS Number0
        FROM CTE_Numbers
        WHERE CTE_Numbers.Number <= DATEDIFF(day, T.date_from, T.date_to) + 1
    ) AS CA
ORDER BY
    RecordID
    ,new_date_from
;
Run Code Online (Sandbox Code Playgroud)

结果

+----------+---------------------+---------------------+
| RecordID |    new_date_from    |     new_date_to     |
+----------+---------------------+---------------------+
|        1 | 2017-02-03 08:00:00 | 2017-02-04 00:00:00 |
|        1 | 2017-02-04 00:00:00 | 2017-02-04 17:00:00 |
|        2 | 2017-02-05 08:00:00 | 2017-02-05 17:00:00 |
|        3 | 2017-02-06 08:00:00 | 2017-02-07 00:00:00 |
|        3 | 2017-02-07 00:00:00 | 2017-02-08 00:00:00 |
|        3 | 2017-02-08 00:00:00 | 2017-02-09 00:00:00 |
|        3 | 2017-02-09 00:00:00 | 2017-02-10 00:00:00 |
|        3 | 2017-02-10 00:00:00 | 2017-02-10 17:00:00 |
+----------+---------------------+---------------------+
Run Code Online (Sandbox Code Playgroud)