【问题标题】:SQL how to query two date windows in one table based on a date in another table optimally?SQL如何根据另一个表中的日期优化查询一个表中的两个日期窗口?
【发布时间】:2022-01-20 09:03:13
【问题描述】:

例如,获取两者:

  • table_1 中日期前 5 天与 table_2 中每日值的最大值
  • table_1 中的日期后 5 天与 table_2 中的每日值的最大值

table1 (uid = id) - 日期窗口基于此表中的日期

id date
a 2021-12-10
b 2021-12-21

表 2 (uid = id + date) - 每日表

id date value
a 2021-12-01 0
a 2021-12-02 3
a ... ...
a 2021-12-31 1
b 2021-12-01 4
b ... ...
b 2021-12-31 0

输出表(uid = id)

id date start_dt_before end_dt_before max_value_before start_dt_after end_dt_after max_value_after
a 2021-12-10 2021-12-05 2021-12-09 3 2021-12-10 2021-12-14 4
b 2021-12-21 2021-12-16 2021-12-20 2 2021-12-21 2021-12-25 5

在两个单独的连接中两次查询其中一个表似乎非常耗费资源。有没有办法在单个查询中更优化地查询这个?

编辑——为每个请求添加示例代码

-- Create table_1
CREATE TABLE table_1 (id CHAR(1), event_dt DATE);
INSERT INTO table_1 (id,event_dt) VALUES ('a','2021-12-10');
INSERT INTO table_1 (id,event_dt) VALUES ('b','2021-12-21');


-- Create table_2

CREATE TABLE table_2 (id CHAR(1), day_dt DATE, value INT);

INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-01',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-02',3);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-03',7);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-04',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-05',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-06',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-07',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-08',3);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-09',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-10',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-11',4);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-12',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-13',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-14',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-15',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-16',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-17',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-18',9);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-19',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-20',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-21',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-22',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-23',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-24',9);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-25',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-26',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-27',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-28',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-29',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-30',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('a','2021-12-31',1);

INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-01',4);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-02',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-03',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-04',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-05',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-06',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-07',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-08',9);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-09',9);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-10',9);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-11',9);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-12',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-13',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-14',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-15',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-16',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-17',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-18',2);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-19',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-20',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-21',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-22',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-23',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-24',5);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-25',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-26',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-27',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-28',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-29',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-30',0);
INSERT INTO table_2 (id,day_dt,value) VALUES ('b','2021-12-31',0);


-- Example queries that creates desired output:

SELECT
    x.id
    , x.event_dt
    , x.before_min_dt
    , x.before_max_dt
    , x.before_value
    , MIN(t2.day_dt) after_min_dt
    , MAX(t2.day_dt) after_max_dt
    , MAX(t2.value) after_value
FROM(
SELECT
    t1.id
    , t1.event_dt
    , MIN(t2.day_dt) before_min_dt
    , MAX(t2.day_dt) before_max_dt
    , MAX(t2.value) before_value
FROM table_1 t1
JOIN table_2 t2
ON (t1.id = t2.id 
    AND t2.day_dt >= DATE_ADD(t1.event_dt, INTERVAL -5 DAY) 
    AND t2.day_dt < t1.event_dt)
GROUP BY 
    t1.id
    , t1.event_dt
) x
JOIN table_2 t2
ON (x.id = t2.id 
    AND t2.day_dt >= x.event_dt 
    AND t2.day_dt < DATE_ADD(x.event_dt, INTERVAL 5 DAY))
GROUP BY     
    x.id
    , x.event_dt
    , x.before_min_dt
    , x.before_max_dt
    , x.before_value;

【问题讨论】:

  • 一个连接,然后是 2 个具有单独窗口定义的窗口函数。
  • 您使用的是哪个版本的 MySQL?那么确切的日期呢? 2021-12-10...是包含在-5天还是+5天?
  • @Akina 听起来很理想,你能举个例子吗?谢谢
  • 将样本数据提供为 CREATE TABLE + INSERT INTO 格式化代码,并严格提供此数据所需的表格格式输出。
  • @Akina 谢谢,我已经添加了示例数据的脚本和生成所需输出的示例查询

标签: mysql sql


【解决方案1】:
SELECT table_2.id,
       table_1.event_dt, 
       table_1.event_dt - INTERVAL 5 DAY before_min_dt,
       table_1.event_dt - INTERVAL 1 DAY before_max_dt,
       MAX(CASE WHEN table_2.day_dt BETWEEN table_1.event_dt - INTERVAL 5 DAY
                                        AND table_1.event_dt - INTERVAL 1 DAY
                THEN value
                END) max_value_before,
       table_1.event_dt after_min_dt,
       table_1.event_dt + INTERVAL 4 DAY after_max_dt,
       MAX(CASE WHEN table_2.day_dt BETWEEN table_1.event_dt
                                        AND table_1.event_dt + INTERVAL 4 DAY
                THEN value
                END) max_value_after
FROM table_1
JOIN table_2 ON table_2.id = table_1.id
            AND table_2.day_dt BETWEEN table_1.event_dt - INTERVAL 5 DAY
                                   AND table_1.event_dt + INTERVAL 4 DAY
GROUP BY table_1.event_dt, table_2.id

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=ffda56d3e03e64b8891d438a68a5bbc2

【讨论】:

    猜你喜欢
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 2013-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    相关资源
    最近更新 更多