MySQL how to get first n groups? - mysql

For the follow table TestTable:
| Id | Name | Flags |
|----|-------|-------|
| 1 | name1 | 1 |
| 2 | name2 | 1 |
| 3 | name3 | 2 |
| 4 | name4 | 2 |
| 5 | name5 | 3 |
how to group by Flags and return the first 2 groups. That is to say I should return rows:
| 1 | name1 | 1 |
| 2 | name2 | 1 |
| 3 | name3 | 2 |
| 4 | name4 | 2 |
I tried this:
select *
from TestTable
group by Flags
order by Flags
limit 0,2
However the query returned 2 rows only.

You could use a sub query to take only the first two flags, and join that:
select t.id, t.name, t.flags
from testtable t
inner join (select distinct flags
from testtable
order by 1
limit 2) filter
on filter.flags = t.flags;
See it run on regtester.com

Related

Joining multiple rows with same ID in one

I am having trouble with an SQL query. I have two tables.
My first table:
+------------+-------------+---------------+
| id_mission | Some column | Other column |
+------------+-------------+---------------+
| 1 | ... | ... |
| 2 | ... | ... |
+------------+-------------+---------------+
My second table:
+------------+-------------+---------+
| id_mission | id_category | points |
+------------+-------------+---------+
| 1 | 1 | 3 |
| 1 | 2 | 4 |
| 1 | 3 | 4 |
| 1 | 4 | 8 |
| 2 | 1 | -4 |
| 2 | 2 | 3 |
| 2 | 3 | 1 |
| 2 | 4 | -7 |
+------------+-------------+---------+
And I would like to have this kind of result with my SELECT request
+------------+-------------+--------------+---------------+----------------+
| id_mission | Some column | Other column | id_category 1 | id_category X |
+------------+-------------+--------------+---------------+----------------+
| 1 | ... | ... | ... | ... |
| 2 | ... | ... | ... | ... |
+------------+-------------+--------------+---------------+----------------+
I have tried this with the first two column but it doesn't work, I also tried GROUP_CONCAT, it works but it's not the result I want.
SELECT m.id_mission ,mc.id_category 1,mc1.id_category 2
from mission m
left join mission_category mc on m.id_mission = mc.id_mission
left join mission_category mc1 on m.id_mission = mc1.id_mission
Can someone help me?
You can use conditional aggregation. Assuming that you want to pivot the points value per category:
select
t1.*,
max(case when t2.id_category = 1 then points end) category_1,
max(case when t2.id_category = 2 then points end) category_2,
max(case when t2.id_category = 3 then points end) category_3
from t1
inner join t2 on t2.id_mission = t1.id_mission
group by t1.id_mission
This assumes that id_mission is the primary key of t1 (else, you need to enumerate the columns you want in both the select and group by clauses).

How to update a column with the number of rows that have a matching column pair?

I have a table called related_clues which lists the id's of pairs of clues which are related
| id | clue_id | related_clue_id | relatedness |
+----+---------+-----------------+-------------+
| 1 | 1 | 232 | 1 |
| 2 | 1 | 306 | 1 |
| 3 | 1 | 458 | 1 |
| 4 | 2 | 620 | 1 |
| 5 | 2 | 72 | 1 |
| 6 | 3 | 212 | 1 |
| 7 | 3 | 232 | 1 |
| 8 | 3 | 412 | 1 |
| 9 | 3 | 300 | 1 |
+----+---------+-----------------+-------------+
Eventually after a while we may reach two id's such as:
+--------+---------+-----------------+-------------+
| id | clue_id | related_clue_id | relatedness |
+--------+---------+-----------------+-------------+
| 121267 | 1636 | 38 | 1 |
| 121331 | 1636 | 38 | 1 |
+--------+---------+-----------------+-------------+
So in this case, for two distinct id values, we have the same (clue_id, related_clue_id) pair
In this case I would like the relatedness value to be updated to 2, signalling that there are two examples of this (clue_id, related_clue_id) pair. Like so:
+--------+---------+-----------------+-------------+
| id | clue_id | related_clue_id | relatedness |
+--------+---------+-----------------+-------------+
| 121267 | 1636 | 38 | 2 |
| 121331 | 1636 | 38 | 2 |
+--------+---------+-----------------+-------------+
So essentially I would like to run some SQL that sets the relatedness value to the number of times a (clue_id, related_clue_id) pair appears.
When I have no relatedness column present, and I simply run the SQL:
SELECT id, clue_id, related_clue_id, COUNT(*) AS relatedness
FROM `related_clues`
GROUP BY clue_id, related_clue_id
It gives me the required result, but of course this doesn't store the relatedness column, it simply shows the column if I run this select. So how do I permanently have this relatedness column?
You could use a update with join
Update related_clues a
INNER JOIN (
SELECT clue_id, related_clue_id, COUNT(*) AS relatedness
FROM `related_clues`
group by clue_id, related_clue_id
having count(*) = 2
) t on t.clue_id = a.clue_id
and t.related_clue_id = a.related_clue_id
set a.relatedness = t.relatedness
I would approach this as an update/join but filter out rows that don't need to be updated:
update related_clues rc join
(select clue_id, related_clue_id, COUNT(*) AS cnt
from `related_clues`
group by clue_id, related_clue_id
) t
on t.clue_id = rc.clue_id and
t.related_clue_id = rc.related_clue_id
set rc.relatedness = t.relatedness
where rc.relatedness <> t.relatedness;

