查找两个最近的可比较日期(相同的工作日和每月的某天)

时间:2018-07-09 16:27:48

标签: sql-server date sql-server-2012

我尝试搜索时没有多大运气。我要根据输入的日期进行操作,获取两个最近的日期作为输入日期,这些日期具有每月的同一天和同一天。

例如,日期02/02/2018(dd / mm / yyyy)应该返回02/04/2018和02/10/2017,因为它们分别是第二个星期一和最近两次出现。

我有一个可以使用的日期表,我正在考虑自己进行联接以获取此日期,但我希望获得一些帮助。

编辑:忘了提及我正在使用SQL Server 2012

2 个答案:

答案 0 :(得分:0)

如果有日期表,则可以使用它。以下基于ANSI SQL函数的伪代码,因为date函数取决于数据库:

select d.*
from dates d
where extract(dow from d.date) = extract(dow from date '2018-07-02') and 
      extract(day from d.date) = extract(day from '2018-07-02') and
      d.date < date '2018-07-02'
order by d.date desc
fetch first 2 rows only;

答案 1 :(得分:0)

您的日期表需要计算每天的星期几(数字)。然后,只需JOIN进行排序,排序和选择前2行即可。

SQL Fiddle

MS SQL Server 2017架构设置

设置日期表

/********************************CALENDAR********************************/
/* 
    As always, thank you to Aaron Bertrand for the Calendar Table example. 
    https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/
*/

SET DATEFIRST 7 ; /* SUNDAY */ /* Make sure the week starts on the same day. */

CREATE TABLE datedim (
      theDate           date        PRIMARY KEY
    , theDay            AS DATEPART(day, theDate)           --int
    , theWeek           AS DATEPART(week, theDate)          --int 
    , theMonth          AS DATEPART(month, theDate)         --int
    , theYear           AS DATEPART(year, theDate)          --int
    , theDOW            AS DATEPART(weekday, theDate)       --int
    , yyyymmdd          AS CONVERT(char(8), theDate, 112)   /* yyyymmdd */
) ;

/************************************************************************/
/* 
  Use the catalog views to generate as many rows as we need. This example
  creates a date dimension for 1 Sept 2017 to 1 Aug 2018.
*/
INSERT INTO datedim ( theDate ) 
SELECT d
FROM (
    SELECT d = DATEADD(day, s1.rn - 1, '2017-01-01')
    FROM 
    (
        SELECT TOP ( DATEDIFF(day, '2017-01-01', '2018-12-31') )
            rn = ROW_NUMBER() OVER (ORDER BY sao.object_id)
        FROM sys.all_objects sao
    ) s1
) s2
/************************************************************************/

设置测试数据

/* TEST DATA */
CREATE TABLE t1 (id int identity, testDate date) ;

INSERT INTO t1 ( testDate )
VALUES 
    ( '2018-04-02' ) /* This */
  , ( '2017-10-02' ) /* This */
  , ( '2018-04-02' ) /* Duplicate */
  , ( '2017-09-27' )
  , ( '2018-07-01' )
  , ( '2018-05-02' ) /* Same day, Diff DOW */
  , ( '2017-09-02' ) /* Same day, Diff DOW */
  , ( '2017-10-09' ) /* Diff day, Same DOW */
  , ( '2017-01-02' ) /* Same day, Same DOW, Earlier */
  , ( null )
;

我添加了一些情况,这些情况会在早期的过滤器中得到处理,但最终会被过滤掉。请参阅设置中的注释。

主要查询

DECLARE @enteredDate date = '2018-07-02' /* This is the date you entered. */

SELECT TOP 2 s1.testDate
FROM (
  SELECT t1.testDate
    , ROW_NUMBER() OVER ( PARTITION BY t1.testDate ORDER BY t1.testDate DESC, t1.id DESC  ) AS rn
  FROM t1
  INNER JOIN datedim dd ON t1.testDate = dd.theDate
    AND dd.theDay = DATEPART(day,@enteredDate)
    AND dd.theDOW = DATEPART(weekday,@enteredDate)
) s1
WHERE rn = 1 /* Get 1st result for a date. */
ORDER BY s1.testDate DESC

在主查询中,我们要做的第一件事是使用ROW_NUMBER()窗口函数来确保只有重复的日期条目,我们才能得到一条记录。如果保证您的数据没有重复日期,则可以跳过此步骤。

[结果] [2]

|   testDate |
|------------|
| 2018-04-02 |
| 2017-10-02 |

我认为这个问题是一个很好的例子,说明日历表有多有用。