【问题标题】:How to get difference between two rows for a column field?如何获得列字段的两行之间的差异?
【发布时间】:2010-10-12 16:25:05
【问题描述】:

我有一张这样的桌子:

rowInt  Value
2       23
3       45
17      10
9       0
....

列 rowInt 的值是整数,但不是具有相同增量的序列。我可以使用以下 sql 按 rowInt 列出值:

SELECT * FROM myTable ORDER BY rowInt;

这将按 rowInt 列出值。如何获得两行之间的 Value 差异,结果如下:

rowInt   Value Diff
2        23    22    --45-23
3        45    -35   --10-45
9        0     -45   --0-45
17       10    10    -- 10-0
....

该表在 SQL 2005 (Miscrosoft) 中

【问题讨论】:

  • 第二行有 10-45 个吗?你从哪里拿 10 分?
  • 一些计算不一致...row2的(45-23)是row3-row2,但是row9的(0-45)是row9-row3,应该不是(10-0)第 17 行到第 9 行是哪个?
  • 您似乎想计算原始行集中相邻值之间的差异(2、3、17、9)。那我得问你:你的 ORIGINAL 行集是在哪一列排序的?请记住,SQL 中没有“默认排序”之类的东西。
  • 无论如何,解决问题。 (--10-45) 不对。

标签: sql sql-server tsql sql-server-2005


【解决方案1】:
SELECT
   [current].rowInt,
   [current].Value,
   ISNULL([next].Value, 0) - [current].Value
FROM
   sourceTable       AS [current]
LEFT JOIN
   sourceTable       AS [next]
      ON [next].rowInt = (SELECT MIN(rowInt) FROM sourceTable WHERE rowInt > [current].rowInt)

编辑:

考虑一下,在选择中使用子查询(ala Quassnoi 的答案)可能会更有效。我会试用不同的版本,并查看执行计划,看看哪个版本在您拥有的数据集大小上表现最佳......


EDIT2:

我仍然看到这获得了选票,尽管不太可能有很多人仍在使用 SQL Server 2005。

如果您可以访问诸如 LEAD() 之类的窗口函数,请改用它...

SELECT
  RowInt,
  Value,
  LEAD(Value, 1, 0) OVER (ORDER BY RowInt) - Value
FROM
  sourceTable

【讨论】:

  • 如果他在 rowInt 上有一个索引(我认为他有),那么我的查询效率更高。如果他没有,那么你的就是(如果在这种情况下可以谈论效率)。详情请看这里:stackoverflow.com/questions/590079/…
  • 我创建了一个包含 100 万条随机创建记录的虚拟表,发现两个查询花费了相同的时间。事实上,执行计划的唯一区别是 SORT 函数的位置(我对最终输出进行了排序)
【解决方案2】:
SELECT rowInt, Value,
       COALESCE(
       (
       SELECT TOP 1 Value
       FROM myTable mi
       WHERE mi.rowInt > m.rowInt
       ORDER BY
             rowInt
       ), 0) - Value AS diff
FROM  myTable m
ORDER BY
      rowInt

【讨论】:

    【解决方案3】:

    SQL Server 2012 及更高版本支持 LAG / LEAD 函数来访问前一行或后一行。 SQL Server 2005 不支持此功能(在 SQL2005 中,您需要连接或其他方式)。

    关于此数据的 SQL 2012 示例

    /* Prepare */
    select * into #tmp
    from
    (
        select 2  as rowint,      23 as Value
        union select 3,       45
        union select 17,      10
        union select 9,       0
    ) x
    
    
    /* The SQL 2012 query */
    select rowInt, Value, LEAD(value) over (order by rowInt) - Value  
    from #tmp
    

    LEAD(value) 将根据“over”子句中的给定顺序返回下一行的值。

    【讨论】:

    • 滞后。不是小伙子。它不允许我编辑,因为您必须更改 6 个字符
    • 这是最好的解决方案。其他答案很巧妙,但这很有效。
    • @DonkeyKong - 其他答案反映问题是针对不支持分析/窗口函数的 SQL Server 2005。
    【解决方案4】:

    如果您真的想确定订单,请使用“Row_Number()”并比较当前记录的下一条记录(仔细查看“on”子句)

    T1.ID + 1 = T2.ID
    

    您基本上是将下一行与当前行连接起来,而无需指定“min”或执行“top”。如果您的记录数量较少,“Dems”或“Quassanoi”的其他解决方案将可以正常工作。

    with T2 as (
        select  ID = ROW_NUMBER() over (order by rowInt),
                rowInt, Value
        from    myTable
    )
    select  T1.RowInt, T1.Value, Diff = IsNull(T2.Value, 0) - T1.Value
    from    (   SELECT  ID = ROW_NUMBER() over (order by rowInt), *
                FROM    myTable ) T1
            left join T2 on T1.ID + 1 = T2.ID
    ORDER BY T1.ID
    

    【讨论】:

      【解决方案5】:

      SQL Server 是否支持分析函数?

      select   rowint,
               value,
               value - lag(value) over (order by rowint) diff
      from     myTable
      order by rowint
      /
      

      【讨论】:

      • Msg 195, Level 15, State 10, Line 3 'lag' 不是公认的内置函数名称。
      • 我给了这一点,因为是的 Denali 确实如此......尽管发布此答案时可能 sql server 没有
      • @FairFunk 我减去了一点,因为这个问题被标记为 2005 年,所以 Denali 功能无关紧要。
      【解决方案6】:
      select t1.rowInt,t1.Value,t2.Value-t1.Value as diff
      from (select * from myTable) as t1,
           (select * from myTable where rowInt!=1
            union all select top 1 rowInt=COUNT(*)+1,Value=0 from myTable) as t2
      where t1.rowInt=t2.rowInt-1
      

      【讨论】:

        【解决方案7】:

        查询单列两行之间的日期差异

        SELECT
        Column name,
        DATEDIFF(
        (SELECT MAX(date) FROM table name WHERE Column name < b. Column name),
        Column name) AS days_since_last
        FROM table name AS b
        

        【讨论】:

        • 这是一个非常古老的问题,您的回答并没有真正回答提出的相同问题。
        【解决方案8】:

        我只是为此做一个小功能。折腾两个值,您需要知道它们之间的差异,并让它从较大的值中减去较小的值。比如:

        CREATE FUNCTION [dbo].[NumDifference] 
            (   @p1 FLOAT,
                @p2 FLOAT )
        RETURNS FLOAT
        AS
        BEGIN
            DECLARE @Diff FLOAT
            IF @p1 > @p2 SET @Diff = @p1 - @p2 ELSE SET @Diff = @p2 - @p1
            RETURN @Diff
        END
        

        在查询中获取 a 列和 b 列之间的差异:

        SELECT a, b, dbo.NumDifference(a, b) FROM YourTable
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-10-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多