在另一个表中查找最接近特定日期的表中的日期列表。

时间:2018-09-05 15:29:26

标签: 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           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放入其临时表中。然后尝试找到需要最接近的匹配值,但是在这里我不确定从哪里开始编码。

抱歉,如果我为此缺少基本功能或子句,我仍在学习!

2 个答案:

答案 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的日期为2018080320180805,则{ {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
  

ROW_NUMBER (Transact-SQL)

     

编号结果集的输出。更具体地说,返回结果集分区中一行的序号,从每个分区中第一行的1开始。

如果您可以正确运行ROW_NUMBER,则应注意,查询将对每个ID的数据进行排名,从1开始,并根据两个日期之间的差值将此排名提高,将其排名重置为{{ 1}}更改ID。


此后,您只需要选择1等于nu_row的那些行。我会为此使用CTE。

  

WITH common_table_expression (Transact-SQL)

     

指定一个临时的命名结果集,称为公用表表达式(CTE)。