getting individual records from a group by - mysql

I have two tables, one is a table of names with a category tag and the other is a table of scores for each name
ID Name Category
1 Dave 1
2 John 1
3 Lisa 2
4 Jim 2
and the score table is
PersonID Score
1 50
2 100
3 75
4 50
4 75
I would then like a query that returned something like
Category TotalScore Names
1 150 Dave, John
2 200 Lisa, Jim
Is this possible to do with one query?
I can get the totals with a sum query and grouping by category but cannot see a way to get the names as I would like.
Many thanks

You need to use group_concat:
select Category, sum(Score) as TotalScore, group_concat(Name) as Names from categories
join scores on scores.category = categories.category
group by category
Or even better:
group_concat(DISTINCT Name ORDER BY Name ASC SEPARATOR ',') as names

Just add group_concat(Name) as names into your sum query.

Here is a solution working for Postgres (which doesn't have a group_concat() function):
select category, sum(score) as TotalScore, array(select id from perso where category=P.category order by id) as Names from perso P JOIN scores S ON S."PersonID" = P.id GROUP BY category;
(I know this was a MySQL question, but nonetheless someone might google it up but needs an answer for Postgres :) )

Related

Can I compare different rows in the same MySQL table (SQL)

Is there a way to compare different rows in the same MySQL table? I want to count how many users have changed their names.
Here is roughly what I got in the MySQL log table...
id userid name
1 1 Joe
2 1 Joe
3 1 Joe
4 2 Fiona
5 3 Mark
6 3 Marcel
7 3 Marcel
8 4 Mary
9 4 Marie
You can see that Joe's name has not changed even though he is in the log table 3 times. "Mark" was changed to "Marcel" and "Mary" was changed to "Marie". So if this was the whole of the table, I want to know that 2 people have changed their names (out of four).
SELECT userid, GROUP_CONCAT(name) FROM tablename GROUP BY userid ORDER BY userid DESC
I can examine the output with a scripting language (PHP), I'm just wondering if there is something I can do in SQL that would be neater and only give me the names that are changed.
I'm not sure if this is possible. Haven't found a solution to this yet, if it's a duplicate please let me know. Thanks.
How about using a HAVING clause?
SELECT userid
FROM tablename
GROUP BY userid
HAVING MIN(name) <> MAX(name)
ORDER BY userid DESC;
If you want the names without duplicates:
SELECT userid, GROUP_CONCAT(DISTINCT name)
FROM tablename
GROUP BY userid
HAVING MIN(name) <> MAX(name)
ORDER BY userid DESC;

MySQL: Count occurrences of distinct values for each row

Based on an example already given, I would like to ask my further question.
MySQL: Count occurrences of distinct values
example db
id name
----- ------
1 Mark
2 Mike
3 Paul
4 Mike
5 Mike
6 John
7 Mark
expected result
name count
----- -----
Mark 2
Mike 3
Paul 1
Mike 3
Mike 3
John 1
Mark 2
In my opinion 'GROUP BY' doesn't help.
Thank you very much.
Simplest approach would be using Count() as Window Function over a partition of name; but they are available only in MySQL 8.0.2 and onwards.
However, another approach is possible using a Derived Table. In a sub-select query (Derived Table), we will identify the counts for each unique name. Now, we simply need to join this to the main table, to show counts against each name (while not doing a grouping on them):
SELECT
t1.name,
dt.total_count
FROM your_table AS t1
JOIN
(
SELECT name,
COUNT(*) AS total_count
FROM your_table
GROUP BY name
) AS dt ON dt.name = t1.name
ORDER BY t1.id
If MySQL 8.0.2+ is available, the solution would be less verbose:
SELECT
name,
COUNT(*) OVER (PARTITION BY name) AS total_count
FROM your_table

Guidance required for sql query

I have a database with one table as shown below. Here I'm trying to write a query to display the names of medication manufactured by the company that manufactures the most number of medications.
By looking at the table we could say the medication names which belongs to the company id 1 and 2 - because those company manufactures the most medication according to this table, but I'm not sure how to write a query for selecting the same i said before.
ID | COMPANY_ID | MEDICATION_NAME
1 1 ASPIRIN
2 1 GLUCERNA
3 2 SIBUTRAMINE
4 1 IBUPROFEN
5 2 VENOFER
6 2 AVONEN
7 4 ACETAMINOPHEN
8 3 ACETAMINO
9 3 GLIPIZIDE
Please share your suggestions. Thanks!
Several ways to do this. Here's one which first uses a subquery to get the maximum count, then another subquery to get the companies with that count, and finally the outer query to return the results:
select *
from yourtable
where companyid in (
select companyid
from yourtable
group by companyid
having count(1) = (
select count(1) cnt
from yourtable
group by companyid
order by 1 desc
limit 1
)
)
SQL Fiddle Demo
This Query might work. I have not tested but the logic is correct
SELECT MEDICATION_NAME
FROM TABLE where
COMPANY_ID=(SELECT
MAX(counted)
FROM ( SELECT COUNT(*) AS counted FROM TABLE ) AS counts);

