我在一个带有日期列的表中列出了唯一的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 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放入其临时表中。然后尝试找到需要最接近的匹配值,但是在这里我不确定从哪里开始编码。
抱歉,如果我为此缺少基本功能或子句,我仍在学习!
答案 0 :(得分:5)
下面是一种方法:
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
,则{ {1}}。因此,您可能需要在1
中加入其他逻辑,以确保结果一致。
答案 1 :(得分:1)
伙计。
在这里我要说几件事供您考虑,因为SQL Server不是我的舒适区,而SQL本身是我的舒适区。
首先,我将每个ID的TABLE1与TABLE2结合在一起。这样,我可以在SELECT
子句中指定以下元组:
SELECT ID, Value, DateDiff(d, T1.Date, T2.Date) qt_diff_days
很显然,根据保存在那里的日期的精度,而不管它们是否有时间,您可以在DateDiff
函数上更改日期字段。
展望未来,我还要将此日期差设为绝对数字(以解决正/负差并仅考虑经过的时间)。
在那之后,这变得很棘手,因为我不知道您使用的SQL Server版本,但是基本上我会使用ROW_NUMBER
窗口函数来按差异对所有行进行排名。类似于以下内容:
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开始。
如果您可以正确运行ROW_NUMBER
,则应注意,查询将对每个ID的数据进行排名,从1
开始,并根据两个日期之间的差值将此排名提高,将其排名重置为{{ 1}}更改ID。
此后,您只需要选择1
等于nu_row
的那些行。我会为此使用CTE。
WITH common_table_expression (Transact-SQL)
指定一个临时的命名结果集,称为公用表表达式(CTE)。