SQL 查询以查找给定日期之前的最后一次更改

Posted

技术标签:

【中文标题】SQL 查询以查找给定日期之前的最后一次更改【英文标题】:SQL Query to find the last change prior to a given date 【发布时间】:2021-03-16 12:24:57 【问题描述】:

我有 2 个表,一个包含产品更改信息,另一个包含测试信息,我正在尝试构建一个查询以查找测试前的最后一个产品更改信息。

例如,在下面的数据中,我想要返回的每个测试都类似于:

product_sn testtype testdate part_spec changedate
ABC0001 hot 2021-01-01 13:00:00 nylon 2021-01-01 00:00:00
ABC0001 hot 2021-01-01 16:00:00 steel 2021-01-01 15:00:00
ABC1234 hot 2021-01-01 18:00:00 steel 2021-01-01 17:00:00
ABC1234 cold 2021-01-01 18:10:00 steel 2021-01-01 17:00:00
ABC1234 mid 2021-01-01 18:20:00 steel 2021-01-01 17:00:00
ABC0001 hot 2021-01-02 09:00:00 brass 2021-01-01 20:00:00
ABC1234 cold 2021-01-01 19:00:00 steel 2021-01-01 17:00:00

我在 sql 方面有点菜鸟,不太清楚在 *** 的其他地方搜索的最佳术语 :)

CREATE OR REPLACE TABLE Scratchpad.product
    (`ID` INT64,
    `product_sn` STRING,
    `part_spec` STRING,
    `changedate` datetime
    )
;
    
INSERT INTO Scratchpad.product
    (`ID`, `product_sn`, `part_spec`, `changedate`)
VALUES
    (1, 'ABC0001', 'nylon','2021-01-01 00:00:00'),
    (2, 'ABC0001', 'steel','2021-01-01 15:00:00'),
    (3, 'ABC0001', 'brass','2021-01-01 20:00:00'),
    (4, 'ABC1234', 'steel','2021-01-01 17:00:00'),
    (5, 'ABC1234', 'nylon','2021-02-01 00:00:00')
;


CREATE OR REPLACE TABLE Scratchpad.test
    (`ID` INT64,
     `product_sn` STRING,
      `testtype` STRING,
      `testdate` datetime
    )
;
    
INSERT INTO Scratchpad.test
    (`ID`, `product_sn`, `testtype`, `testdate`)
VALUES
    (1, 'ABC0001', 'hot','2021-01-01 13:00:00'),
    (2, 'ABC0001', 'hot','2021-01-01 16:00:00'),
    (3, 'ABC1234', 'hot','2021-01-01 18:00:00'),
    (4, 'ABC1234', 'cold','2021-01-01 18:10:00'),
    (5, 'ABC1234', 'mid','2021-01-01 18:20:00'),
    (6, 'ABC0001', 'hot','2021-01-02 09:00:00'),
    (7, 'ABC1234', 'cold','2021-01-01 19:00:00')
;

【问题讨论】:

【参考方案1】:

感谢https://***.com/a/45041970/274349这里的另一个答案@

#standardSQL
SELECT 
  t.ID AS ID, 
  t.product_sn,
  t.testdate as date, 
  t.testtype,

  ARRAY_AGG(r.part_spec ORDER BY r.changedate desc LIMIT 1)[SAFE_OFFSET(0)] AS part_spec,
  ARRAY_AGG(r.changedate ORDER BY r.changedate desc LIMIT 1)[SAFE_OFFSET(0)] AS part_change

FROM `Scratchpad.test` AS t
JOIN `Scratchpad.product` AS r
ON t.product_sn = r.product_sn 
AND r.changedate <= t.testdate
GROUP BY ID,product_sn, date, testtype

【讨论】:

。 .这基本上是我回答中的最后一个解决方案。但重要的是,这不会做LEFT JOIN,这是您问题的棘手部分。【参考方案2】:

这在 BQ 中可能是一个棘手的问题。一种解决方案是:

select t.*,
       (select as struct p.part_spec, p.change_date
        from `Scratchpad.product` p
        where p.product_sn = t.product_sn and
              p.changedate < t.testdate
        order by p.changedate desc
        limit 1
       )
from `Scratchpad.test` t;

这可能有效,但 BigQuery 有时对左连接和子查询中的不等式很挑剔。

更详细的方法是:

select array_agg(t order by p.change_date desc limit 1)[ordinal(1)].*,
       array_agg(p order by p.change_date desc limit 1)[ordinal(1)].*
from `Scratchpad.test` t left join
     `Scratchpad.product` p
     on p.product_sn = t.product_sn and
        p.changedate < t.testdate
group by t.id;

【讨论】:

不太奏效,但 BQ 错误消息确实给了我一些新的线索和搜索词。发现这个非常相似 - ***.com/questions/45040472/… @MartinD 。 . .错误信息是什么?有一种更有效的方法可以解决这个问题——而且是一种可扩展的方法。我不确定在这种情况下是否需要它。 第一个是“标量子查询不能有多个列,除非使用 SELECT AS STRUCT 来构建 STRUCT 值”所以我只是删除了其中一个被要求的列。然后下一个错误是“不支持引用其他表的相关子查询,除非它们可以去相关,例如通过将它们转换为有效的 JOIN”,所以我在 Correlated SubQueries 上进行了搜索并查看了一些解决方案。跨度>

以上是关于SQL 查询以查找给定日期之前的最后一次更改的主要内容,如果未能解决你的问题,请参考以下文章

跟踪员工在办公室时间查询 - Oracle SQL Developer

优化慢 SQL 查询

Oracle SQL 按日期查找唯一 ID

帮助形成 mysql 查询以查找给定日期范围的免费(可用)场所/资源

MySql 查询以查找给定日期“从”和“到”可用的房间

SQL查询以查找表中列值多次出现的计数?