SQL group by aggregate varchar column - sql

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

Related

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().

if count value of the column is greater than 1, I want to print the count of the column else I want to print value in the field

I am writing a query which fetches details from different tables. In one column I want to print count value of a column. If the count value of the column is greater than 1, I want to print the count of the column else I want to print value in the field.
I want to build a query which will give me count of user_id from table 1 & 2. if the count user_id is greater than 1, then print count (user_id) else print value of user_id
Table:1
| user_id |
| John |
| Bob |
| Kris |
| Tom |
Table:2
| user_id |
| Rob |
query result should list count of table1 as it greater than 1. Table2 should list Rob as it is lesser than 2
You want to select user IDs (names actually) from a table. If it's just one row then show that name, otherwise show the number of entries instead. So, just use a CASE expression to check whether count is 1 or greater than 1.
You probably need CAST or CONVERT to turn the count number into a string, so the CASE expression always returns the same type (this is how CASE works).
select
case when count(*) > 1
then cast(count(*) as varchar(100))
else max(user_id)
end as name_or_count
from mytable
Window Functions come to mind but since your user_ids are not numbers, you'll run into an issue where you can't have two different data types in the same column. See how this works for you. Make sure to cast the varchar numbers back to integer if this script is part of a larger process.
with cte as
(select 'John' as user_id union all
select 'Bob' as user_id union all
select 'Kris' as user_id union all
select 'Tom' as user_id)
select distinct case when count(*) over() > 1
then cast(count(*) over() as varchar) else user_id end
from cte
with cte as
(select 'Rob' as user_id)
select distinct case when count(*) over() > 1
then cast(count(*) over() as varchar) else user_id end
from cte

Replacing data in column that has different Grouped Data

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

SQL Group By and changing the grouped values

I have a table like this:
1 | Madrid | 45000
2 | Berlin | 35000
3 | Berlin | 65000
Now I want to show a result like this:
1 | Madrid | 45000
2 | Berlin | "Different Values"
So basically I want to use a "Group By" and if it is grouped, then change the value of some columns to a manual string.
I thought about using a view, update all values in this view to the string where i have duplications of the grouped column and then use the real query.
I even thought about implementing an assembly into the sql server that does this, but I don't find any good tutorials on this, only that you can do it.
Or has someone an even better idea? (The real tables used here are huge and the sql query does take sometimes up to 3 minutes to perform, so I made this example simple and I didn't wanted to work here with counts on every column to group, because that could take more than just a few minutes.
Something like this should work
select min(id) as id,
name,
case when count(*) = 1
then cast(sum(value) as varchar)
else 'Different values'
end as value
from your_table
group by name
I would do this as:
select min(id) as id, city,
(case when min(value) = max(value)
then cast(max(value) as varchar(255))
else 'Different Values'
end) as result
from t
group by city;
In fact, I might use something more informative than "different values", such as the range:
select min(id) as id, city,
(case when min(value) = max(value)
then cast(max(value) as varchar(255))
else cast(min(value) as varchar(255)) + '-' + cast(max(value) as varchar(255))
end) as result
from t
group by city;

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