You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自连接表匹配15天内归还对应的最早借出记录?

问题:归还记录匹配15天内最早借出记录的SQL实现

需求:对borrow_data表进行自连接,将每条归还记录(type='RETURNED')匹配到其15天内发生的最早借出记录(type='BORROWED');若借出记录距归还记录超过15天则跳过,无符合条件的借出记录则显示NULL。

现有表结构与数据

基础查询语句:

SELECT
trans_numb,
type,
date,
Borrow_occur,
return_occur
FROM borrow_data;

表数据:

trans_numbtypedateBorrow_occurreturn_occur
15BORROWED3/9/14 5:581NULL
19BORROWED3/10/14 5:582NULL
26BORROWED3/12/14 5:583NULL
31RETURNED3/10/14 9:58NULL1
37RETURNED3/13/14 9:58NULL2
42BORROWED3/13/14 5:214NULL
48BORROWED3/24/14 17:335NULL
53RETURNED3/27/14 13:27NULL3
59RETURNED3/30/14 12:31NULL4
61BORROWED4/5/14 13:316NULL
64RETURNED4/31/2014 7:31NULL5

期望输出框架与结果

期望查询框架:

SELECT
r.type AS type_return,    
r.return_occur,    
r.date AS return_date,    
b.type AS type_borrow,    
b.borrow_occur,    
b.date AS borrow_date,    
Date_diff(r.date,b.date) AS date_diff   
FROM borrow_data r
LEFT JOIN borrow_data b ...

期望输出结果:

(row_number)type_returnreturn_occurreturn_datetype_borrowborrow_occurborrow_datedate_diff
(1)RETURNED13/10/14 9:58BORROWED13/9/14 5:581
(2)RETURNED23/13/14 9:58BORROWED23/10/14 5:583
(3)RETURNED33/27/14 13:27BORROWED43/13/14 5:2114
(4)RETURNED43/30/14 12:31BORROWED53/24/14 17:336
(5)RETURNED54/31/2014 7:31NULLNULLNULLNULL

注:第3行跳过borrow_occur=3的记录(距归还记录超过15天);第5行无符合条件的借出记录,故显示NULL。


解决方案:无需递归,两种实现方式

方式一:关联子查询匹配最早记录

直接通过子查询定位每个归还记录对应的、符合日期条件的最早借出记录,逻辑简洁:

SELECT
    r.type AS type_return,
    r.return_occur,
    r.date AS return_date,
    b.type AS type_borrow,
    b.borrow_occur,
    b.date AS borrow_date,
    -- 不同数据库日期差函数有差异,MySQL用DATEDIFF,PostgreSQL用AGE
    DATEDIFF(r.date, b.date) AS date_diff
FROM borrow_data r
LEFT JOIN borrow_data b
    ON b.type = 'BORROWED'
    -- 精确筛选15天内的借出记录(含时间则用TIMESTAMPDIFF避免误判)
    AND TIMESTAMPDIFF(DAY, b.date, r.date) <= 15
    AND b.date <= r.date
    -- 锁定该归还记录下最早的借出记录
    AND b.date = (
        SELECT MIN(b_inner.date)
        FROM borrow_data b_inner
        WHERE b_inner.type = 'BORROWED'
        AND TIMESTAMPDIFF(DAY, b_inner.date, r.date) <= 15
        AND b_inner.date <= r.date
    )
WHERE r.type = 'RETURNED'
ORDER BY r.return_occur;

方式二:窗口函数筛选最优匹配

先关联所有符合条件的借出-归还对,再用ROW_NUMBER()窗口函数给候选记录排序,取最早的一条:

WITH borrow_return_pairs AS (
    SELECT
        r.type AS type_return,
        r.return_occur,
        r.date AS return_date,
        b.type AS type_borrow,
        b.borrow_occur,
        b.date AS borrow_date,
        TIMESTAMPDIFF(DAY, b.date, r.date) AS date_diff,
        -- 按归还记录分组,借出记录按日期升序排序
        ROW_NUMBER() OVER (PARTITION BY r.return_occur ORDER BY b.date ASC) AS rn
    FROM borrow_data r
    LEFT JOIN borrow_data b
        ON b.type = 'BORROWED'
        AND TIMESTAMPDIFF(DAY, b.date, r.date) <= 15
        AND b.date <= r.date
    WHERE r.type = 'RETURNED'
)
SELECT
    type_return,
    return_occur,
    return_date,
    type_borrow,
    borrow_occur,
    borrow_date,
    date_diff
FROM borrow_return_pairs
-- 取每个归还记录的最早借出记录,无匹配则保留NULL
WHERE rn = 1 OR rn IS NULL
ORDER BY return_occur;

关键说明

  • 无需递归:本需求是日期范围匹配+取极值场景,递归仅适用于层级遍历、连续数据迭代等情况,这里完全不需要。
  • 日期精度:若date字段包含时间,建议用TIMESTAMPDIFF(MySQL)或INTERVAL比较(PostgreSQL)精确计算时间差,避免因整天数差导致的误判(比如用户示例中borrow_occur=3的记录与归还记录间隔超15天,会被正确排除)。

内容的提问来源于stack exchange,提问作者M. Die K. S.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 08:30:10