如果将给定日期的总时数值超过午夜,则在不同日期拆分行

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如果将给定日期的总时数值超过午夜,则在不同日期拆分行相关的知识,希望对你有一定的参考价值。

我有这样的结构

+-----+-----+------------+----------+------+----------------------+---+
| Row | id  |    date    |   time   | hour |     description      |   |
+-----+-----+------------+----------+------+----------------------+---+
|   1 | foo | 2018-03-02 | 19:00:00 |    8 | across single day    |   |
|   2 | bar | 2018-03-02 | 23:00:00 |    1 | end at midnight      |   |
|   3 | qux | 2018-03-02 | 10:00:00 |    3 | inside single day    |   |
|   4 | quz | 2018-03-02 | 23:15:00 |    2 | with minutes         |   |
+-----+-----+------------+----------+------+----------------------+---+

(我添加了description列只是为了理解上下文,因为分析目的是没用的)

这是生成表的语句

WITH table AS ( 
  SELECT "foo" as id, CURRENT_dATE() AS date, TIME(19,0,0) AS time,8 AS hour
  UNION ALL
  SELECT "bar", CURRENT_dATE(), TIME(23,0,0), 1
  UNION ALL
  SELECT "qux", CURRENT_dATE(), TIME(10,0,0), 3
  UNION ALL
  SELECT "quz", CURRENT_dATE(), TIME(23,15,0), 2
) 

SELECT * FROM table

hour值添加到给定时间,我需要将行分成多个,如果总和在第二天进行。

不要考虑多天的跳跃,比如+27小时(这应该简化场景)

我最初的想法是从日期字段中添加小时值开始,以获得间隔的开始和结束限制

SELECT
  id,
  DATETIME(date, time) AS date_start,
  DATETIME_ADD(DATETIME(date, time), INTERVAL hour HOUR) AS date_end
FROM table

这是结果

+-----+-----+---------------------+---------------------+---+
| Row | id  |     date_start      |      date_end       |   |
+-----+-----+---------------------+---------------------+---+
|   1 | foo | 2018-03-02T19:00:00 | 2018-03-03T03:00:00 |   |
|   2 | bar | 2018-03-02T23:00:00 | 2018-03-03T00:00:00 |   |
|   3 | qux | 2018-03-02T10:00:00 | 2018-03-02T13:00:00 |   |
|   4 | quz | 2018-03-02T23:15:00 | 2018-03-03T01:15:00 |   |
+-----+-----+---------------------+---------------------+---+

但现在我仍然坚持考虑现有的间隔时间。

从这个表开始,行应该分为日更改,例如

+-----+-----+------------+-------------+----------+-------+--+
| Row | id  |    date    | hourt_start | hour_end | hours |  |
+-----+-----+------------+-------------+----------+-------+--+
|   1 | foo | 2018-03-02 | 19:00:00    | 00:00:00 |     5 |  |
|   2 | foo | 2018-03-03 | 00:00:00    | 03:00:00 |     3 |  |
|   3 | bar | 2018-03-02 | 23:00:00    | 00:00:00 |     1 |  |
|   4 | qux | 2018-03-02 | 10:00:00    | 13:00:00 |     3 |  |
|   5 | quz | 2018-03-02 | 23:15:00    | 00:00:00 |  0.75 |  |
|   6 | quz | 2018-03-03 | 00:00:00    | 01:15:00 |  1.25 |  |
+-----+-----+------------+-------------+----------+-------+--+

我尝试从已经analyzed scenario研究类似的场景,但我也无法调整它来处理日期组件。

我的整个最终场景将包括这种方法和另一个问题中分析的另一个方法(在单日拆分,然后在给定的休息时间拆分),但我可以分别处理这两个主题,首先查询与日分开(这个问题) )然后按时间划分(其他问题)

答案

有趣的问题......我尝试了以下方法:

  • 创建第二个表,创建从午夜开始的所有新行
  • UNION ALL它与源表,同时相应地纠正旧行的小时

评论结果:

WITH table AS ( 
  SELECT "foo" as id, CURRENT_dATE() AS date, TIME(19,0,0) AS time,8 AS hour
  UNION ALL
  SELECT "bar", CURRENT_dATE(), TIME(23,0,0), 1
  UNION ALL
  SELECT "qux", CURRENT_dATE(), TIME(10,0,0), 3
) 

