【问题标题】:T-SQL - SELECT by nearest date and GROUPED BY IDT-SQL - 按最近的日期和 GROUPED BY ID 选择
【发布时间】:2011-01-10 17:38:42
【问题描述】:

从下面的数据中,我需要使用 SQL Server 2005 为每个 Linked ID 选择最接近指定日期的记录:

ID     Date      Linked ID
...........................
1    2010-09-02     25
2    2010-09-01     25
3    2010-09-08     39
4    2010-09-09     39
5    2010-09-10     39
6    2010-09-10     34
7    2010-09-29     34
8    2010-10-01     37
9    2010-10-02     36
10   2010-10-03     36

因此使用 01/10/2010 选择它们应该会返回:

1    2010-09-02     25 
5    2010-09-10     39
7    2010-09-29     34 
8    2010-10-01     37
9    2010-10-02     36

我知道这一定是可能的,但我似乎无法理解它(一定是太接近一天的结束了:P)如果有人可以帮助我或者在正确的方向上轻轻推动我,它会不胜感激!

编辑:我也遇到过这个 sql 来获取最近的日期:

abs(DATEDIFF(minute, Date_Column, '2010/10/01'))

但不知道如何正确地合并到查询中...

谢谢

【问题讨论】:

  • 添加...您在我的评论后添加到编辑中。好的,我会给你写完整的查询。
  • 你的标题有误导性,可能是“select ID order by nearest date”
  • 您的示例使用 minute 作为 datediff 的第一个参数可能不起作用(因为您的示例日期中没有时间。)您想使用 day - 这可以是缩写。如dayddd。有趣的是,所有答案都使用不同的缩写。
  • @dvhh 不,我不这么认为,我正在描述我正在尝试做的事情,如果你看看霍根斯的回答,那正是他所做的

标签: sql sql-server sql-server-2005 tsql


【解决方案1】:

你可以试试这个。

DECLARE @Date DATE = '10/01/2010';

WITH cte AS
    (
    SELECT ID, LinkedID, ABS(DATEDIFF(DD, @date, DATE)) diff,
        ROW_NUMBER() OVER (PARTITION BY LinkedID ORDER BY ABS(DATEDIFF(DD, @date, DATE))) AS SEQUENCE
    FROM MyTable
    )

SELECT *
FROM cte
WHERE SEQUENCE = 1
ORDER BY ID
;

您没有说明要如何处理 LinkedID 组中的多行表示最接近目标日期的情况。此解决方案将仅包含一行,并且在这种情况下,您无法保证包含多个有效值中的哪一行。

如果您想包含代表最接近值的所有行,您可以在查询中使用 RANK() 更改 ROW_NUMBER()。

【讨论】:

  • 这比我的查询更好(只有一个选择)但我的对初学者来说可能更清楚......
  • 更多关于 ROW_NUMBER() 的信息在这里:msdn.microsoft.com/en-us/library/ms186734.aspx
  • @Hogan - 我不确定我是否同意。如果您仍然要使用 CTE,那么您不妨利用 Row_Number()。
  • 感谢您的回答。重复是无关紧要的,只要它返回一个就是我所需要的
  • @Thomas :是的,如果您对我对@Sean 的回答发表评论,我基本上说了这么多(并投票支持您的回答。)
【解决方案2】:

您想按天查看 DATEDIFF 函数 (http://msdn.microsoft.com/en-us/library/ms189794.aspx) 的绝对值。

查询可能看起来像这样(未经测试)

with absDates as 
(
   select *, abs(DATEDIFF(day, Date_Column, '2010/10/01')) as days
   from table
), mdays as
( 
   select min(days) as mdays, linkedid
   from absDates
   group by linkedid
)
select * 
from absdates
inner join mdays on absdays.linkedid = mdays.linkedid and absdays.days = mdays.mdays

【讨论】:

  • @Hogan 啊,是的,我已经遇到过,但忘了在问题中提及,所以我更新了它。感谢您提及
  • @w69rdy :添加了示例查询。
  • 示例查询可能不正确——它应该是 min(days),否则你会返回最大的差异,对吧?另外,我不认为这方面的表现会非常好。一般来说,我建议使用 ROW_NUMBER() 解决方案。它应该更直接、更高效。
  • @Hogan,您的查询现在失败。表absdays在哪里定义?
  • @bobs : 不是 :D 我修正了错字。
【解决方案3】:

您也可以尝试在 select 语句中使用子查询:

select  [LinkedId],
        (select top 1 [Date] from [Table] where [LinkedId]=x.[LinkedId] order by abs(DATEDIFF(DAY,[Date],@date)))
from    [Table] X
group by [LinkedId]

【讨论】:

  • 哇,这是定义。性能最低——每个linkedid的选择。
  • 是的,它只适用于小桌子
猜你喜欢
  • 2011-10-24
  • 2023-03-13
  • 2012-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-01
相关资源
最近更新 更多