假设我有表1和表2,其中包含以下数据。我想找到表 1(JoiningDt) 中每个 ID 的 Table2.ClosestDt 中可用的下一个最接近的日期匹配项。注意:表 2 中的最接近匹配应大于表 1 的日期,并且 2 个 ID 不能具有相同的最接近匹配(例如:ID 2 应采用值 08-Apr-2024,即使 07-Apr-2024 是最接近的1,因为它已被 ID 1 占用。)
表1:
身份证 | 加入Dt | 文档编号 |
---|---|---|
1 | 2024 年 4 月 5 日 | A123 |
2 | 2024 年 4 月 6 日 | A123 |
3 | 2024 年 4 月 4 日 | B123 |
表2
文档编号 | 最近Dt |
---|---|
A123 | 2024 年 4 月 3 日 |
A123 | 2024 年 4 月 4 日 |
A123 | 2024 年 4 月 7 日 |
A123 | 2024 年 4 月 8 日 |
B123 | 2024 年 4 月 2 日 |
B123 | 2024 年 4 月 5 日 |
我的预期输出是:
身份证 | 加入Dt | 文档编号 | 最近Dt |
---|---|---|---|
1 | 2024 年 4 月 5 日 | A123 | 2024 年 4 月 7 日 |
2 | 2024 年 4 月 6 日 | A123 | 2024 年 4 月 8 日 |
3 | 2024 年 4 月 4 日 | B123 | 2024 年 4 月 5 日 |
当我尝试左外连接时,我得到
身份证 | 加入Dt | 文档编号 | 最近Dt |
---|---|---|---|
1 | 2024-04-05 | A123 | 2024-04-07 |
1 | 2024-04-05 | A123 | 2024-04-08 |
2 | 2024-04-06 | A123 | 2024-04-07 |
2 | 2024-04-06 | A123 | 2024-04-08 |
3 | 2024-04-04 | B123 | 2024-04-05 |
select t1.ID ,t1.JoiningDt, t1.DocNum, (t2.ClosestDt)
from #Table1 t1
left join #Table2 t2 on
t1.DocNum = t2.DocNum
and t2.ClosestDt > t1.JoiningDt
我也尝试使用 rownumber,但具有挑战性的部分是获取 id 2 的下一场比赛(8-apr 而不是 7-apr),因为 7-apr 已被 Id 1 占用。
您可以使用相关子查询,您可以在其中选择最近的日期。
对于这样的动态,你需要至少处理两次数据。 基本思想是使用行号来确定两个日期选择的两个或多个齿的位置,然后根据其具有的行号简单地选择行中的下一个。
这意味着表 2 中有足够的数据来填充该列,否则您需要更多编程,以确定在最后一个日期之后接下来要采用哪些日期。
CREATE TABLE Table1 (
ID INTEGER,
JoiningDt DATETIME,
DocNum VARCHAR(4)
);
INSERT INTO Table1
(ID, JoiningDt, DocNum)
VALUES
('1', '05-Apr-2024', 'A123'),
('2', '06-Apr-2024', 'A123'),
('3', '04-Apr-2024', 'B123');
CREATE TABLE Table2 (
DocNum VARCHAR(4),
ClosestDt DATETIME
);
INSERT INTO Table2
(DocNum, ClosestDt)
VALUES
('A123', '03-Apr-2024'),
('A123', '04-Apr-2024'),
('A123', '07-Apr-2024'),
('A123', '08-Apr-2024'),
('B123', '02-Apr-2024'),
('B123', '05-Apr-2024');
9 rows affected
WITH CTE1 As (
SELECT t1.ID, t1.JoiningDt, t1.DocNum,
(SELECT TOP 1 ClosestDt FROM Table2
WHERE DocNum = t1.DocNum AND ClosestDt > t1.JoiningDt ORDER BY ClosestDt ASC ) ClosestDt
, ROW_NUMBER() OVER(PARTITION BY DocNum, (SELECT TOP 1 ClosestDt FROM Table2
WHERE DocNum = t1.DocNum AND ClosestDt > t1.JoiningDt ORDER BY ClosestDt ASC ) ORDER BY ID) rn
FROM Table1 t1
)
SELECT ID, JoiningDt, DocNum,
CASE WHEN rn = 1 then ClosestDt ELSE
(SELECT ClosestDt FROM Table2
WHERE DocNum = c1.DocNum AND ClosestDt > c1.JoiningDt ORDER BY ClosestDt ASC
OFFSET c1.rn -1 ROWS FETCH NEXT 1 ROWS ONLY) END
FROM CTE1 c1
身份证 | 加入Dt | 文档编号 | (无栏名) |
---|---|---|---|
1 | 2024-04-05 00:00:00.000 | A123 | 2024-04-07 00:00:00.000 |
2 | 2024-04-06 00:00:00.000 | A123 | 2024-04-08 00:00:00.000 |
3 | 2024-04-04 00:00:00.000 | B123 | 2024-04-05 00:00:00.000 |
另一种方法有两个cte,这样子选择就不会运行两次,但它就像第一个一样,只是重写了
WITH CTE1 As (
SELECT t1.ID, t1.JoiningDt, t1.DocNum,
(SELECT TOP 1 ClosestDt FROM Table2
WHERE DocNum = t1.DocNum AND ClosestDt > t1.JoiningDt ORDER BY ClosestDt ASC ) ClosestDt
FROM Table1 t1
), CTE2 AS (
SELECT
ID, JoiningDt, DocNum, ClosestDt
, ROW_NUMBER() OVER(PARTITION BY DocNum, ClosestDt ORDER BY ID) rn
FROM CTE1
)
SELECT ID, JoiningDt, DocNum,
CASE WHEN rn = 1 then ClosestDt ELSE
(SELECT ClosestDt FROM Table2
WHERE DocNum = c1.DocNum AND ClosestDt > c1.JoiningDt ORDER BY ClosestDt ASC
OFFSET c1.rn -1 ROWS FETCH NEXT 1 ROWS ONLY) END
FROM CTE2 c1
身份证 | 加入Dt | 文档编号 | (无栏名) |
---|---|---|---|
1 | 2024-04-05 00:00:00.000 | A123 | 2024-04-07 00:00:00.000 |
2 | 2024-04-06 00:00:00.000 | A123 | 2024-04-08 00:00:00.000 |
3 | 2024-04-04 00:00:00.000 | B123 | 2024-04-05 00:00:00.000 |