,table2 AS (
  SELECT
    id,
    -- create datetime, add hours, then cast as date again
    CAST( datetime_add( datetime(date, time), INTERVAL hour HOUR) AS date) date,
    time(0,0,0) AS time -- losing minutes and seconds
    -- substract hours to midnight
    ,hour - (24-EXTRACT(HOUR FROM time)) hour
  FROM
    table
  WHERE
    date != CAST( datetime_add( datetime(date,time), INTERVAL hour HOUR) AS date) )

SELECT
  id
  ,date
  ,time 
  -- correct hour if midnight split
  ,IF(EXTRACT(hour from time)+hour > 24,24-EXTRACT(hour from time),hour) hour
FROM
  table
UNION ALL
SELECT
  *
FROM
  table2

希望,这是有道理的。当然,如果您需要考虑多天跳转,则更正失败:)

另一答案

这是一个可能的解决方案,我从@Martin Weitzman方法开始。

我用了两种不同的方式:

  • 当天有“跳跃”的ids
  • 在同一天的ID

以及两个数据的最终UNION ALL

我忘了第一次提到输入值的小时值可以浮动(小时的一部分),所以我也加了。

#standardSQL
WITH 

input AS (
  -- change of day
  SELECT "bap" as id, CURRENT_dATE() AS date, TIME(19,0,0) AS time, 8.0 AS hour UNION ALL
  -- end at midnight
  SELECT "bar", CURRENT_dATE(), TIME(23,0,0), 1.0 UNION ALL
  -- inside single day
  SELECT "foo", CURRENT_dATE(), TIME(10,0,0), 3.0 UNION ALL
  -- change of day with minutes and float hours
  SELECT "qux", CURRENT_dATE(), TIME(23,15,0), 2.5 UNION ALL
  -- start from midnight
  SELECT "quz",CURRENT_dATE(), TIME(0,0,0), 4.5
),

-- Calculate end_date and end_time summing hours value    
table AS (
  SELECT
    id,
    date AS start_date,
    time AS start_time,
    EXTRACT(DATE FROM DATETIME_ADD(DATETIME(date,time), INTERVAL CAST(hour*3600 AS INT64) SECOND)) AS end_date,
    EXTRACT(TIME FROM DATETIME_ADD(DATETIME(date,time), INTERVAL CAST(hour*3600 AS INT64) SECOND)) AS end_time
  FROM input
),

-- portion that start from start_time and end at midnight
start_to_midnight AS (
  SELECT
    id,
    start_time,
    start_date,
    TIME(23,59,59) as end_time,
    start_date as end_date
  FROM
    table
  WHERE end_date > start_date
),

-- portion that start from midnightand end at end_time
midnight_to_end AS (
  SELECT
   id,
   TIME(0,0,0) as start_time,
   end_date as start_date,
   end_time,
   end_date
  FROM
   table
  WHERE
   end_date > start_date 
   -- Avoid rows that starts from 0:0:0 and ends to 0:0:0 (original row ends at 0:0:0)
   AND end_time != TIME(0,0,0)
)

-- Union of the 3 tables
SELECT
  id,
  start_date,
  start_time,
  end_time

FROM (
  SELECT id, start_time, end_time, start_date FROM table WHERE start_date = end_date
  UNION ALL
  SELECT id, start_time, end_time, start_date FROM start_to_midnight
  UNION ALL
  SELECT id, start_time, end_time, start_date FROM midnight_to_end
)

ORDER BY id,start_date,start_time

这是提供的输出

+-----+-----+------------+------------+----------+---+
| Row | id  | start_date | start_time | end_time |   |
+-----+-----+------------+------------+----------+---+
|   1 | bap | 2018-03-03 | 19:00:00   | 23:59:59 |   |
|   2 | bap | 2018-03-04 | 00:00:00   | 03:00:00 |   |
|   3 | bar | 2018-03-03 | 23:00:00   | 23:59:59 |   |
|   4 | foo | 2018-03-03 | 10:00:00   | 13:00:00 |   |
|   5 | qux | 2018-03-03 | 23:15:00   | 23:59:59 |   |
|   6 | qux | 2018-03-04 | 00:00:00   | 01:45:00 |   |
|   7 | quz | 2018-03-03 | 00:00:00   | 04:30:00 |   |
+-----+-----+------------+------------+----------+---+

以上是关于如果将给定日期的总时数值超过午夜,则在不同日期拆分行的主要内容,如果未能解决你的问题,请参考以下文章

如何仅查询 HealthKit 以获取给定日期的总“在床上”时间?

给定 UTC 时间,获取特定时区是午夜

MDX - 到给定日期的总成本

如何在python中查找给定日期每周的总播放时间?

django python 日期时间设置为午夜

如何确保保存在数据库中的UTC日期等于Django中指定时区的午夜[重复]