dionajie
dionajie

Reputation: 404

SQL Server : SUM Multiple columns without using group by

I have table like this.

Table 1 :

ID Name s1 s2 s3 id_sub
-----------------------
1  John 90 80 90 1
2  Nick 80 70 90 1
3  Mike 95 95 80 1
4  John 70 70 70 2

Table 2 :

id_sub sub sub_name
---------------
1      ph  physic
2      mt  math
3      cm  chemistry

Query:

SELECT t_score.name, (t_score.s1 + t_score.s2 + t_score.s3) as score 
FROM t_score, t_sub
where t_score.id_sub = t_sub.id_sub AND t_score.id_sub = 1
GROUP BY name 

I want it return like this

Name score
----------
John 260
Nick 240
Mike 210

But it returns

Column 't_score.s1' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause
Column 't_score.s2' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause
Column 't_score.s3' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

How to fix it?

[EDIT] i made a mistake on calculate score.

Name score
----------
John 260
Nick 240
Mike 270

score is SUM of each row contains s1+s2+s3

Upvotes: 1

Views: 2471

Answers (4)

gofr1
gofr1

Reputation: 15977

You can get what you need without GROUP BY and SUM, if you don't have duplicates with same id and name:

;WITH cte AS (
SELECT *
FROM (VALUES
(1, 'John', 90, 80, 90, 1),
(2, 'Nick', 80, 70, 90, 1),
(3, 'Mike', 95, 95, 80, 1),
(4, 'John', 70, 70, 70, 2)
) as t (ID, Name, s1, s2, s3, id_sub)
)

SELECT  name,
        IsNull(s1,0)+IsNull(s2,0)+IsNull(s3,0) as [score]
FROM cte
WHERE id_sub = 1

Output:

name score
---- -----------
John 260
Nick 240
Mike 270

(3 row(s) affected)

Upvotes: 2

Thorsten Kettner
Thorsten Kettner

Reputation: 94859

First of all you are using an antiquated join syntax that you shouldn't use anymore. Use explicit joins instead:

FROM t_score
JOIN t_sub ON t_sub.id_sub = t_score.id_sub

Then you join with t_sub, but you select no field from it, so why join at all? Your query could be re-written as:

SELECT name, (s1 + s2 + s3) AS score 
FROM t_score
WHERE id_sub = 1
GROUP BY name;

Then you group by name, but you don't say what aggregate on s1 etc. you want to see. Do you want to sum the maximum s1, s2, s3? Or the minimum values? Or the avarages? Probably the sums. Hence:

SUM(s1) + SUM(s2) + SUM(s3)

or simply

SUM(s1 + s2 + s3)

But then: can s1, s2 or s3 be NULL? Then you'd have to deal with that, too:

COALESCE(SUM(s1), 0) + COALESCE(SUM(s2), 0) + COALESCE(SUM(s3), 0)

Here is the final query:

SELECT 
  name, 
  COALESCE(SUM(s1), 0) + COALESCE(SUM(s2), 0) + COALESCE(SUM(s3), 0) AS score 
FROM t_score
WHERE id_sub = 1
GROUP BY name;

Or is the name in t_score unique (over all records or at least per id_sub)? Then you wouldn't have to aggregate records at all (i.e. no SUM, no GROUP BY):

SELECT 
  name, 
  COALESCE(s1, 0) + COALESCE(s2, 0) + COALESCE(s3, 0) AS score 
FROM t_score
WHERE id_sub = 1;

Upvotes: 1

Madhivanan
Madhivanan

Reputation: 13700

Use SUM function

SELECT t_score.name, SUM(t_score.s1 + t_score.s2 + t_score.s3) as score 
FROM t_score, t_sub
where t_score.id_sub = t_sub.id_sub AND t_score.id_sub = 1
GROUP BY name 

Upvotes: 3

Giorgos Betsos
Giorgos Betsos

Reputation: 72165

Use SUM:

SELECT t_score.name, SUM(t_score.s1 + t_score.s2 + t_score.s3) as score 
FROM t_score
INNER JOIN t_sub ON t_score.id_sub = t_sub.id_sub
WHERE t_score.id_sub = 1
GROUP BY name 

Also, it is preferable to use explicit join syntax, as in the above query.

Upvotes: 4

Related Questions