SQL Server 查找接近服务日期和月份的行

Posted

技术标签:

【中文标题】SQL Server 查找接近服务日期和月份的行【英文标题】:SQL Server find rows approaching a service day and month 【发布时间】:2020-11-13 00:05:51 【问题描述】:

我有一张表格,其中列出了带有安装日期的设备。这些物品需要每年或每五年保养一次。因此,这些行的服务间隔为 1 或 5。类似于:

CREATE TABLE Equipment(
    Guid uniqueidentifier,
    InstallationDate datetime,
    ServiceInterval tinyint
);

我需要做的是在设备到期前两个月返回一份设备清单

为简单起见,假设我有这些安装日期,并且它们的服务间隔均为 1,这意味着需要每年进行一次服务。

2008-1-17
2011-4-28
2012-5-13
2020-9-6
2006-12-2

我需要从这个列表中返回那些(忽略年份)日期和月份属于接下来两个月的列表。所以第一个和最后一个项目需要服务。第一项需要在 1 月维修,最后一项在 12 月维修。

我不确定解决此问题的最佳方法。当然这一定是一个常见的要求,但我找不到任何可以学习的例子。我可以轻松找到范围之间的日期,但很难解决这个问题。

有人能指点我正确的方向吗?

更新:2020 年 11 月 15 日

经过一番思考和尝试其他人提出的建议后,我想出了以下脚本。我意识到这些设备大部分是灭火器,每年都需要维修。他们还需要每 5 年和 10 年提供一次扩展服务。我需要一份即将用于这些服务的资产清单。

select top 20
    MONTH(InstallationDate) as InstallMonth,
    Day(InstallationDate) as InstallDay,
    format(InstallationDate,'MMM dd yyyy') as Installed,
    case WHEN DATEFROMPARTS(year(getdate()),month(InstallationDate),day(InstallationDate)) < getdate()
    then dateadd(year,1, DATEFROMPARTS(year(getdate()),month(InstallationDate),day(InstallationDate)) )
    else   DATEFROMPARTS(year(getdate()),month(InstallationDate),day(InstallationDate))
    end as ServiceDue,
    case when year(InstallationDate) + 5 = year(getdate()) then '5 year service due' 
    when year(InstallationDate) + 5 < year(getdate()) then '5 year service passed' 
    when year(InstallationDate) + 5 > year(getdate()) then 'Five year service due ' + cast(year(InstallationDate) + 5 as varchar)
    end as '5 Year Service',

    case when year(InstallationDate) + 10 = year(getdate()) then '10 year service due' 
    when year(InstallationDate) + 10 < year(getdate()) then '10 year service passed' 
    when year(InstallationDate) + 10 > year(getdate()) then 'Ten year service due ' + cast(year(InstallationDate) + 10 as varchar)
    end as '10 Year Service'

    
from equipment e    

order by
case WHEN DATEFROMPARTS(year(getdate()),month(InstallationDate),day(InstallationDate)) < getdate()
    then dateadd(year,1, DATEFROMPARTS(year(getdate()),month(InstallationDate),day(InstallationDate)) )
    else   DATEFROMPARTS(year(getdate()),month(InstallationDate),day(InstallationDate))
    end asc

【问题讨论】:

【参考方案1】:

可以使用 GETDATE 作为 CURR_START_DT 以及使用 EOMONTH(GETDATE(), 2) 作为 CURR_END_DT 来计算即将到来的 2 个月日期窗口。截至今天的日期窗口是 CURR_START_DT ='2020-11-13' 和 CURR_END_DT='2021-01-31'。由于年份无关紧要,而且日期窗口可能跨越 1 年以上,因此 CALC_DT 是使用 CURR_START_DT 中的 YEAR 创建的,而 PLUS_CALC_DT 是使用 CURR_END_DT 中的 YEAR 创建的。像这样的

声明表并查询

declare @YourTable              table(InstallationDate      date);  

insert into @YourTable values 
 ('2008-1-17')
,('2011-4-28')
,('2012-5-13')
,('2020-9-6')
,('2006-12-2');

select yt.InstallationDate, dfp.calc_dt, dfp_plus.calc_dt as plus_calc_dt, 
       dfp.dt as curr_start_dt, dfp.eom as curr_end_dt 
from @YourTable yt
     cross apply
     (select cast(getdate() as date) dt, eomonth(getdate(), 2) eom,
             datefromparts(year(getdate()),
                           month(yt.InstallationDate), 
                           day(yt.InstallationDate)) calc_dt) dfp
     cross apply
     (select datefromparts(year(dfp.eom),
                           month(yt.InstallationDate), 
                           day(yt.InstallationDate)) calc_dt) dfp_plus
where dfp.calc_dt between dfp.dt and dfp.eom
      or
      dfp_plus.calc_dt between dfp.dt and dfp.eom;

输出

InstallationDate    calc_dt     plus_calc_dt    curr_start_dt   curr_end_dt
2008-01-17          2020-01-17  2021-01-17      2020-11-13      2021-01-31
2006-12-02          2020-12-02  2021-12-02      2020-11-13      2021-01-31

【讨论】:

非常感谢。自从它首先出现以来,我将其标记为答案。【参考方案2】:

根据要求,以下查询应该可以工作

SELECT
  InstallationDate,
  CONCAT(MONTH(InstallationDate),'-',DAY(InstallationDate)) as install_mmdd,
  CONCAT(MONTH(DATEADD(MONTH,2,InstallationDate)),'-',DAY(DATEADD(MONTH,2,InstallationDate))) as next_svc_mmdd
    FROM Equipment
    WHERE MONTH(DATEADD(MONTH,2,InstallationDate)) <= 3

SQL Fiddle link

【讨论】:

非常有帮助的感谢和小提琴是一个很大的帮助。谢谢回答。我将较早的答案标记为答案只是因为它排在第一位。【参考方案3】:

嗯。 . .我正在考虑构建下一个安装日期,然后只是做一个简单的比较:

select e.*
from equipment e cross apply
     (values (case when month(installationdate) < month(getdate()) or
                        (month(installationdate) = month(getdate()) and
                         day(installationdate < day(getdate())
                        )
                   then datefromparts(year(getdate()) + 1, month(installationdate), day(installationdate))
                   else datefromparts(year(getdate()), month(installationdate), day(installationdate))
               end)
     ) v(next_installationdate)                   
where next_installationdate < dateadd(month, -2, getdate())

【讨论】:

这有几个我修复的语法错误,但它没有返回任何数据。不过谢谢分享。

以上是关于SQL Server 查找接近服务日期和月份的行的主要内容,如果未能解决你的问题,请参考以下文章

在SQL Server表查询中查找不同的用户

在 SQL Server 中查找最近的日期

sql server 如何将日期时间字段修改成最接近该时间的整点时间?

查找具有月份最后日期的行

在 SQL Server 2008 中从月份和年份创建日期

如何从 sql server 2008 中具有不同 TaskIds 的表中查找日期?