SQL Server:如何在SELECT语句中的不同列上使用2+聚合函数?

时间:2017-03-15 21:55:52

标签: sql-server

我在SQL Server 2012中工作。我有以下简单表:

CREATE TABLE t
(
    NK1 varchar(255)
    ,NK2 varchar(255)
    ,ID int
    ,amount decimal(10,2)
);

INSERT INTO t
    SELECT 'a', 'x', 3, 10.00 UNION ALL
    SELECT 'a', 'x', 1, 5.00 UNION ALL
    SELECT 'a', 'x', 0, 15.00 UNION ALL
    SELECT 'a', 'y', 1, 0.00 UNION ALL
    SELECT 'a', 'y', 10, -5.00 UNION ALL
    SELECT 'b', 'x', 2, 10.00 UNION ALL
    SELECT 'b', 'y', 0, 0.00 UNION ALL
    SELECT 'b', 'y', -1, 15.00 UNION ALL
    SELECT 'b', 'y', 3, 10.00 UNION ALL
    SELECT 'b', 'y', 15, 10.00;

NK1NK2定义表的自然键。我的目标是返回最大行号(对于每个自然键:ORDER BY NK1 ASC, NK2 ASC, ID ASC),相应的amount值以及每个自然键的amount列的总和。

因此,对于给定的表,我期望得到以下结果集:

NK1 || NK2 || max_RowNumber || amount || sum_amount
a   | x    | 1              | 10.00   | 30.00
a   | y    | 2              | -5.00   | -5.00
b   | x    | 1              | 10.00   | 10.00
b   | y    | 4              | 10.00   | 35.00

我在单个SELECT语句中使用2个以上的聚合函数时遇到了麻烦(显然,在2个以上的不同列上)。

这是我的尝试:

WITH cte AS
(
    SELECT
        *,
        ROW_NUMBER() OVER (PARTITION BY NK1, NK2 ORDER BY NK1, NK2, ID) AS RowNumber
    FROM
        t
)
SELECT
    NK1, NK2,
    MAX(RowNumber) AS max_RowNumber,
    amount,
    SUM(amount) AS sum_amount
FROM
    cte
GROUP BY
    NK1, NK2;

当我运行上述查询时,出现以下错误:

  

关键字'From'附近的语法不正确。

它指的是“FROM cte”行。我相信这是因为SELECT中不同列上的2+聚合函数。

特别是,“SUM”行表示

  

'SUM'不是公认的内置函数名称。

如何解决此问题?

4 个答案:

答案 0 :(得分:2)

我得到了一个不同的错误:

  

列'cte.amount'在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。

从查询中删除,amount时,它可以正常工作:

;

WITH cte AS
(
SELECT
  *
  ,ROW_NUMBER() OVER (
                     PARTITION BY
                       NK1
                       ,NK2
                     ORDER BY
                       NK1
                       ,NK2
                       ,ID
                     ) AS RowNumber
  FROM
      t
)
SELECT
   NK1
   ,NK2
   ,MAX(RowNumber) AS max_RowNumber
   ,SUM(amount) AS sum_amount
FROM
   cte
GROUP BY
   NK1
   ,NK2
;

结果:

NK1     NK2     max_RowNumber   sum_amount
a       x       3               30,00
b       x       1               10,00
a       y       2               -5,00
b       y       4               35,00

3rd Image is pushed up

答案 1 :(得分:0)

错误是由于您的最终SELECT语句包含amount,但amount中不存在GROUP BY

如果您从最终查询中取出amount(而不是SUM(amount),则可以正常使用。

WITH cte AS (
SELECT *
    ,ROW_NUMBER() OVER (
      PARTITION BY
        NK1
        ,NK2
      ORDER BY
        NK1
        ,NK2
        ,ID
      ) AS RowNumber
FROM
  t
)
SELECT
   NK1
   ,NK2
   ,MAX(RowNumber) AS max_RowNumber
   ,SUM(amount) AS sum_amount
FROM cte
GROUP BY
NK1
,NK2;

结果:

NK1  NK2  max_RowNumber  sum_amount
---- ---- -------------- ----------
a    x    3              30.00
b    x    1              10.00
a    y    2              -5.00
b    y    4              35.00

答案 2 :(得分:0)

我已经赞同Zohar的答案,因为他首先清除了错误,但我想知道你为什么这样使用row_number()

with cte as (
 select *
  , row_number() over (
      partition by NK1, NK2 
      order by  NK1, NK2,ID /* NK1, NK2 don't do anything here either */
   ) as RowNumber
 from t
 )
select 
     NK1
   , NK2
   , max(RowNumber) as max_RowNumber
   , sum(amount) as sum_amount
from cte
group by NK1, NK2;

这与此不一样?

select 
     NK1
   , NK2
   , count(*) as max_RowNumber
   , sum(amount) as sum_amount
from t
group by NK1, NK2;

rextester演示显示相同的结果:http://rextester.com/XSGIP25353

答案 3 :(得分:0)

我建议采用下一种方法:

CTE计算RANK()(或ROW_NUMBER),但我按NK1,NK2排序, ID DESC 它允许INNER JOIN与t表WHERE RowNumber = 1,因此您可以获得ID和最大行号的数量。

WITH ctMax AS
(
    SELECT NK1, 
           NK2,
           ID,
           RANK() OVER (PARTITION BY NK1, NK2 ORDER BY NK1, NK2, ID DESC) AS RK
    FROM   t
)
SELECT     t.NK1, t.NK2, t.ID, t.amount,
           (SELECT SUM(amount)
            FROM  t t2
            WHERE t2.NK1 = t.NK1
            AND   t2.NK2 = t.NK2) as TotalAmount
FROM       t
INNER JOIN ctMax cm
ON         t.NK1 = cm.NK1
AND        t.NK2 = cm.NK2
AND        t.ID  = cm.ID
WHERE      cm.RK = 1;


NK1 | NK2 | ID | amount | TotalAmount
:-- | :-- | -: | :----- | :----------
a   | x   |  3 | 10.00  | 30.00      
a   | y   | 10 | -5.00  | -5.00      
b   | x   |  2 | 10.00  | 10.00      
b   | y   | 15 | 10.00  | 35.00      

dbfiddle here