Replacing data in column that has different Grouped Data - sql

I have a SQL query that returns records with a group by statement. However, sometimes 1 column will have different values and return multiple rows instead of a single row as intended with the Group By.
SELECT ID, Division, Team
FROM Table
GROUP BY ID, Division, Team
----------------------------------------
ID Division Team
20 Div 1 2
20 Div 2 2
20 Div 3 2
----------------------------------------
I'd like the query to display this instead
----------------------------------------
ID Division Team
20 Multiple 2
----------------------------------------

You can use a case expression:
SELECT ID,
(CASE WHEN MIN(Division) = MAX(Division) THEN MIN(Division)
ELSE 'Multiple'
END) as Division,
Team
FROM Table
GROUP BY ID, Team

Related

Collapse multiple rows with character variables -- SQL

I have a table that looks like the following:
id
gender
race
income
1
M
[REDACTED]
10,000
1
[REDACTED]
2054-5
[REDACTED]
2
F
[REDACTED]
50,000
2
[REDACTED]
2054-5
[REDACTED]
I am trying to collapse it by the id variable, such that I get this dataset
id
gender
race
income
1
M
2054-5
10,000
2
F
2054-5
50,000
Normally, I would do the following:
select
max(gender),
max(race),
max(income),
id
from
table
group by id
but gender, race, and income are not numeric so I can't do that. Is there a way to select the non-redacted answers? For reference, I am conducting this in Snowflake using SnowSql.
You can try replacing the '[REDACTED]' value with null before the aggregation:
select max(CASE WHEN gender='[REDACTED]' THEN NULL ELSE gender END),
max(CASE WHEN race ='[REDACTED]' THEN NULL ELSE race END),
max(CASE WHEN income='[REDACTED]' THEN NULL ELSE income END),
id
from table
group by id
For a tested solution, please update your post with the DBMS you're using.
You can use CASE or NULLIF #lemon's answer shows you how to use CASE here is how to use NULLIF
select max(NULLIF(gender,'[REDACTED]')) as gender,
max(NULLIF(race ,'[REDACTED]')) as race,
max(NULLIF(income,'[REDACTED]')) as income,
id
from table
group by id

Get rollup group value in SQL Server

