Group by values in one column - mysql

I have a table with this data in it:
ID Name Color
1 Kyle Blue
1 Susan Orange
1 Steven Orange
2 Susan Blue
I want to use a query like this:
Select * from table group by ID, Top1(Name), Top1(Color)
So I get these results:
ID Name Color
1 Kyle Blue
2 Susan Blue
I don't care if it's Kyle Blue, or Steven Orange as long as the color matches the name.

Eg
SELECT x.*
FROM my_table x
JOIN (SELECT id, MIN(name) min_name FROM my_table GROUP BY id) y
ON y.id = x.id
AND y.min_name = x.name;

select *
from (
select *,
row_number() over (partition by Name order by Name) as row_number
from table
) as rows
where row_number = 1

Related

Select the first occurrence of each id

I have table like this
id
name
1
Apple
1
Banana
1
Guava
2
Cassava
2
Carrot
2
Potato
3
Almond
3
Soybeans
3
Peanuts
I want to select only the first one from each id
id
name
1
Apple
2
Cassava
3
Almond
What's the query like?
you can try this way
SELECT id, name FROM table_name GROUP BY id ORDER BY id ASC;
You can achieve your goal by using row_number(). You can check my query in db-fiddle: https://www.db-fiddle.com/f/g4MrUTTTGDFfqjAKYnkFxn/1
WITH CTE as
(
SELECT id, name, ROW_NUMBER() OVER (ORDER BY null) as rowNumber FROM Fruits
)
SELECT id, name FROM CTE WHERE rowNumber IN(SELECT min(rowNumber) FROM CTE Group by id)

MYSQL - count how many times a person comes second in a competition

