【问题标题】:postgresql join on max(date) and another indexpostgresql 加入 max(date) 和另一个索引
【发布时间】:2016-10-05 08:43:13
【问题描述】:

我正在尝试加入 2 个表格以查找下一个交货日期之前的天数。

一张表是零件号和补货日期

part    restock_date
123 01/01/15
123 04/01/15
123 06/30/15
123 09/28/15
234 01/25/15
234 04/25/15
234 07/24/15
234 10/22/15

另一张表是零件编号和分析日期

part    analysis_date
123 02/12/15
123 03/29/15
123 05/13/15
123 06/27/15
234 03/23/15
234 05/07/15
234 06/21/15
234 08/05/15

我正在尝试创建一个显示给定分析日期的下一个补货日期的联接,以便我可以计算分析日期和下一个补货日期之间的天数差异。

part    restock_date    analysis_date   days_to_restock
123 04/01/15    02/12/15    48
123 04/01/15    03/29/15    3
123 06/30/15    05/13/15    48
123 06/30/15    06/27/15    3
234 04/25/15    03/23/15    33
234 07/24/15    05/07/15    78
234 07/24/15    06/21/15    33
234 10/22/15    08/05/15    78

有什么建议吗?

【问题讨论】:

  • 但是我们怎么知道要匹配哪些日期呢?
  • @jarlh : 这是未来最接近的补货日期
  • 如果有两个“匹配”的日期,或者没有?让样本数据更复杂!
  • @jarlh:每个 part_num 的补货日期都是唯一的,但可以跨部分重复。连接需要涉及 part_num 和有序日期 - 我只是不确定如何编写查询:)
  • restock_dateanalysis_date 会不会相同,或者restock_date 至少应该晚一天?

标签: sql postgresql date join


【解决方案1】:

寻找连续观察的简单方法:

SELECT a.*, r.*
        , (r.restock_date - a.analysis_date ) AS nday
FROM tbl_analysis a
LEFT JOIN tbl_restock r
        ON a.part = r.part
        AND r.restock_date >= a.analysis_date           -- restock *after* analysys
        AND NOT EXISTS ( SELECT * FROM tbl_restock nx   -- ,but no observations inbetween 
                WHERE nx.part = a.part
                AND nx.restock_date > a.analysis_date
                AND nx.restock_date < r.restock_date
                )
ORDER BY a.part,a.analysis_date
        ;

【讨论】:

    【解决方案2】:

    这假设您只关心零件有补货的情况,这就是为什么这是一个内部连接。如果您想单独处理尚未补货的那些,则需要将其设为左连接并添加适当的逻辑。

    表格设置

    DROP TABLE IF EXISTS tbl_restock;
    CREATE TABLE tbl_restock (part TEXT, restock_date DATE);
    INSERT INTO tbl_restock
    VALUES
    ('123','01/01/15'),
    ('123','04/01/15'),
    ('123','06/30/15'),
    ('123','09/28/15'),
    ('234','01/25/15'),
    ('234','04/25/15'),
    ('234','07/24/15'),
    ('234','10/22/15');
    
    DROP TABLE IF EXISTS tbl_analysis;
    CREATE TABLE tbl_analysis (part TEXT, analysis_date DATE);
    INSERT INTO tbl_analysis
    VALUES
    ('123','02/12/15'),
    ('123','03/29/15'),
    ('123','05/13/15'),
    ('123','06/27/15'),
    ('234','03/23/15'),
    ('234','05/07/15'),
    ('234','06/21/15'),
    ('234','08/05/15');
    

    解决方案 1

    WITH cte AS
    (
      SELECT
        ta.part,
        tr.restock_date,
        ta.analysis_date,
        EXTRACT(DAY FROM AGE(tr.restock_date,ta.analysis_date)) AS days_to_restock,
        RANK() OVER (PARTITION BY ta.part, ta.analysis_date ORDER BY AGE(tr.restock_date,ta.analysis_date) ASC) AS dtr_rank
      FROM
        tbl_analysis ta
      INNER JOIN
        tbl_restock tr
        ON  (tr.part = ta.part)
        AND  (tr.restock_date >= ta.analysis_date)
    )
    
    SELECT
      part,
      restock_date,
      analysis_date,
      days_to_restock
    FROM
      cte
    WHERE
      dtr_rank = 1;
    

    更新 - 解决方案 2

    这是另一个使用DISTINCT ON 方法的解决方案,灵感来自@GordonLinoff 的回答:Multiple unwanted records in Group by clause in Postgress

    SELECT
      DISTINCT ON (ta.part, ta.analysis_date)
      ta.part,
      tr.restock_date,
      ta.analysis_date,
      (tr.restock_date - ta.analysis_date) AS days_to_restock
    FROM
      tbl_analysis ta
    LEFT JOIN
      tbl_restock tr
      ON  (tr.part = ta.part)
      AND (tr.restock_date >= ta.analysis_date)
    ORDER BY
      part,
      analysis_date,
      restock_date;
    

    输出

    【讨论】:

      【解决方案3】:

      你可以通过横向连接来解决这个问题:

      select t2.*, t1.restock_date,
             (t1.restock_date - t2.analysis_date) as diff
      from table2 t2 left join lateral
           (select t1.*
            from table1 t1
            where t2.part = t1.part and t2.analysis_date <= t1.restock_date
            order by t1.restock_date
            limit 1
           ) t1;
      

      【讨论】:

      • 我很好奇,因为我刚刚看到你在这里发布你的答案:stackoverflow.com/questions/37645842/… -- 你能不能在这里用DISTINCT ON 使用partanalysis_date 做类似的事情?如果是这样,与其他解决方案相比有什么好处吗?
      • @Nicarus 。 . .是的,但是中间的join 表可能非常大。这个公式将允许 Postgres 使用table1(part, analysis_date) 上的索引。
      猜你喜欢
      • 2020-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-21
      • 2021-08-17
      • 1970-01-01
      相关资源
      最近更新 更多