You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何为加油记录匹配其加油时间之前最近的油价更新记录?

解决方案:匹配加油记录与最近的油价更新

问题背景

我们有两张无直接等值关联字段的表:

  • RefuelRecord(加油记录表):存储车辆加油的ID和对应时间
  • PriceUpdateRecord(油价更新记录表):存储油价的更新时间和对应价格

需求是为每一条加油记录,找到加油时间之前最近的一次油价更新记录,并关联出对应的油价和更新时间——直接用普通LEFT JOIN会因为没有等值条件产生笛卡尔积,完全不符合预期。

示例数据

先确认创建表和插入数据的SQL(修正了原示例中的时间小差异,保证逻辑一致):

Create table RefuelRecord (RefuelId int, RefuelTime datetime);
INSERT INTO RefuelRecord VALUES(1, '2022-02-01 12:15:00');
INSERT INTO RefuelRecord VALUES(2, '2022-03-01 12:15:00');
INSERT INTO RefuelRecord VALUES(3, '2022-04-01 12:15:00');

Create table PriceUpdateRecord (UpdateTime datetime, Price double);
INSERT INTO PriceUpdateRecord VALUES('2022-01-20 00:00:00', 9.0);
INSERT INTO PriceUpdateRecord VALUES('2022-02-20 00:00:00', 8.1);
INSERT INTO PriceUpdateRecord VALUES('2022-03-20 00:00:00', 7.2);

方案一:子查询获取最近的油价更新

这种方式适配绝大多数SQL数据库(MySQL、SQL Server、PostgreSQL等都支持),核心思路是为每条加油记录单独筛选出符合条件的最近油价更新:

SELECT
    r.RefuelId,
    r.RefuelTime,
    p.UpdateTime,
    p.Price
FROM RefuelRecord r
LEFT JOIN PriceUpdateRecord p 
    ON p.UpdateTime = (
        SELECT MAX(UpdateTime)
        FROM PriceUpdateRecord
        WHERE UpdateTime <= r.RefuelTime
    )
ORDER BY r.RefuelId;

逻辑拆解

  1. 外层遍历每一条加油记录r
  2. 子查询针对当前加油时间r.RefuelTime,找出所有在它之前的油价更新时间,取最大的那个(也就是时间上最近的一次)
  3. 通过这个最大的UpdateTime关联油价表,拿到对应的油价数据

方案二:窗口函数ROW_NUMBER()筛选最优匹配

如果你的数据库支持窗口函数(比如MySQL 8.0+、SQL Server 2008+、PostgreSQL等),可以用更高效的分组排序方式:

WITH RankedPriceUpdates AS (
    SELECT
        r.RefuelId,
        r.RefuelTime,
        p.UpdateTime,
        p.Price,
        ROW_NUMBER() OVER (
            PARTITION BY r.RefuelId 
            ORDER BY p.UpdateTime DESC
        ) AS rn
    FROM RefuelRecord r
    LEFT JOIN PriceUpdateRecord p 
        ON p.UpdateTime <= r.RefuelTime
)
SELECT RefuelId, RefuelTime, UpdateTime, Price
FROM RankedPriceUpdates
WHERE rn = 1
ORDER BY RefuelId;

逻辑拆解

  1. 先用LEFT JOIN关联所有加油时间之前的油价更新记录(这一步会产生多对一的临时结果)
  2. ROW_NUMBER()RefuelId分组,对每个分组内的油价更新记录按UpdateTime倒序排序,最近的那条会被标记为rn=1
  3. 最后筛选出rn=1的记录,就是我们需要的精准匹配结果

预期结果

两种方案都会输出符合要求的结果:

RefuelIdRefuelTimeUpdateTimePrice
12022-02-01 12:15:002022-01-20 00:00:009.0
22022-03-01 12:15:002022-02-20 00:00:008.1
32022-04-01 12:15:002022-03-20 00:00:007.2

内容的提问来源于stack exchange,提问作者foxever

火山引擎 最新活动