【问题标题】:What is the counterpart for SUM() in SQL Server?SQL Server 中 SUM() 的对应物是什么?
【发布时间】:2024-05-22 04:15:01
【问题描述】:

SQL Server 中,您可以执行 sum(field1) 来获取与 groupby 子句匹配的所有字段的总和。
但我需要减去字段,而不是相加。
有没有类似的东西可以用来代替 sum(field1) ?

例如table1有这样的内容:

name field1  
A 1  
A 2  
B 4  

查询:

select name, sum(field1), subtract(field1)  
from table1  
group by name  

会给我:

A 3 -1  
B 4 4 

我希望我的问题很清楚。

编辑:

还有一个我可以使用的排序字段。 这确保值 1 和 2 将始终导致 -1 而不是 1。

我需要的是减去 A 的所有值,在我的示例中为 1 - 2 = -1

编辑2: 如果 A 组的值为 1、2、3、4,则结果必须为 1 - 2 - 3 - 4 = -8

【问题讨论】:

  • subtract 将转换为 SUM(-field1) 但从您给出的示例来看,它不会给您想要的结果。你想要+X1-X2-X3,它不是和的倒数,是+X1+X2+X3
  • 您必须有一列指示订单,因为 2-1 不是 1-2
  • 你必须详细说明这个函数应该如何工作。如果 A 组有以下值:1、2、3、4,最终结果应该是什么,为什么?
  • 如果一个组的值为 1、2、3、4,则结果必须为 1 - 2 - 3 - 4 = -8

标签: sql sql-server tsql aggregate-functions


【解决方案1】:

假设您有一些列来指示顺序,要选择每个组的第一个元素,您可以使用窗口函数来计算您的 substract

CREATE TABLE tab(ID INT IDENTITY(1,1) PRIMARY KEY, name CHAR(1), field1 INT);
INSERT INTO tab(name, field1) VALUES ('A', 1), ('A', 2), ('B', 4);

SELECT DISTINCT 
   name
   ,[sum]       = SUM(field1) OVER (PARTITION BY name)
   ,[substract] = SUM(-field1) OVER (PARTITION BY name) 
                  + 2*FIRST_VALUE(field1) OVER(PARTITION BY name ORDER BY ID)
FROM tab;

LiveDemo

输出:

╔══════╦═════╦═══════════╗
║ name ║ sum ║ substract ║
╠══════╬═════╬═══════════╣
║ A    ║   3 ║        -1 ║
║ B    ║   4 ║         4 ║
╚══════╩═════╩═══════════╝

警告:

FIRST_VALUE 可从SQL Server 2012+ 获得

【讨论】:

    【解决方案2】:

    所以你想从第一个值中减去倒数第二个的总和?

    您需要一列来指示顺序。如果您没有像 datetime 列这样的逻辑列,则可以使用主键。

    这是一个使用公用表表达式(CTE)和ROW_NUMBER-function 的示例:

    WITH CTE AS
    (
        SELECT Id, Name, Field1,
               RN = ROW_NUMBER() OVER (Partition By name ORDER BY Id)
        FROM dbo.Table1
    ), MinValues AS
    (
        SELECT Id, Name, Field1
        FROM CTE
        WHERE RN = 1
    )
    , OtherValues AS
    (
        SELECT Id, Name, Field1
        FROM CTE
        WHERE RN > 1
    )
    SELECT mv.Name, 
           MIN(mv.Field1) - COALESCE(SUM(ov.Field1), 0) AS Subtract
    FROM MinValues mv LEFT OUTER JOIN  OtherValues ov 
        ON mv.Name = ov.Name
    GROUP BY mv.Name  
    

    Demo

    【讨论】:

      【解决方案3】:

      另一种方法

      declare @t table(name char(1), field1  int)
      insert into @t
      select 'A', 1 union all  
      select 'A', 2  union all
      select 'B', 4
      
      
      
      select name, sum(field1) as addition,
                   sum(case when sno=1 then field1 else -field1 end) as subtraction from 
      (
          select *, row_number() over (partition by name order by (select 1)) as sno from @t 
      ) as t2 group by name
      

      【讨论】:

      • ORDER BY (SELECT 1) 不可靠。它可以返回表中的值,但不能保证。
      【解决方案4】:

      除了使用算法解决问题的所有答案之外,您还必须记住,SUM 是数据集的聚合。您无法在此处预测执行顺序。

      这就是人们提到 SUM (-field) 的原因 - 这不是真正的减法运算,它只会反转值并在数据集上使用 SUM,因为“减法”实际上没有任何意义放。减法需要您定义参数选择的顺序以对它们应用二元运算符。

      【讨论】:

        最近更新 更多