DATE的第一个值减去30天的SQL

时间:2018-07-11 13:33:15

标签: sql sql-server date max min

我有一堆数据,其中显示了ID,最大日期及其对应的值(用户ID,类型,...)。然后我需要为每个ID取MAX日期,减去30天并显示第一个日期及其在该日期范围内的对应值。

示例:

ID  Date        Name
1   01.05.2018  AAA
1   21.04.2018  CCC
1   05.04.2018  BBB
1   28.03.2018  AAA

预期:

ID  max_date    max_name previous_date previous_name 
1   01.05.2018  AAA      05.04.2018 BBB

我有使用子选择的有效解决方案,但是由于我的WHERE部分相当庞大,刷新需要一段时间。

SUBSELECT看起来像这样: (SELECT MIN(N.name)     从t1 N开始     N.ID = T.ID         AND(N.date =(MAX(T.date)-30))         AND(...))AS PreviousName

您如何编写选择?

我正在使用TSQL

谢谢

2 个答案:

答案 0 :(得分:1)

我可以使用2个CTE来建立日期和名称。

SQL Fiddle

MS SQL Server 2017架构设置

CREATE TABLE t1 (ID int, theDate date, theName varchar(10)) ;

INSERT INTO t1 (ID, theDate, theName)
VALUES
    ( 1,'2018-05-01','AAA' )
  , ( 1,'2018-04-21','CCC' )
  , ( 1,'2018-04-05','BBB' )
  , ( 1,'2018-03-27','AAA' )
  , ( 2,'2018-05-02','AAA' )
  , ( 2,'2018-05-21','CCC' )
  , ( 2,'2018-03-03','BBB' )
  , ( 2,'2018-01-20','AAA' )
;

主要查询

;WITH cte1 AS (
  SELECT t1.ID, t1.theDate, t1.theName
    , DATEADD(day,-30,t1.theDate) AS dMinus30
    , ROW_NUMBER() OVER (PARTITION BY t1.ID ORDER BY t1.theDate DESC) AS rn
  FROM t1
)
, cte2 AS (
  SELECT c2.ID, c2.theDate, c2.theName
    , ROW_NUMBER() OVER (PARTITION BY c2.ID ORDER BY c2.theDate) AS rn
    , COUNT(*) OVER (PARTITION BY c2.ID) AS theCount
  FROM cte1
  INNER JOIN cte1 c2 ON cte1.ID = c2.ID
    AND c2.theDate >= cte1.dMinus30
  WHERE cte1.rn = 1
  GROUP BY c2.ID, c2.theDate, c2.theName
)
SELECT cte1.ID, cte1.theDate AS max_date, cte1.theName AS max_name
  , cte2.theDate AS previous_date, cte2.theName AS previous_name 
  , cte2.theCount
FROM cte1 
INNER JOIN cte2 ON cte1.ID = cte2.ID 
  AND cte2.rn=1
WHERE cte1.rn = 1

Results

| ID |   max_date | max_name | previous_date | previous_name |
|----|------------|----------|---------------|---------------|
|  1 | 2018-05-01 |      AAA |    2018-04-05 |           BBB |
|  2 | 2018-05-21 |      CCC |    2018-05-02 |           AAA |

cte1构建按max_date分组的max_nameID的列表,然后使用ROW_NUMBER()窗口函数按日期对分组进行排序,以获取最新日期。 cte2返回此列表,以获取cte1的最大日期的最近30天内的所有日期。然后,它执行相同的操作来获取最后一个日期。然后,外部查询将这两个结果结合在一起,以获取所需的列,而仅分别从每个行中选择最新和最近的行。

我不确定它将如何随您的数据扩展,但是使用CTE应该可以很好地进行优化。

编辑:出于其他要求,我刚刚在COUNT()中添加了另一个cte2窗口函数。

答案 1 :(得分:0)

我会做的:

select id,
       max(case when seqnum = 1 then date end) as max_date,
       max(case when seqnum = 1 then name end) as max_name,
       max(case when seqnum = 2 then date end) as prev_date,
       max(case when seqnum = 2 then name end) as prev_name,
from (select e.*, row_number() over (partition by id order by date desc) as seqnum
      from example e
     ) e
group by id;