I have the following table called 'players' which contains scores from 3 games played by Tim, Bob and Jon.
playid | name | score
1 | Tim | 10
1 | Bob | 5
2 | Tim | 5
2 | Bob | 10
3 | Tim | 5
3 | Bob | 10
3 | Jon | 4
I want to be able to count the number of times that Tim, Bob and Jon have come second i.e. Tim = 2, Bob = 1, Jon = 0.
I have the following query:
SELECT name FROM players WHERE playid = 1 ORDER BY score Desc LIMIT 1, 1
Which returns the name of the person in second place in the first game i.e. Bob, but I can't figure out how to extend this to cover all games and players. Eventually I also want to be able to count the number of times they come 3rd, 4th etc.
Thanks in advance
Try with following one:
SELECT count(playid), name, score
FROM `players`
WHERE score = (SELECT MAX(score) FROM players WHERE score < (SELECT MAX(score) FROM players))
GROUP BY score, name;
With multiple joins and groupings:
select pl.name, ifnull(counter, 0) counter from (
select distinct name from players) pl
left join (
select players.name, count(*) counter from players
inner join (
select p.playid, max(p.score) as secondscore from (
select players.* from players
left join (
select playid, max(score) as maxscore
from players
group by playid) p
on p.playid = players.playid and p.maxscore = players.score
where p.maxscore is null) p
group by p.playid
) p
on p.playid = players.playid and p.secondscore = players.score
group by players.name) p
on p.name = pl.name
See the demo
You can use this query below to find the secondly-ranked people :
SELECT q2.playid, q2.name
FROM
(
SELECT q1.* , if(switch1,#r:=#r+1,#r:=0) as switch2
FROM
(
SELECT playid, score, name,
if(playid=#p,#p:=0,#p:=playid+1) as switch1
FROM players
JOIN ( SELECT #p:=0, #r:=-1 ) p2
ORDER BY playid, score desc
) q1
) q2
WHERE q2.switch2 = 1
ORDER BY q2.playid
playid name
------ ----
1 Bob
2 Tim
3 Tim
4 George
Rextester Demo
As per the comment by Raymond Nijland, in MySQL 8.0+ you can use window functions to achieve this:
SELECT name, COUNT(*) AS second_place_count
FROM (
SELECT
name,
playid,
ROW_NUMBER() OVER (PARTITION BY playid ORDER BY score DESC) AS rn
FROM players
) AS ranks
WHERE ranks.rn = 2
GROUP BY name
...or if you want to extend this to all places:
SELECT
name,
rn AS place,
COUNT(*) AS place_count
FROM (
SELECT
name,
playid,
ROW_NUMBER() OVER (PARTITION BY playid ORDER BY score DESC) AS rn
FROM players
) AS ranks
GROUP BY
name,
rn

Need MYSQL Query to select specific child rows only

FX., Given tables for baskets and fruits, looking for a query that returns the basket_id that contains ONLY the two specific fruit.
EX
table: fruits
basket_id | fruit
_________________
1 | apple
1 | orange
1 | pear
2 | apple
2 | orange
3 | apple
3 | pear
Given the above table, I'm looking for a query that returns the basket_id that ONLY contains the fruits "apple" and "orange", which would be row 2 only. Basket id 1 should be excluded because it also contains "pear".
Help with this would be most appreciated.
Please note for the example table, I added one more basket which is basket_id = 4, that has two apples only, and it will be a strong test sample for the query.
WITH ABC --sample table
AS
(
SELECT 1 as basket_id, 'Apple' as fruit
UNION ALL
SELECT 1 as basket_id, 'Orange' as fruit
UNION ALL
SELECT 1 as basket_id, 'Pear' as fruit
UNION ALL
SELECT 2 as basket_id, 'Apple' as fruit
UNION ALL
SELECT 2 as basket_id, 'Orange' as fruit
UNION ALL
SELECT 3 as basket_id, 'Apple' as fruit
UNION ALL
SELECT 3 as basket_id, 'Pear' as fruit
UNION ALL
SELECT 4 as basket_id, 'Apple' as fruit
UNION ALL
SELECT 4 as basket_id, 'Apple' as fruit
)
--main query:
SELECT basket_id FROM
(
SELECT *,CASE WHEN fruit in ('Apple','Orange') THEN 1 ELSE 0 END AS row_check
FROM ABC
) as A
GROUP BY basket_id
HAVING COUNT(DISTINCT row_check) =1 -- make sure there is no other fruit
AND COUNT(DISTINCT fruit) >1 -- make sure there are at least one apple and one orange
output: basket_id 2
select
f.basket_id,
(select count(1) from fruits where basket_id = f.basket_id) as fruits_in_basket,
(select count(1) from fruits where basket_id = f.basket_id and fruit in ("apple", "orange")) as specific_fruits_in_basket
from
fruits as f
group by f.basket_id
having fruits_in_basket = specific_fruits_in_basket
Here is a fiddle: http://sqlfiddle.com/#!9/f4ae3c/37/0
SELECT DISTINCT basket_id
FROM fruits f
WHERE
NOT EXISTS (SELECT 1 FROM fruits f1 WHERE f.basket_id=f1.basket_id AND f1.fruit NOT IN ('apple', 'orange'))
AND
(SELECT count(*) FROM fruits f2 WHERE f.basket_id=f2.basket_id AND f2.fruit='apple')=1
AND
(SELECT count(*) FROM fruits f3 WHERE f.basket_id=f3.basket_id AND f3.fruit='orange')=1;
I have tested the query on your example. Demo
If it is possible to use the list of items as an ordered list you want to select like 'apple,orange', then you can use following.
SELECT f.basket_id, f.fruit
FROM fruits f
INNER JOIN (
SELECT basket_id, GROUP_CONCAT(fruit order by fruit) as a
FROM fruits
GROUP BY basket_id
HAVING a = 'apple,orange'
) f1 ON f.basket_id = f1.basket_id
Here is the fiddle.
SELECT DISTINCT(basket_id)
FROM basket
where fruit IN ('apple', 'orange');

Order by two columns

Imagine the following MySQL table of orders:
id | name
1 | Mike
2 | Steve
3 | Janet
4 | Juliet
5 | Mike
6 | Jane
This is my current query:
SELECT * FROM table ORDER BY id DESC
However, I'd like to "group" those by name, so that I have orders from the same person listed after one another, however, I cannot do ORDER BY name.
This is my desired output:
id | name
6 | Jane
5 | Mike
1 | Mike
4 | Juliet
3 | Janet
2 | Steve
What's the query for this output?
E.g.:
SELECT y.id
, y.name
FROM my_table x
JOIN my_table y
ON y.name = x.name
GROUP
BY name
, id
ORDER
BY MAX(x.id) DESC
, id DESC;
You need to have special calculation to get their row position.
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT Name,
#ord := #ord + 1 ord
FROM
(
SELECT MAX(ID) ID, NAME
FROM TableName
GROUP BY Name
) a, (SELECT #ord := 0) b
ORDER BY ID DESC
) b ON a.Name = b.Name
ORDER BY b.ord, a.ID DESC
SQLFiddle Demo
You can do it via double ORDER BY:
SELECT * FROM t ORDER BY name ASC, id DESC
SELECT * FROM table1
ORDER BY field(NAME,'Mike','Jane') desc,
`ID` desc;
exactly as you asked
You could also try this query if you want to have something which is more generic SQL.
SELECT id, name
FROM ( SELECT id, name, (SELECT MAX(id) from Table1 where name=t.name) AS max_id
FROM Table1 AS t
ORDER BY max_id DESC, id DESC) as x
What about to use group by?
You can group it by name and then order...

Counting unique numbers in a column MySQL

I have a query that returns data in the following format:
id | name | number
1 John 12545
1 John 50496
2 Mary 23443
3 Mark 54
3 Mark 5600
3 Mark 50206
I would like to find out the number of distinct ids that appear in the result set. For example, for the result above. I would like to obtain the value 3.
Is there any way to add a column so the result looks like this instead?
count | id | name | number
3 1 John 12545
3 1 John 50496
3 2 Mary 23443
3 3 Mark 54
3 3 Mark 5600
3 3 Mark 50206
My query is:
SELECT * FROM (
SELECT id FROM tableA
WHERE xyz
) as t1
JOIN tableB using (id)
SELECT (SELECT COUNT(DISTINCT id) FROM tableName) totalCount,
id,name,number
FROM tableName
or by using CROSS JOIN
SELECT x.totalCount,
a.id, a.name, a.number
FROM tableName a, (SELECT COUNT(DISTINCT id) totalCount
FROM tableName) x
You should try :
SELECT id,name,number, (SELECT COUNT(DISTINCT name) FROM YourTableName) FROM YourTableName
Good luck
SELECT COUNT(DISTINCT id) would be faster than using column name.
SELECT (SELECT COUNT(DISTINCT id) FROM tableName) as 'count',
id,name,number
FROM tableName
SELECT COUNT(id) AS count , id, name, number
FROM
(
SELECT id
FROM tableA
WHERE xyz
) as t1
JOIN tableB using (id)
GROUP BY id, name, number