在 SQL Server 中查找最近的日期
Posted
技术标签:
【中文标题】在 SQL Server 中查找最近的日期【英文标题】:Find closest date in SQL Server 【发布时间】:2012-12-10 23:34:07 【问题描述】:我有一张表 dbo.X
和 DateTime
column Y
可能有数百条记录。
我的存储过程有参数@CurrentDate
,我想找出上表dbo.X
中column Y
中小于和最接近@CurrentDate.
的日期
如何找到它?
【问题讨论】:
【参考方案1】:where 子句将匹配日期小于@CurrentDate 的所有行,并且由于它们是按后代排序的,因此 TOP 1 将是与当前日期最接近的日期。
SELECT TOP 1 *
FROM x
WHERE x.date < @CurrentDate
ORDER BY x.date DESC
【讨论】:
取决于数据库设计。我建议您尝试在表上为日期字段设置索引,以便系统能够直接查找与查询匹配的值。 我想问一个后续问题:您如何找到每个客户的最近日期? This article 建议使用窗口函数。你同意吗? @kmote 如果您只需要客户 ID 和相应的日期,那么为简单起见,我会选择 'SELECT x.CustomerID, MAX(x.date) FROM x GROUP BY x.CustomerID' 替代方案在您链接的文章中提出。但是,如果您想检索更多信息和/或执行更多计算而不是获取最新日期,那么窗口函数似乎是一个不错的选择。我没有太多经验可以告诉你这个函数在性能方面的表现如何,但我肯定会尝试。【参考方案2】:使用DateDiff 并按该日期与输入内容之间的天数或秒数对结果排序
类似的东西
select top 1 rowId, dateCol, datediff(second, @CurrentDate, dateCol) as SecondsBetweenDates
from myTable
where dateCol < @currentDate
order by datediff(second, @CurrentDate, dateCol)
【讨论】:
在 ORDER BY 中,您可以通过别名引用列(即您可以ORDER BY SecondsBetweenDate
)。但是,您是按表达式而不是按列对行进行排序。这很可能使查询成为非sargable。只是一个注释。
你可能会在 datediff 中得到负数,然后最接近你想要的结果的地方就是中间的某个地方。
如果您不知道您的第一个日期是否小于或大于第二个日期,则可能需要使用 diff 的绝对值 ABS
来处理负值。【参考方案3】:
我认为对于这个问题我有更好的解决方案。
我将展示一些图片来支持和解释最终解决方案。
背景 在我的解决方案中,我有一张外汇汇率表。这些代表不同货币的市场汇率。但是,我们的服务提供商在费率馈送方面存在问题,因此某些费率的值为零。我想用最接近缺失汇率的同一货币的汇率填充缺失的数据。基本上我想获得最接近的非零利率的 RateId,然后我将替换它。 (这在我的示例中没有显示。)
1) 首先让我们找出缺失的费率信息:
Query showing my missing rates i.e. have a rate value of zero
2) 接下来让我们确定没有遗漏的费率。 Query showing rates that are not missing
3) 这个查询是魔法发生的地方。我在这里做了一个假设,可以删除但添加以提高查询的效率/性能。第 26 行的假设是,我希望在丢失/零交易的同一天找到替代交易。 神奇的是第 23 行:Row_Number 函数添加了一个从 1 开始的自动编号,用于丢失和未丢失事务之间的最短时间差。下一个最接近的事务的 rownum 为 2 等。
请注意,我必须在第 25 行加入货币,以免货币类型不匹配。那就是我不想用瑞士法郎值代替澳元货币。我想要最匹配的货币。
Combining the two data sets with a row_number to identify nearest transaction
4) 最后,让我们获取 RowNum 为 1 的数据 The final query
查询全查询如下;
; with cte_zero_rates as
(
Select *
from fxrates
where (spot_exp = 0 or spot_exp = 0)
),
cte_non_zero_rates as
(
Select *
from fxrates
where (spot_exp > 0 and spot_exp > 0)
)
,cte_Nearest_Transaction as
(
select z.FXRatesID as Zero_FXRatesID
,z.importDate as Zero_importDate
,z.currency as Zero_Currency
,nz.currency as NonZero_Currency
,nz.FXRatesID as NonZero_FXRatesID
,nz.spot_imp
,nz.importDate as NonZero_importDate
,DATEDIFF(ss, z.importDate, nz.importDate) as TimeDifferece
,ROW_NUMBER() Over(partition by z.FXRatesID order by abs(DATEDIFF(ss, z.importDate, nz.importDate)) asc) as RowNum
from cte_zero_rates z
left join cte_non_zero_rates nz on nz.currency = z.currency
and cast(nz.importDate as date) = cast(z.importDate as date)
--order by z.currency desc, z.importDate desc
)
select n.Zero_FXRatesID
,n.Zero_Currency
,n.Zero_importDate
,n.NonZero_importDate
,DATEDIFF(s, n.NonZero_importDate,n.Zero_importDate) as Delay_In_Seconds
,n.NonZero_Currency
,n.NonZero_FXRatesID
from cte_Nearest_Transaction n
where n.RowNum = 1
and n.NonZero_FXRatesID is not null
order by n.Zero_Currency, n.NonZero_importDate
【讨论】:
【参考方案4】:CREATE PROCEDURE CurrentDate
@CurrentDate DATETIME
AS
BEGIN
Select * from orders
where OrderDate < @CurrentDate
END
GO
【讨论】:
虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。 我听到了,但是这个网站的规则并不喜欢讨论。我希望有人能下定决心。以上是关于在 SQL Server 中查找最近的日期的主要内容,如果未能解决你的问题,请参考以下文章