Sql 从不同的表中查找最接近特定日期的表中的日期列表。
我在一个有日期列的表中有一个唯一ID的列表。例如:Sql 从不同的表中查找最接近特定日期的表中的日期列表。,sql,sql-server,Sql,Sql Server,我在一个有日期列的表中有一个唯一ID的列表。例如: TABLE1 ID Date 0 2018-01-01 1 2018-01-05 2 2018-01-15 3 2018-01-06 4 2018-01-09 5 2018-01-12 6 2018-01-15 7 2018-01-02 8
TABLE1
ID Date
0 2018-01-01
1 2018-01-05
2 2018-01-15
3 2018-01-06
4 2018-01-09
5 2018-01-12
6 2018-01-15
7 2018-01-02
8 2018-01-04
9 2018-02-25
然后在另一个表中,我有一个不同值的列表,这些值针对每个ID和不同的日期多次出现
TABLE 2
ID Value Date
0 18 2017-11-28
0 24 2017-12-29
0 28 2018-01-06
1 455 2018-01-03
1 468 2018-01-16
2 55 2018-01-03
3 100 2017-12-27
3 110 2018-01-04
3 119 2018-01-10
3 128 2018-01-30
4 223 2018-01-01
4 250 2018-01-09
4 258 2018-01-11
等
我想在表2中找到最接近表1中唯一日期的值。
有时表2确实包含一个与日期完全匹配的值,我在遍历这些值时没有遇到任何问题。但我无法计算出代码,以通过最接近表1中请求的日期的值
基于上述示例,我期望的结果是
ID Value Date
0 24 2017-12-29
1 455 2018-01-03
2 55 2018-01-03
3 110 2018-01-04
4 250 2018-01-09
因为我可以很容易地找到具有精确匹配的ID,所以我尝试过的一件事是将没有精确日期匹配的ID及其对应值放入临时表中。然后试图找到我需要的最接近的匹配值,但我不确定从哪里开始编码
抱歉,如果我缺少一个基本函数或子句,我还在学习 以下是一种方法:
WITH Table1 AS(
SELECT ID, CONVERT(date, datecolumn) DateColumn
FROM (VALUES (0,'20180101'),
(1,'20180105'),
(2,'20180115'),
(3,'20180106'),
(4,'20180109'),
(5,'20180112'),
(6,'20180115'),
(7,'20180102'),
(8,'20180104'),
(9,'20180225')) V(ID, DateColumn)),
Table2 AS(
SELECT ID, [value], CONVERT(date, datecolumn) DateColumn
FROM (VALUES (0,18 ,'2017-11-28'),
(0,24 ,'2017-12-29'),
(0,28 ,'2018-01-06'),
(1,455,'2018-01-03'),
(1,468,'2018-01-16'),
(2,55 ,'2018-01-03'),
(3,100,'2017-12-27'),
(3,110,'2018-01-04'),
(3,119,'2018-01-10'),
(3,128,'2018-01-30'),
(4,223,'2018-01-01'),
(4,250,'2018-01-09'),
(4,258,'2018-01-11')) V(ID, [Value],DateColumn))
SELECT T1.ID,
T2.[Value],
T2.DateColumn
FROM Table1 T1
CROSS APPLY (SELECT TOP 1 *
FROM Table2 ca
WHERE T1.ID = ca.ID
ORDER BY ABS(DATEDIFF(DAY, ca.DateColumn, T1.DateColumn))) T2;
请注意,如果差异为天,则返回的行将是随机的(并且每次运行查询时可能会有所不同)。例如,如果
Table
具有日期20180804
和Table2
具有日期20180803
和20180805
它们都具有ABS(DATEDIFF(DAY,ca.DateColumn,T1.DateColumn))的值1
。因此,您可能需要在您的订单中加入额外的逻辑,以确保一致的结果。以下是一种方法:
WITH Table1 AS(
SELECT ID, CONVERT(date, datecolumn) DateColumn
FROM (VALUES (0,'20180101'),
(1,'20180105'),
(2,'20180115'),
(3,'20180106'),
(4,'20180109'),
(5,'20180112'),
(6,'20180115'),
(7,'20180102'),
(8,'20180104'),
(9,'20180225')) V(ID, DateColumn)),
Table2 AS(
SELECT ID, [value], CONVERT(date, datecolumn) DateColumn
FROM (VALUES (0,18 ,'2017-11-28'),
(0,24 ,'2017-12-29'),
(0,28 ,'2018-01-06'),
(1,455,'2018-01-03'),
(1,468,'2018-01-16'),
(2,55 ,'2018-01-03'),
(3,100,'2017-12-27'),
(3,110,'2018-01-04'),
(3,119,'2018-01-10'),
(3,128,'2018-01-30'),
(4,223,'2018-01-01'),
(4,250,'2018-01-09'),
(4,258,'2018-01-11')) V(ID, [Value],DateColumn))
SELECT T1.ID,
T2.[Value],
T2.DateColumn
FROM Table1 T1
CROSS APPLY (SELECT TOP 1 *
FROM Table2 ca
WHERE T1.ID = ca.ID
ORDER BY ABS(DATEDIFF(DAY, ca.DateColumn, T1.DateColumn))) T2;
请注意,如果差异为天,则返回的行将是随机的(并且每次运行查询时可能会有所不同)。例如,如果Table
具有日期20180804
和Table2
具有日期20180803
和20180805
它们都具有ABS(DATEDIFF(DAY,ca.DateColumn,T1.DateColumn))的值1
。因此,您可能需要在您的
订单中包含额外的逻辑,以确保一致的结果。dude
我会说几件事让您考虑,因为SQL Server不是我的舒适区,而SQL本身是.< /P>
首先,我将每个ID连接TABLE1和TABLE2。这样,我可以在SELECT
子句中指定以下元组:
SELECT ID, Value, DateDiff(d, T1.Date, T2.Date) qt_diff_days
显然,根据保存在那里的日期的精度,而不是它们是否有时间,您可以在DateDiff
函数中更改日期字段
向前,我也将这个日期差设为绝对数(以解决正/负差异,只考虑经过时间)。
在那之后,这就是问题的症结所在,因为我不知道您使用的SQL Server版本,但基本上我会使用
行数
窗口函数按差异对所有行进行排序。如下所示:
SELECT
ID, Value, Abs(DateDiff(d, T1.Date, T2.Date)) qt_diff_days,
ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Abs(DateDiff(d, T1.Date, T2.Date)) ASC) nu_row
对结果集的输出进行编号。更具体地说,返回结果集分区内一行的序列号,从每个分区中第一行的1开始
如果您可以正确运行行号
,您应该注意到查询将按ID对其数据进行排序,从1
开始,并根据两个日期之间的差异增加此排序,当ID更改时,将其排序重置为1
之后,只需选择nu_row
等于1
的行。我会用CTE来解决这个问题
指定临时命名结果集,称为公共表表达式(CTE)
伙计
我会说几件事让您考虑,因为SQL Server不是我的舒适区,而SQL本身是.< /P>
首先,我将每个ID连接TABLE1和TABLE2。这样,我可以在SELECT
子句中指定以下元组:
SELECT ID, Value, DateDiff(d, T1.Date, T2.Date) qt_diff_days
显然,根据保存在那里的日期的精度,而不是它们是否有时间,您可以在DateDiff
函数中更改日期字段
向前,我也将这个日期差设为绝对数(以解决正/负差异,只考虑经过时间)。
在那之后,这就是问题的症结所在,因为我不知道您使用的SQL Server版本,但基本上我会使用
行数
窗口函数按差异对所有行进行排序。如下所示:
SELECT
ID, Value, Abs(DateDiff(d, T1.Date, T2.Date)) qt_diff_days,
ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Abs(DateDiff(d, T1.Date, T2.Date)) ASC) nu_row
对结果集的输出进行编号。更具体地说,返回结果集分区内一行的序列号,从每个分区中第一行的1开始
如果您可以正确运行行号
,您应该注意到查询将按ID对其数据进行排序,从1
开始,并根据两个日期之间的差异增加此排序,当ID更改时,将其排序重置为1
之后,只需选择nu_row
等于1
的行。我会用CTE来解决这个问题
指定临时命名结果集,称为公共表表达式(CTE)
如果您正在寻找1月2日,并且唯一可用的数据是1月1日和1月3日,您想要哪一个?你会考虑最大的距离吗?(如果最接近的值为+1年和-1年,您是否仍然想要其中一个?)您知道值之间的最大实际差距吗?(这将有助于优化对大型数据集的搜索)此外,您正在使用哪个版本的SQL Server?如果您正在查找1月2日的数据,并且唯一可用的数据是1月1日和1月3日,您希望使用哪个版本?你会考虑最大的距离吗?(如果最接近的值为+1年和-1年,您是否仍然想要其中一个?)您知道最大re值吗