I have a table with following data:
Name
Score
A
2
B
3
A
1
B
3
I want a query which returns the following output.
Name
Score
A
2
A
1
Subtotal: A
3
B
3
B
3
Subtotal: B
6
I am able to get "Subtotal" with group by rollup query but I want to get subtotal along with group column value.
Please help me with some SQL code
If score has at most one value per name, you can use GROUPING SETS`:
select name, sum(score) as score
from t
group by grouping sets ((name, score), (name));
If name is never null, I would just use:
coalesce(name, 'Grouping ' + name)
Otherwise you need to use grouping().

SQL group by aggregate varchar column

I'm trying to figure out the SQL to aggregate the data in my Vehicles table:
Id | Name | Make
---+-------+------
1 Car Ford
1 Car Volvo
1 Car BMW
2 Bike Honda
3 Truck Tata
3 Truck abc
4 Train bullet
in order to return the following:
Id | Name | Result
---+-------+------
1 Car 3 items selected
2 Bike Honda
3 Truck 2 items selected
4 Train bullet
So if an Id,Name combination has more than one make then output 'X items selected' where X is the number of makes for that combination. Otherwise output the Make as-is. Note that the make will be unique for each Id,Name combination.
Can this be achieved using a GROUP BY expression? If so what aggregate function do I need in place of ??? below? Or can it be achieved some other way?
select Id,
Name,
case when count(Make) > 1 then convert(varchar(10), count(Make)) + ' items selected'
else ??? end Result
from Vehicles
group by Id, Name
I'm using SQL Server 2008.
Use MIN() or MAX():
select Id, Name,
(case when count(Make) > 1
then convert(varchar(10), count(Make)) + ' items selected'
else min(Make)
end) as Result
from Vehicles
group by Id, Name;
If there is only one row, then the MIN() and MAX() are the values on that row.
Use CTE (Common Table Expression) because that increase your query performance.especially in your query. check the Query
WITH Vehicles_CTE (Id, Name, Result,Make)
AS (
SELECT Id, Name, COUNT(1) Result, MAX(Make) Make FROM Vehicles
Group By Id, Name
)
SELECT Id, Name, CASE WHEN Result>1
THEN Cast(Result AS varchar(10)) + ' items selected'
ELSE Make End Result FROM Vehicles_CTE

Difference in output from two SQL queries

What is the difference between the two SQL queries below other than Query2 returning an additional field? Are there any possible scenarios where the output of the two queries would be different (other than the additional field in Query2)
Query1:
SELECT Field1, COUNT(*)
FROM Table1
GROUP BY Field1
HAVING COUNT(*) > 1
Query2:
SELECT Field1, Field2, COUNT(*)
FROM Table1
GROUP BY Field1, Field2
HAVING COUNT(*) > 1
Absolutely, these are different. Query2's Group By clause specifies an extra field. That means when the results are aggregated, they will be aggregated for the combined unique values of Field1 AND Field2. That is, two records are aggregated if and only if both Field1 and Field2 are equal.
For example:
SELECT Profession, Count(*)
FROM People
GROUP BY Profession
HAVING Count(*) > 1
will return a list of professions with associated counts like:
Software Developer, 10
PM, 5
Tester, 2
whereas:
SELECT Profession, Gender, Count(*)
FROM People
GROUP BY Profession, Gender
HAVING Count(*) > 1
will return a list of professions broken out by gender like:
Software Developer, Male, 5
Sofware Developer, Female, 5
PM, Male, 3
PM, Female, 2
Tester, Male, 2
Edit with additional requested information:
You can retrieve counts of professions with rows for both genders via:
SELECT Profession, Count(*)
FROM People
GROUP BY Profession
HAVING SUM(case Gender when 'Female' then 1 else 0 end) > 0 AND SUM(case Gender when 'Male' then 1 else 0 end) > 0
It gets a bit hairy (need subqueries) if you also need associated gender counts
Extra group by clause in query 2 filters records.To know more look at below example.
test data:
id name
1 a
2 b
3 a
4 a
So when I say group by name,sql first filters out distinct records for name which goes like below for the below query
select name,sum(id)
from test
group by name
--first filter out distinct values for group by column (here name)
a
b
--next for each distinct record ,how many values fall into that category..
a 1 a
4 a
3 a
b 2 b
So from the above groups ,now you can calculate any aggregations on the group in our case,it is sum,so next output will go some thing like this
a 8
b 2
As you can see from above output,you also can calculate,any aggregation on group (here a and b values) ,like give me count(id),len(name) on group like below
select name,len(name),sum(id)
from test
group by name
The same thing happens when you group by another field,lets say like below
select id,name
from
test
group by id,name
so in above case,sql first filters alldistinct records for id,name
1 a
2 b
3 a
4 a
next step is to get records which fall for each group
groupby columns --columns which fall into this
1 a 1 a
2 b 2 b
3 a 3 a
4 a 4 a
Now you can calculate aggergations on above groups.hope this helps in visualizing your group by.further having will eliminate groups after group by phase,where will eliminate record before group by phase

Selecting count by row combinations

I'm strugling with what on the first sight appeared to be simple SQL query :)
So I have following table which has three columns: PlayerId, Gender, Result (all of type integer).
What I'm trying to do, is to select distinct players of gender 2 (male) with number of each results.
There are about 50 possible results, so new table should have 51 columns:
|PlayerId | 1 | 2 | 3 | ... | 50 |
So I would like to see how many times each individual male (gender 2) player got specific result.
*** In case question is still not entirely clear to you: After each game I insert a row with a player ID, gender and result (from 1 - 50) player achieved in that game. Now I'd like to see how many times each player achieved specfic results.
If there are 50 results and you want them in columns, then you are talking about a pivot. I tend to do these with conditional aggregation:
select player,
sum(case when result = 0 then 1 else 0 end) as result_00,
sum(case when result = 1 then 1 else 0 end) as result_01,
. . .
sum(case when result = 50 then 1 else 0 end) as result_50
from t
group by player;
You can choose a particular gender if you like, with where gender = 2. But why not calculate all at the same time?
try
select player, result, count(*)
from your_table
where Gender = 2
group by player, result;
select PleyerId from tablename where result = 'specific result you want' and gender = 2 group by PleyerId
The easiest way is to use pivoting:
;with cte as(Select * from t
Where gender = 2)
Select * from cte
Pivot(count(gender) for result in([1],[2],[3],....,[50]))p
Fiddle http://sqlfiddle.com/#!3/8dad5/3
One note: keeping gender in scores table is a bad idea. Better make a separate table for players and keep gender there.