【问题标题】:Add a column containing the id of the previous row in each group添加包含每个组中上一行的 id 的列
【发布时间】:2016-01-12 09:35:20
【问题描述】:

我想添加一列,其中包含每个组中上一行的 id。

示例:

Product       ID
Orange        1
Orange        2
Orange        3
Orange        4
Apple         5
Apple         6
Apple         7
Grapes        8
Grapes        9

期望的输出:

Product       ID
Orange        1
Orange        1
Orange        2
Orange        3
Apple         5
Apple         5
Apple         6
Grapes        8
Grapes        8

谢谢!

【问题讨论】:

  • 我也想要。到目前为止,您尝试过什么?
  • 我使用了 MIN([Id) OVER (PARTITION BY Description) 但这只是获取每个组中的第一行。
  • 由于 LAG 在上述版本中不可用,您必须找到一种解决方法。提示:前一个 ID 是所有较小 ID 中最高的 ID。如果 ID 没有间隙,那么您甚至可以从每个 ID 中减去一个,每个产品的最小 ID 除外。
  • @ohhzumm 检查我的答案,也许这就是你要找的。​​span>

标签: sql sql-server sql-server-2008 sql-server-2005 sql-server-2008-r2


【解决方案1】:

如果正确理解您的问题,您可以尝试以下方法:

SELECT DISTINCT Product, 
                MIN(Id) OVER (PARTITION BY Product) Id
FROM #Products

UNION ALL

SELECT Product, Id
FROM (
    SELECT Product, 
           Id, 
           ROW_NUMBER() OVER (PARTITION BY Product ORDER BY ID DESC) AS rn
FROM #Products
)x
WHERE rn <> 1
ORDER BY Id

输出

Product Id
Orange  1
Orange  1
Orange  2
Orange  3
Apple   5
Apple   5
Apple   6
Grapes  8
Grapes  8

【讨论】:

  • 它正在重复并且计数增加
【解决方案2】:

我会使用outer apply 或相关子查询来解决这个问题。通常,如果没有以前的 id,NULL 是完全可以接受的:

select s.*, s2.id as previd
from sample s outer apply
     (select top 1 s2.id
      from sample s2
      where s2.product = s.product and s2.id < s.id
      order by s2.id desc
     ) s2 ;

在这种情况下,您似乎想要第一个 id。这是一个修复:

select s.*, coalesce(s2.id, smin.minid) as previd
from sample s outer apply
     (select top 1 s2.id
      from sample s2
      where s2.product = s.product and s2.id < s.id
      order by s2.id desc
     ) s2 outer apply
     (select min(s2.id) as minid
      from sample s2
      where s2.product = s.product
     ) mins;

当然,在 SQL Server 2012+ 中,您将使用 ANSI 标准函数lag()

select s.*,
       coalesce(lag(s.id) over (partition by s.product order by s.id),
                min(s.id) over (partition by s.product)
               ) as sprev
from sample s;

【讨论】:

    【解决方案3】:
    DECLARE @DUMMY TABLE
      (
        Product VARCHAR(6) ,
        ID INT
      );
    
    INSERT  INTO @DUMMY ( Product, ID )
    VALUES  ( 'Orange', 1 ),
            ( 'Orange', 2 ),
            ( 'Orange', 3 ),
            ( 'Orange', 4 ),
            ( 'Apple', 5 ),
            ( 'Apple', 6 ),
            ( 'Apple', 7 ),
            ( 'Grapes', 8 ),
            ( 'Grapes', 9 );
    
    
    WITH  dummy
            AS (
                 SELECT [Product], [ID],
                        ROW_NUMBER() OVER ( PARTITION BY Product ORDER BY ID ) AS rn
                 FROM   @DUMMY AS [d]
               )
      SELECT  [d1].[Product], [d1].[ID], [d2].[ID]
      FROM    dummy AS [d1]
      LEFT JOIN dummy AS [d2] ON [d2].[Product] = [d1].[Product] AND
                                 [d2].[rn] + 1 = [d1].[rn]
      ORDER BY d1.[ID];
    

    PS:如果是 2012 年或之后的版本,那么它支持 ROWS/RANGE,就像 PostgreSQL 一样。 PS2:您可以使用 SQLFiddle 将示例数据作为代码而不是纯文本提供。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-09
      • 2015-09-03
      • 1970-01-01
      • 1970-01-01
      • 2021-01-25
      • 1970-01-01
      • 1970-01-01
      • 2020-12-14
      相关资源
      最近更新 更多