Select grouped by two columns with Count

Im having problems trying to understand how to build this query.
My data scheme:
id category name userid
1 sports football 1
2 cars ferrari 1
3 sports basketball 1
4 film Matrix 9
5 film Fauno 9
6 sports Surf 3
As you can see the category can be repeated even for a same user id because the name field is different. So my idea is to get the categories of a set of users and the amount of users for each categories on that set.
Lets say i have the set of user set_of_user = (1,9,3), If i run the query
SELECT something FROM category_table WHERE userid IN set_of_user SOME CONDITION HERE
The correct result should be:
category: sports
users: 2
category: cars
users: 1
category: film
users: 1
My best shot was:
SELECT userid, category, COUNT(userid) as users from interests WHERE `userid` in ' . $norm_info_ids . ' GROUP BY category
But this gave a bad result, how can i solve this?
I think this is what you're looking for using COUNT with DISTINCT, along with GROUP BY:
select category, count(distinct userid)
from interests
where userid in (1,3,9)
group by category
SQL Fiddle Demo
Resulting in:
CATEGORY COUNT(DISTINCT USERID)
cars 1
film 1
sports 2
First you need to select the distinct paring of category and user id
select t.category, count(t.user_id)
from
(
SELECT distinct category,user_id
from tab
where user_id in (1,3,9)
) t
group by t.category

Select distinct column along with some other columns in MySQL

I can't seem to find a suitable solution for the following (probably an age old) problem so hoping someone can shed some light. I need to return 1 distinct column along with other non distinct columns in mySQL.
I have the following table in mySQL:
id name destination rating country
----------------------------------------------------
1 James Barbados 5 WI
2 Andrew Antigua 6 WI
3 James Barbados 3 WI
4 Declan Trinidad 2 WI
5 Steve Barbados 4 WI
6 Declan Trinidad 3 WI
I would like SQL statement to return the DISTINCT name along with the destination, rating based on country.
id name destination rating country
----------------------------------------------------
1 James Barbados 5 WI
2 Andrew Antigua 6 WI
4 Declan Trinidad 2 WI
5 Steve Barbados 4 WI
As you can see, James and Declan have different ratings, but the same name, so they are returned only once.
The following query returns all rows because the ratings are different. Is there anyway I can return the above result set?
SELECT (distinct name), destination, rating
FROM table
WHERE country = 'WI'
ORDER BY id
Using a subquery, you can get the highest id for each name, then select the rest of the rows based on that:
SELECT * FROM table
WHERE id IN (
SELECT MAX(id) FROM table GROUP BY name
)
If you'd prefer, use MIN(id) to get the first record for each name instead of the last.
It can also be done with an INNER JOIN against the subquery. For this purpose the performance should be similar, and sometimes you need to join on two columns from the subquery.
SELECT
table.*
FROM
table
INNER JOIN (
SELECT MAX(id) AS id FROM table GROUP BY name
) maxid ON table.id = maxid.id
The problem is that distinct works across the entire return set and not just the first field. Otherwise MySQL wouldn't know what record to return. So, you want to have some sort of group function on rating, whether MAX, MIN, GROUP_CONCAT, AVG, or several other functions.
Michael has already posted a good answer, so I'm not going to re-write the query.
I agree with #rcdmk . Using a DEPENDENT subquery can kill performance, GROUP BY seems more suitable provided that you have already INDEXed the country field and only a few rows will reach the server. Rewriting the query giben by #rcdmk , I added the ORDER BY NULL clause to suppress the implicit ordering by GROUP BY, to make it a little faster:
SELECT MIN(id) as id, name, destination as rating, country
FROM table WHERE country = 'WI'
GROUP BY name, destination ORDER BY NULL
You can do a GROUP BY clause:
SELECT MIN(id) AS id, name, destination, AVG(rating) AS rating, country
FROM TABLE_NAME
GROUP BY name, destination, country
This query would perform better in large datasets than the subquery alternatives and it can be easier to read as well.