【问题标题】:SQL Select: Get the previous Date in columnSQL Select:获取列中的上一个日期
【发布时间】:2017-10-26 11:45:59
【问题描述】:

我的 SQL 服务器中有一张表,上面有一些日期。现在我想创建一个 Select,它给我一个包含所有日期的列,然后是第二列,其中包含第一列的先前日期,第三列包含前一个日期列 (c2) 的先前日期。 举例:

  c1(orginal)          c2(prevoius of c1)    c3(previous of c2)
2017-10-15 00:00:00   2017-04-15 00:00:00   2016-10-15 00:00:00
2017-04-15 00:00:00   2016-10-15 00:00:00   2016-04-15 00:00:00
2016-10-15 00:00:00   2016-04-15 00:00:00   2015-10-15 00:00:00
2016-04-15 00:00:00   2015-10-15 00:00:00           null
2015-10-15 00:00:00           null                  null

颜色示例:

是否可以进行 SELECT,其中第一行是第 1 列的第一个日期,第 1 列的第二个日期和第 1 列的第三个日期。第二行是第 1 列的第二个日期,列的第三个日期1 和第 1 列的第四个。

我当前的查询

SELECT DISTINCT(BFSSTudStichdatum) AS C1, BFSSTudStichdatum AS C2, 
BFSSTudStichdatum AS C3  FROM BFSStudierende
ORDER BY C1 DESC

结果:

【问题讨论】:

  • 您已经尝试过哪些查询?
  • 你的意思是 column2 中 column1 的上一个最大日期等。你的问题说明了所有以前的日期,这意味着你的结果集的大小会爆炸
  • 您的数据是否可以包含重复项,如果可以,是否应消除重复项?

标签: sql sql-server tsql


【解决方案1】:

因为您需要首先获取日期列表 distinct,所以您需要将查询拆分为一个公用表表达式,然后使用 lag 获取您的 c2c3 值:

declare @t table(c1 datetime);
insert into @t values ('2017-10-15 00:00:00'),('2017-04-15 00:00:00'),('2016-10-15 00:00:00'),('2016-04-15 00:00:00'),('2015-10-15 00:00:00')
                     ,('2017-10-15 00:00:00'),('2017-04-15 00:00:00'),('2016-10-15 00:00:00'),('2016-04-15 00:00:00'),('2015-10-15 00:00:00');

with c as
(
    select distinct c1
    from @t
)
select c1
      ,lag(c1, 1) over (order by c1) as c2
      ,lag(c1, 2) over (order by c1) as c3
from c
order by c1 desc;

输出:

+-------------------------+-------------------------+-------------------------+
|           c1            |           c2            |           c3            |
+-------------------------+-------------------------+-------------------------+
| 2017-10-15 00:00:00.000 | 2017-04-15 00:00:00.000 | 2016-10-15 00:00:00.000 |
| 2017-04-15 00:00:00.000 | 2016-10-15 00:00:00.000 | 2016-04-15 00:00:00.000 |
| 2016-10-15 00:00:00.000 | 2016-04-15 00:00:00.000 | 2015-10-15 00:00:00.000 |
| 2016-04-15 00:00:00.000 | 2015-10-15 00:00:00.000 | NULL                    |
| 2015-10-15 00:00:00.000 | NULL                    | NULL                    |
+-------------------------+-------------------------+-------------------------+

【讨论】:

  • 如果同一个日期重复多次,这些滞后不能确保值小于前一个日期
  • @AbBennett 这由cte 中的select distinctlag 中的order by 负责。您会注意到,我的示例数据确实包含经过适当处理的重复数据。
  • 因此,如果您有 8 个日期,并且 2 个相同,则生成的数据集将是 7 行,这是错误的。在您的示例中,您将 6 行减少到 5 行来证明这一点
  • @AbBennett 幸好你不是 OP,不是吗?
  • @AbBennett 您会注意到这刚刚被接受为正确答案,我认为这可以最终解决问题。很高兴您如此热衷于在这里提供答案,但请仅在您有一个体面的答案并且不要那么激动时才这样做 - 我的意思是拒绝有用的答案,真的吗? - 因为发帖人不同意你的观点。
【解决方案2】:

你在找lag()吗?

select col1,
       lag(col1, 1) over (order by col1) as col1_prev,
       lag(col1, 2) over (order by col1) as col1_prev2
from t;

【讨论】:

  • 如果有重复的日期,第二个延迟将无法确保第三个日期小于第二个日期
  • 我在问题中看不到任何解决该问题的内容。您应该询问 OP (1) 是否存在重复项以及 (2) 如何处理它们。我认为没有理由不必要地使问题复杂化。
  • 如果没有这些信息,您就无法假设不可能有重复
  • @AbBennett 。 . .你可能不明白这个问题,但这张照片对我来说非常清楚。我看不出有歧义。你应该问 OP。
  • 图片如何清晰,如果你没有问过这个人或与他们核实过。
【解决方案3】:

对于 SQL Server 2008 及更高版本:

WITH DataSource AS
(
    SELECT DISTINCT *
          ,DENSE_RANK() OVER (ORDER BY c1) rowID
    FROM @t
)
SELECT DS1.[c1]
      ,DS2.[c1]
      ,DS3.[c1]
FROM DataSource DS1
LEFT JOIN DataSource DS2
    ON DS1.[rowID] = DS2.[rowID] + 1
LEFT JOIN DataSource DS3
    ON DS1.[rowID] = DS3.[rowID] + 2;

【讨论】:

    【解决方案4】:

    对于 SQL Server 2008 及更高版本:

    希望您确实想要一个自动列生成,其中一个值落后于过去列的第一个值。试试下面的 sn-p。

    根据数据集中的列数创建了一个动态查询。

    create table BFSStudierende
    (
    BFSSTudStichdatum  datetime
    )
    insert into BFSStudierende
    Select getdate()
    union
    Select dateadd(day,1,getdate())
    union
    Select dateadd(day,2,getdate())
    union
    Select dateadd(day,3,getdate())
    union
    Select dateadd(day,4,getdate())
    
    Declare @count int=(Select count(BFSSTudStichdatum ) from BFSStudierende)
    
    Declare @query nvarchar(max)='with BFSStudierendeCte as (Select *,row_number() over(order by BFSSTudStichdatum)rn  from BFSStudierende)  Select *from BFSStudierendeCte as BFSStudierendeCte1'
    
    Declare  @i int=2 ;
    Declare  @j int ;
    
    while(@i<=@count)
    begin
    Set @j=@i-1
    Set @query=@query+' left outer join BFSStudierendeCte as BFSStudierendeCte'+cast(@i as varchar(5)) +' on BFSStudierendeCte1.rn+'+cast(@j as varchar(5))+'=BFSStudierendeCte'+cast(@i as varchar(5))+'.rn';
    set @i+=1;
    End
    print @query
    Execute(@query)
    

    注意:重复的日期不会从结果中删除。如果您需要删除重复项。请在上面的 sn-p 中更改以下行。

    Declare @count int=(Select count(distinct BFSSTudStichdatum ) from BFSStudierende)
    
    Declare @query nvarchar(max)='with BFSStudierendeCte as (Select *,row_number() over(order by BFSSTudStichdatum)rn from(Select distinct BFSSTudStichdatum from BFSStudierende)l   )  Select *from BFSStudierendeCte as BFSStudierendeCte1'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 1970-01-01
      • 2022-01-04
      • 2014-12-14
      • 1970-01-01
      • 2018-03-21
      相关资源
      最近更新 更多