2016-12-15 25 views
1
最小值

我有以下SQL表:在給定時間獲取在SQL

start_time   end_time   value 
2016-01-01 00:00:00 2016-01-01 08:59:59 1 
2016-01-01 06:00:00 2016-01-01 14:59:59 2 
2016-01-01 12:00:00 2016-01-01 17:59:59 1.5 
2016-01-01 03:00:00 2016-01-01 17:59:59 3 

我想把它轉換成:

start_time   end_time   min_value 
2016-01-01 00:00:00 2016-01-01 08:59:59 1 
2016-01-01 09:00:00 2016-01-01 11:59:59 2 
2016-01-01 12:00:00 2016-01-01 17:59:59 1.5 

其中min_value是在給定點的最小value及時。是否有可能在SQL中做到這一點?

+1

這是一個非常困難的問題。 –

+1

@戈登林諾夫 - 同意,比這裏的常見問題複雜一點:o) –

回答

1

請嘗試以下。我認爲這不正是你問
正如你所看到的 - 我加在你的例子一個條目,使其一點點辣:O)

WITH YourTable AS (
SELECT TIMESTAMP '2016-01-01 00:00:00' AS start_time, TIMESTAMP '2016-01-01 08:59:59' AS end_time, 1 AS value UNION ALL 
SELECT TIMESTAMP '2016-01-01 06:00:00' AS start_time, TIMESTAMP '2016-01-01 14:59:59' AS end_time, 2 AS value UNION ALL 
SELECT TIMESTAMP '2016-01-01 12:00:00' AS start_time, TIMESTAMP '2016-01-01 17:59:59' AS end_time, 1.5 AS value UNION ALL 
SELECT TIMESTAMP '2016-01-01 03:00:00' AS start_time, TIMESTAMP '2016-01-01 17:59:59' AS end_time, 3 AS value UNION ALL 
SELECT TIMESTAMP '2016-01-01 12:30:00' AS start_time, TIMESTAMP '2016-01-01 12:40:59' AS end_time, 1 AS value 
), 
Intervals AS (
    SELECT iStart AS start_time, LEAD(iStart) OVER(ORDER BY iStart) AS end_time 
    FROM (
    SELECT DISTINCT iStart FROM (
     SELECT start_time AS iStart FROM YourTable UNION ALL 
     SELECT end_time AS iStart FROM YourTable) 
) 
), 
Intervals_Mins AS (
    SELECT b.start_time, b.end_time, MIN(value) AS min_value 
    FROM YourTable AS a 
    JOIN Intervals AS b 
    ON b.start_time BETWEEN a.start_time AND a.end_time 
    AND b.end_time BETWEEN a.start_time AND a.end_time 
    GROUP BY b.start_time, b.end_time 
), 
Intervals_Group AS (
    SELECT start_time, end_time, min_value, IFNULL(SUM(flag) OVER(PARTITION BY CAST(min_value AS STRING) ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) AS time_group 
    FROM (
    SELECT start_time, end_time, min_value, IF(end_time = LEAD(start_time) OVER(PARTITION BY CAST(min_value AS STRING) ORDER BY start_time), 0, 1) AS flag 
    FROM Intervals_Mins 
) 
) 
SELECT MIN(start_time) AS start_time, MAX(end_time) AS end_time, min_value 
FROM Intervals_Group 
GROUP BY min_value, time_group 
-- ORDER BY start_time 
0

我不知道,我明白了預期的輸出如何與投入,但如果你只是想用不同的(start_timeend_time)對最小值相關聯,你可以做如:

#standardSQL 
WITH T AS (
    SELECT TIMESTAMP '2016-01-01 00:00:00' AS start_time, 
    TIMESTAMP '2016-01-01 08:59:59' AS end_time, 1 AS value UNION ALL 
    SELECT TIMESTAMP '2016-01-01 06:00:00', 
    TIMESTAMP '2016-01-01 14:59:59', 2 UNION ALL 
    SELECT TIMESTAMP '2016-01-01 12:00:00', 
    TIMESTAMP '2016-01-01 17:59:59', 1.5 UNION ALL 
    SELECT TIMESTAMP '2016-01-01 3:00:00', 
    TIMESTAMP '2016-01-01 17:59:59', 3 
) 
SELECT 
    start_time, 
    end_time, 
    MIN(value) AS min_value 
FROM T 
GROUP BY start_time, end_time; 
1

嗯。 。 。這似乎很難。我認爲以下策略將起作用:

  1. 將數據分爲兩部分:開始時間和結束時間。
  2. 對於每個開始時間計算當時有效的最小值。
  3. 對於每個結束時間,計算此時開始生效的最小值。
  4. 複合使用的差距和離島的做法

我只是不能100%肯定,你可以在BQ做到這一點,因爲它涉及到非等值連接。但是。 。 。

with starts as (
     select start_time as time, 
      (select min(t2.value) 
       from t t2 
       where t.start_time between t2.start_time and t2.end_time 
      ) as value 
     from t 
    ), 
    ends as (
     select end_time as time, 
      (select min(t2.value) 
       from t t2 
       where t2.end_time > t.end_time and 
        t2.start_time <= t.end_time 
      ) as value 
     from t 
    ) 
select value, min(time), max(time) 
from (select time, 
      row_number() over (order by time) as seqnum, 
      row_number() over (partition by value order by time) as seqnum_v 
     from ((select s.* from starts) union all 
      (select e.* from ends) 
      ) t 
    ) t 
group by value, (seqnum - seqnum_v); 
相關問題