我在编写要在以下系统上运行的 SQL 查询时遇到问题:
表架构(带有一些示例数据):
DROP TABLE IF EXISTS reference_log;
CREATE TABLE reference_log
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
reference_number VARCHAR(20) NOT NULL,
reference_date DATE NOT NULL,
log_date DATE NOT NULL
) Engine=InnoDB;
INSERT INTO reference_log (
id,
reference_number,
reference_date,
log_date
) VALUES (
1,
'123',
'2024-04-01',
'2024-04-14'
);
INSERT INTO reference_log (
id,
reference_number,
reference_date,
log_date
) VALUES (
2,
'123',
'2024-04-01',
'2024-04-15'
);
INSERT INTO reference_log (
id,
reference_number,
reference_date,
log_date
) VALUES (
3,
'123',
'2024-04-01',
'2024-05-01'
);
INSERT INTO reference_log (
id,
reference_number,
reference_date,
log_date
) VALUES (
4,
'123',
'2024-05-01',
'2024-05-06'
);
行具有以下属性,这些属性由应用程序而不是数据库强制执行(即没有约束):
其他相关统计数据:
我正在查找给定日志日期的所有参考编号,其中前一个实例具有较早的参考日期。前一个实例被定义为具有相同参考号和较低 id 的行。如果有多个(通常是这种情况),则使用 id 最高的那个。对于前一个实例,任何组合都是可能的,即
使用示例数据,我预计会出现以下情况:
我可以轻松获得日志日期的所有参考编号:
SELECT reference_number
FROM reference_log
WHERE
log_date = '2024-05-01'
我还可以获取特定参考号(“123”)和 ID(50)的前一个实例:
SELECT reference_number
FROM reference_log
WHERE
reference_number = '123'
AND id < 50
ORDER BY id DESC
LIMIT 1
我正在努力解决的是如何组合这两个查询。如果我不需要 ORDER BY 和 LIMIT,那么自联接将很简单,尽管速度很慢(由于“检查每个记录的范围”,并且有超过 200 万行,因此执行需要 4 分钟以上):
SELECT
rl1.reference_number
FROM reference_log rl1, reference_log rl2
WHERE
rl1.log_date = '2024-05-01'
AND rl2.reference_number = rl1.reference_number
AND rl2.id < rl1.id
AND rl2.reference_date < rl1.reference_date
有没有办法使用单个查询来获取我需要的内容?
唯一的其他选择是获取给定 log_date 的每一行,然后发出另一个查询来查找前一个实例。然而,每个 log_date 通常有大约 7,000 个参考号,因此这意味着发出 7,000 个查询。这也意味着我无法直接针对数据库测试查询(我更喜欢在可能的情况下这样做,因为我可以确保任何错误都不是应用程序中的错误造成的)。
你可以尝试更简单的方法 - 使用窗口函数
select *
from(
select *
,coalesce(lag(reference_date)
over(partition by reference_number order by id)
,reference_date)prev_ref_date
from reference_log
)logprev
where reference_date<>prev_ref_date
输出是
id | 参考号 | 参考日期 | 日志日期 | prev_ref_date |
---|---|---|---|---|
4 | 123 | 2024-05-01 | 2024-05-06 | 2024-04-01 |