如何使用动态滞后功能来避免将表连接到自身以检索日期值

问题描述 投票:0回答:4

我目前正在用 SQL 编写代码,将红色列添加到下表中:

Example Table

逻辑如下:

对于每一行:

  • 如果该行的标志=1,则使用该行的日期

  • 如果该行的标志=0,则找到同一方标志=1的最新行(基于日期),并返回该行的日期。如果不存在这样的行,则返回 null

我找到了一种通过将表格连接到自身来实现此目的的方法,但我想避免这样做,因为表格的大小非常大。

我有什么


select b.*, a.date, 
  from table a left join table b on a.party=b.party
  where a.flag =1


有人告诉我我可以使用滞后函数、分区函数以及何时返回我想要的值的情况,但我一直无法弄清楚。

有人可以帮忙吗?非常感谢!

sql sql-server lag partition
4个回答
5
投票

试试这个

    DECLARE @tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
    INSERT INTO @tab1
    SELECT 'A','7-24-2018',1 Union ALL
    SELECT 'A','7-28-2018',0 Union ALL
    SELECT 'A','7-29-2018',0 Union ALL
    SELECT 'A','7-29-2018',0 Union ALL
    SELECT 'B','7-13-2018',1 Union ALL
    SELECT 'B','7-17-2018',0 Union ALL
    SELECT 'B','7-18-2018',0 Union ALL
    SELECT 'C','7-8-2018',1 Union ALL
    SELECT 'C','7-13-2018',0 Union ALL
    SELECT 'C','7-19-2018',0 Union ALL
    SELECT 'C','7-19-2018',0 Union ALL
    SELECT 'C','7-20-2018',0


    select t.*,
           max(case when flag = 1 then date end) over (partition by PARTY order by date) as [Last Flag On Date]
    from @tab1 t


0
投票

使用

CROSS APPLY()
获取标志为 1 的最新行

SELECT *
FROM   yourtable t
       CROSS APPLY
       (
           SELECT TOP 1 x.Date as [Last flag on date]
           FROM   yourtable x
           WHERE  x.Party = t.Party
           AND    x.Flag = 1
           ORDER BY x.Date desc
       ) d

0
投票

是的,如果写得正确,可以通过连接表来完成。

@Sahi 查询也很好,很简单。

既然你要求

Dynamic LAG()

这个查询的性能可能很高,也可能不是很高,但它确实值得学习。

使用各种示例数据对此进行测试,并告诉我它不适用于哪种场景。 这样我就可以相应地修改我的脚本。

 DECLARE @tab1 TABLE(PARTY CHAR(1),DATE DATE,Flag bit)
INSERT INTO @tab1
SELECT 'A','7-24-2018',1 Union ALL
SELECT 'A','7-28-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'A','7-29-2018',0 Union ALL
SELECT 'B','7-13-2018',1 Union ALL
SELECT 'B','7-17-2018',0 Union ALL
SELECT 'B','7-18-2018',0 Union ALL
SELECT 'C','7-8-2018',1 Union ALL
SELECT 'C','7-13-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-19-2018',0 Union ALL
SELECT 'C','7-20-2018',0; 

WITH cte 
     AS (SELECT *, 
                Row_number() 
                  OVER ( 
                    partition BY party 
                    ORDER BY flag DESC, [date] DESC ) rn 
         FROM   @tab1) 
SELECT *, 
       CASE 
         WHEN flag = 1 THEN [date] 
         ELSE Lag([date], (SELECT TOP 1 a.rn - a1.rn 
                           FROM   cte a1 
                           WHERE  a1.party = a.party)) 
                OVER ( 
                  ORDER BY party ) 
       END 
FROM   cte a 

0
投票

试试这个:->

select 
  b.*, 
  a.date, 
from 
  table a 
  left join table b on a.party = b.party 
where 
  a.flag = CASE WHEN a.flag = 1 THEN a.date WHEN a.flag = 0 THEN (
    SELECT 
      date 
    FROM 
      (
        SELECT 
          TOP 1 row_number() OVER (
            ORDER BY 
              a.date DESC
          ) rs, 
          a.date 
        FROM 
          a 
        WHERE 
          a.flag = 1 
        GROUP BY 
          a.date
      ) s
  ) END

© www.soinside.com 2019 - 2024. All rights reserved.