【问题标题】:SQL Join on timestamps where you only take the first/oldest resultSQL Join 时间戳,您只获取第一个/最旧的结果
【发布时间】:2021-03-12 04:56:48
【问题描述】:

假设我有两张桌子:

Table #1t1

ID | Col1 | MeasureTime         | Parameter_ID
----------------------------------------------
1  | abc  | 2020-11-11 07:00:00 | 1
2  | abc  | 2020-11-11 08:00:00 | 1

Table #2t2

ID | Parameter_ID | Col2 | ValidFrom
----------------------------------------------
1  | 1            | xyz  | 2020-11-11 06:30:00
2  | 1            | def  | 2020-11-11 07:30:00

我想使用Parameter_ID 加入两个表,并且我想建立 1:1 的关系。 t2 中的ValidFrom 是该参数生效的时间。但不幸的是,没有ValidTo,而是我必须检查我是否加入了t2 中的第一个Parameter_ID,其中ValidFrom 是有效的。

所以我想要这个结果:

Table #3t3

ID | Col1 | MeasureTime         | Parameter_ID | ValidFrom | Col2
-----------------------------------------------------------------
1  | abc  | 2020-11-11 07:00:00 | 1            | 06:30:00  | xyz
2  | abc  | 2020-11-11 08:00:00 | 1            | 07:30:00  | def

但如果我会做一个简单的:

SELECT * 
FROM t1 
JOIN t2 ON t1.PARAMETER_ID = t2.PARAMETER_ID AND t1.Measuretime >= t2.ValidFrom

我会得到:

Table #3t3

ID | Col1 | MeasureTime         | Parameter_ID | ValidFrom | Col2
-----------------------------------------------------------------
1  | abc  | 2020-11-11 07:00:00 | 1            | 06:30:00  | xyz
2  | abc  | 2020-11-11 08:00:00 | 1            | 06:30:00  | xyz
3  | abc  | 2020-11-11 08:00:00 | 1            | 07:30:00  | def

我实际上不想拥有ID 2

希望我的问题变得清晰。我可以想到类似“如果 t2 有多个结果,则按 ValidFrom ASC 排序并只取第一个”。但不幸的是,我不确定如何使用 SQL 来做到这一点。也许这个问题还有更优雅的解决方案?

【问题讨论】:

    标签: sql oracle join oracle11g


    【解决方案1】:

    我建议使用lead() 生成valid_to。然后使用join:

    select t1.*, t2.valid_from, t2.col2
    from table1 t1 join
         (select t2.*,
                 lead(valid_from) over (partition by parameter_id order by valid_from) as valid_to
          from t2
         ) t2
         on t1.parameter_id = t2.parameter_id and
            t1.MeasureTime >= t2.valid_from and
            (t1.MeasureTime < t2.valid_to or t2.valid_to is null);
    

    虽然您愿意将两个表中的值对齐,但听起来正确的解决方案是从日期范围包括 table1 日期的table2 获取行。

    【讨论】:

    • 虽然其他答案也是正确的(使用 ROW_NUMBER()),但我最喜欢您的解决方案!谢谢,这就是我想要的。
    【解决方案2】:

    你可以使用 row_number()

    select a.* from 
    
    (SELECT *, row_number()over(partition by Col1,MeasureTime order by MeasureTime) rn
    FROM t1 
    JOIN t2 ON t1.PARAMETER_ID = t2.PARAMETER_ID AND t1.Measuretime >= t2.ValidFrom
    ) a were a.rn=1
    

    【讨论】:

      【解决方案3】:

      您可以使用ROW_NUMBER 解析函数扩展您的原始查询,如下所示:

      SELECT * FROM
      (SELECT T1.*, T2.VALID_FROM, T2.COL2,
              ROW_NUMBER() 
                OVER (PARTITION BY T1.ID ORDER BY T2.VALID_FROM DESC NULLS LAST) AS RN
        FROM T1 JOIN T2 ON T1.PARAMETER_ID = T2.PARAMETER_ID
                       AND T1.MEASURETIME >= T2.VALIDFROM)
      WHERE RN = 1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-12
        相关资源
        最近更新 更多