日期中的第一个值减去30天SQL

日期中的第一个值减去30天SQL,sql,sql-server,date,max,min,Sql,Sql Server,Date,Max,Min,我有一堆数据,其中我显示了ID、最大日期和它对应的值用户ID、类型等等。。。。然后我需要为每个ID取最大日期,减去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 0

我有一堆数据,其中我显示了ID、最大日期和它对应的值用户ID、类型等等。。。。然后我需要为每个ID取最大日期,减去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看起来是这样的: 选择MINN.name 从t1到N 其中N.ID=T.ID 和N.date=MAXT.date-30 和作为以前的名字

你是怎么写选择的

我正在使用TSQL


谢谢

我可以用两个CTE来建立日期和名称

MS SQL Server 2017架构设置:

主要查询:

:

cte1构建按ID分组的max_日期和max_名称列表,然后使用行数窗口函数按日期对组进行排序,以获得最近的日期。cte2返回此列表,以获取cte1最大日期后最后30天内的所有日期。然后它做了基本相同的事情来获得最后的日期。然后外部查询将这两个结果连接在一起,以获得所需的列,同时仅分别从每个结果中选择最近的行和最近的行

我不确定它与您的数据的可伸缩性如何,但使用CTE应该可以很好地进行优化

编辑:对于额外的要求,我刚刚在cte2中添加了另一个计数窗口函数

我会:

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;

将您的代码粘贴到此处,这样我们就可以看到它是否可以获得更好的示例数据,预期输出也是此处的标准要求:否则伪代码可能只会引出更多问题一对应用操作可能会有所帮助,但是如果不知道你现在在做什么,就很难知道。ID日期名称2018年5月1日AAA 2018年4月21日CCC 2018年4月5日BBB 2018年3月28日AAA预计:ID最大日期最大名称前一个日期前一个日期前一个日期2018年5月1日AAA 2018年4月5日BBBand前30天我正在使用这样的东西:从t1 N中选择MINN.Name,其中N.ID=T.ID和N.Date=MAXT.date-30和。。。如前所述,它的执行计划比我的要干净得多,但它不包括最大要求后30天内的最小日期。是否可以修改为仅选取ID的最近30天?可以修改subselect和WHERE子句。我喜欢这个方法。也许还有一个问题。我可以添加一个新的列来查看在这30天内我们有多少ID。谢谢
;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
| 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 |
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;