【问题标题】:Slice a row containing time range into multiple rows (tricky sql question)将包含时间范围的行切成多行(棘手的 sql 问题)
【发布时间】:2020-08-01 07:43:06
【问题描述】:

首先,我无法指定标题来包含我的整个问题。我很抱歉。

我的目标是在更改某些列值的同时将行相乘,直到满足某个条件。是的,糟糕的解释。

我有:

CREATE TABLE OldTable 
(
    fullname varchar(50) NOT NULL,
    unit varchar(50) NOT NULL,
    code int NOT NULL,
    shift_datetime datetime NOT NULL,
    timespan int NOT NULL
)

INSERT INTO OldTable (fullname, unit, code, shift_datetime, timespan) 
VALUES ('John Smith', 'Heroes', '239', '2020-03-04 13:35:00.000', '55'
'Tom Cruise', 'Heroes', '213', '2020-03-05 09:13:00.000', '8'
'My Mom', 'Heroes', '483', '2020-02-01 08:57:00.000', '16')

生成此表,OldTable

| fullname   | unit   | code | shift_datetime          | timespan |
+------------+--------+------+-------------------------+----------+
| John Smith | Heroes | 239  | 2020-03-04 13:35:00.000 |      55  |
| Tom Cruise | Heroes | 213  | 2020-03-05 09:13:00.000 |       8  |
| Mom        | Heroes | 483  | 2020-02-01 08:57:00.000 |      16  |

我想创建这个NewTable

| fullname   | unit   | code | shift_datetime          | timespan |
+------------+--------+------+-------------------------+----------+
| John Smith | Heroes | 239  | 2020-03-04 13:35:00.000 |      15  |
| John Smith | Heroes | 239  | 2020-03-04 13:50:00.000 |      15  |
| John Smith | Heroes | 239  | 2020-03-04 14:05:00.000 |      15  |
| John Smith | Heroes | 239  | 2020-03-04 14:20:00.000 |      10  |
| Tom Cruise | Heroes | 213  | 2020-03-05 09:13:00.000 |       8  |
| Mom        | Heroes | 483  | 2020-02-01 08:57:00.000 |      15  |
| Mom        | Heroes | 483  | 2020-02-01 08:12:00.000 |       1  |

所以问题的表述是相当的

if span > 15,然后分成floor(span/15) 行和span = 15 在每一行,同时将shift_datetime 每添加一行增加15 miutes,最后添加span = span %% 15 的最后一行并添加那些span %% 15 分钟到该“循环”中的最大 shift_datetime 值。

如果您对如何“解决”这个问题有任何想法,我将不胜感激。我不是只是在寻找解决方案,但我非常期待有关如何处理此类问题的建议。

我可以通过循环在 R 中做到这一点,所以我假设这也可以通过 SQL 中的循环来完成。但是,我很想听听其他选择或想法。

【问题讨论】:

    标签: sql sql-server loops split


    【解决方案1】:

    听起来递归 CTE 可以提供帮助:

    with cte as (
          select fullname, unit, code, shift_datetime, 
                 (case when timespan > 15 then 15 else timespan end) as timespan,
                 timespan as time_remaining, 1 as lev
          from oldtable
          union all
          select fullname, unit, code,
                 dateadd(minute, 15, shift_datetime),
                 (case when time_remaining > 15 then 15 else time_remaining end) as timespan,
                 time_remaining - 15, lev + 1
          from cte
          where time_remaining > 15
         )
    select * 
    from cte
    order by 1, lev;
    

    Here 是一个 dbfiddle。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 2019-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多