Selecting rows that are not defined

How to select rows which are not defined? Like row 2 have undefined day 3 and row 3 have undefined day 1. I want them to be 0 in result set.
+----+-----+-------+
| id | day | count |
+----+-----+-------+
| 1 | 1 | 262 |
| 1 | 2 | 685 |
| 1 | 3 | 984 |
| 2 | 1 | 692 |
| 2 | 2 | 962 |
| 3 | 2 | 355 |
| 3 | 3 | 741 |
+----+-----+-------+
EDIT:
I want select count from days 1, 2 and 3 (not whole table) and display 0 on undefined day.
We can get all unique id values in a Derived Table.
For day, you seem to want only 1,2 and 3 only. So we can directly consider these values only using UNION ALL.
CROSS JOIN between them to get all possible combinations.
LEFT JOIN from all_combinations table to the main table on id and day.
We can use Coalesce() function to consider 0 value for count, for the cases where there is no matching row in the main table
Try the following:
SELECT all_combinations.id,
all_combinations.day,
COALESCE(t.count, 0) AS count
FROM
(
SELECT ids.id, days.day
FROM
(SELECT DISTINCT id FROM your_table) AS ids
CROSS JOIN
(SELECT 1 AS day UNION ALL SELECT 2 UNION ALL SELECT 3) AS days
) AS all_combinations
LEFT JOIN your_table AS t
ON t.id = all_combinations.id AND
t.day = all_combinations.day
Result:
| id | day | count |
| --- | --- | ----- |
| 1 | 1 | 262 |
| 2 | 1 | 692 |
| 3 | 1 | 0 |
| 1 | 2 | 685 |
| 2 | 2 | 962 |
| 3 | 2 | 355 |
| 1 | 3 | 984 |
| 2 | 3 | 0 |
| 3 | 3 | 741 |
View on DB Fiddle

Fetch Max-Distict values from MySQL

I have a table in database. A user(Name) with a serial no(User-no) can play multiple times. Each time user plays, a new id(Id) is generated and it gets stored in the database along with the score(Score). I want to fetch the top three scores from the table where each users' only top scores get displayed.
Table:
Id | User-no | Name | Score
1 | 1 | Name1 | 400
2 | 2 | Name2 | 700
3 | 3 | Name3 | 100
4 | 2 | Name2 | 500
5 | 4 | Name4 | 800
6 | 3 | Name3 | 200
7 | 1 | Name1 | 500
8 | 4 | Name4 | 700
Result should be:
Id | User-no | Name | Score
5 | 4 | Name4 | 800
2 | 2 | Name2 | 700
7 | 1 | Name1 | 500
How can I get the above result. I am using MySQL.
this can be done with a join on a derived table, though you'd need the right index for it to be efficient
select id, uid, name, score
from scores
join (select uid, max(score) as score from scores group by uid) t
using (uid, score)
order by score desc
limit 3;
+------+------+------+-------+
| id | uid | name | score |
+------+------+------+-------+
| 5 | 4 | n4 | 800 |
| 2 | 2 | n2 | 700 |
| 7 | 1 | n1 | 500 |
+------+------+------+-------+
3 rows in set (0.00 sec)
Edit: the right index would be (uid, score). Derived tables do not have indexes, so mysql would loop through the max scores results and pull up the matching rows from the main table.

Counting from another table [mysql]

I have one table like this:
+----+---------+-------------+
| id | site_id | search_term |
+----+---------+-------------+
| 1 | 2 | apple |
| 2 | 2 | banana |
| 3 | 3 | cheese |
| 4 | 1 | aubergine |
+----+---------+-------------+
And another like this:
+----+---------+-------------+
| id | site_id | search_term |
+----+---------+-------------+
| 1 | 2 | 1 |
| 2 | 2 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 1 |
| 5 | 3 | 3 |
| 6 | 1 | 4 |
+----+---------+-------------+
I want to find out how many times each search_term shows up in the 2nd table, and how many times.
In other words, from this data, if I was asking about site_id 2, I'd want this to be returned:
+-------------+-------+
| search_term | count |
+-------------+-------+
| apple | 3 |
| banana | 1 |
+-------------+-------+
I'm familiar with basic joins and such, as well as COUNT, but I'm not sure how to count things from another table.
Thanks!
You could join the tables together, and count the number of rows in the second table:
select t1.search_term
, count(t2.id)
from table1 t1
left join table2 t2
on t1.id = t2.search_term
group by t1.search_term
Give this a try:
select t1.search_term, count(*) from t1
join t2 on t1.id = t2.search_term and t1.site_id = t2.site_id
where t1.site_id = 2
group by t1.search_term