Reputation: 2101
I am working in SQL Server 2012. I have the following simple table:
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;
Columns NK1
and NK2
define the natural key for the table. My goal is to return the max row number (for each natural key: ORDER BY NK1 ASC, NK2 ASC, ID ASC
), the corresponding amount
value, and the sum of the amount
column for each natural key.
So, for the given table, I expect the following result set:
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
I am having troubles using 2+ aggregate functions in a single SELECT
statement (obviously, on 2+ different columns).
Here is my attempt:
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;
When I run the above query, I get the following error:
Incorrect syntax near the keyword 'From'.
and it's referring to the "FROM cte
" line. I believe this is occurring because of the 2+ aggregate functions on different columns in the SELECT
.
In particular, the "SUM
" line says that
'SUM' is not a recognized built-in function name.
How do I resolve this?
Upvotes: 0
Views: 374
Reputation: 10827
I'd suggest next approach:
CTE calculates RANK() (or ROW_NUMBER) but I ordered by NK1, NK2, ID DESC It allows a INNER JOIN with t table WHERE RowNumber = 1, hence you can get ID and amount of max row number.
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
Upvotes: 0
Reputation: 38063
I already upvoted the answer by Zohar because he cleared the error first, but I want to know why you are using row_number()
like this:
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;
How is it not the same as this?
select
NK1
, NK2
, count(*) as max_RowNumber
, sum(amount) as sum_amount
from t
group by NK1, NK2;
rextester demo showing the same results: http://rextester.com/XSGIP25353
Upvotes: 0
Reputation: 6174
The error is caused by the fact that your final SELECT
statement contains amount
, yet amount
is not in your GROUP BY
.
If you take amount
out of your final query, (not the SUM(amount)
, it works fine.
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;
RESULTS:
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
Upvotes: 0
Reputation: 82524
I got a different error:
Column 'cte.amount' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
When removing the ,amount
from the query, it works fine:
;
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
;
Results:
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
Upvotes: 2