Selecting rows that are not defined - mysql

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

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;

Filter every column in MySQL

I have a database with three tables right now : equipements and equipements_statistics that contains the statistics of each equipements and finally stats that contains all type of statistics.
To retrieve an equipement on a filter I'm doing this query :
SELECT
*
FROM
`equipement`
INNER JOIN `equipement_stats` ON `equipement_stats`.`id_equipement` = `equipement`.`id_equipement`
INNER JOIN `stats` ON `stats`.`id_stats` = `equipement_stats`.`id_stats`
WHERE
`stats`.`id_stats` IN(1068, 1069)
GROUP BY
`equipement`.`id_equipement`
HAVING
COUNT(DISTINCT stats.id_stats) = 1
LIMIT 10
Tables are like this :
equipement
+---------------+-----------------+
| id_equipement | name_equipement |
+---------------+-----------------+
| 1 | one |
| 2 | two |
| 3 | three |
+---------------+-----------------+`
equipement_stats
+---------------+-----------+---------------+
| id_equipement | id_stats | random_number |
+---------------+-----------+---------------+
| 1 | 2 | 0 |
| 1 | 4 | 0 |
| 1 | 1069 | 1 |
| 1 | 8 | 0 |
| _____________ | _________ | _____________ |
| 2 | 1070 | 2 |
| 2 | 1069 | 3 |
| 2 | 20 | 0 |
| 2 | 40 | 0 |
+---------------+-----------+---------------+
If stats are 1068 or 1069 I must filter them on the column random_number but random_number value can be different for 1070 and 1069. How to look only for a precise id_stats with a precise random_number?
In my case for example, I would like to filter on equipements that has the stats 1070 with random_number 2 and stats 1069 with random_number 3 as the 2nd entry.
Thanks you for helping!
The easiest way to filter tuples is this:
WHERE (equipement_stats.id_stats, equipement_stats.random_number) IN ( (1068,2) , (1069,3) )

mysql: order -> limit -> sum... possible?

i am loosing it over the following problem:
i have a table with participants and points. each participant can have up to 11 point entries of which i only want the sum of the top 6.
in this example lets say we want the top 2 of 3
+----+---------------+--------+
| id | participantid | points |
+----+---------------+--------+
| 1 | 1 | 11 |
+----+---------------+--------+
| 2 | 3 | 1 |
+----+---------------+--------+
| 3 | 3 | 4 |
+----+---------------+--------+
| 4 | 2 | 3 |
+----+---------------+--------+
| 5 | 1 | 5 |
+----+---------------+--------+
| 6 | 2 | 10 |
+----+---------------+--------+
| 7 | 2 | 9 |
+----+---------------+--------+
| 8 | 1 | 3 |
+----+---------------+--------+
| 9 | 3 | 4 |
+----+---------------+--------+
as a result i want something like
+---------------+--------+
| participantid | points |
+---------------+--------+
| 2 | 19 |
+---------------+--------+
| 1 | 16 |
+---------------+--------+
| 3 | 8 |
+---------------+--------+
(it should be ordered DESC by the resulting points)
is this at all possible with mysql? in one query?
oh and the resulting participant ids should be resolved into the real names from another 'partcipant' table where
+----+------+
| id | name |
+----+------+
| 1 | what |
+----+------+
| 2 | ev |
+----+------+
| 3 | er |
+----+------+
but that should be doable with a join at some point... i know...
Using one of the answers from ROW_NUMBER() in MySQL for row counts, and then modifying to get the top.
SELECT ParticipantId, SUM(Points)
FROM
(
SELECT a.participantid, a.points, a.id, count(*) as row_number
FROM scores a
JOIN scores b ON a.participantid = b.participantid AND cast(concat(a.points,'.', a.id) as decimal) <= cast(concat(b.points,'.', b.id) as decimal)
GROUP BY a.participantid, a.points, a.id
) C
WHERE row_number IN (1,2)
GROUP BY ParticipantId
Had an issue with ties until I arbitrarily broke them with the id

How to create a simple crosstab query in MySQL

I have two tables containing fields as below.
Table 1
| SetID | InQty | Day |
| 1 | 10 | 1 |
| 2 | 10 | 2 |
| 3 | 10 | 3 |
Table 2
| SetID | OtQty | Day |
| 1 | 1 | 5 |
| 1 | 2 | 6 |
| 1 | 3 | 7 |
SetID in table 2 is linked with SetId in table 1. Day is placed in place of date, just for convenience only. Expected Output,
| Day | InQty | OtQty |
| 1 | 10 | |
| 5 | | 1 |
| 6 | | 2 |
| 7 | | 3 |
Blank Space can be filled with NULL or Zero.
It appears you are querying ONLY for set ID = 1 otherwise, I would expect to see in/out values for Set 2 and 3. You should be able to get with a simple UNION
select t1.Day, t1.InQty, 0 OutQty
from Table1 t1
where SetID = 1
order by t1.Day
union select t2.Day, 0, t2.OtQty
from Table2 t2
where SetID = 1
Now, if you want totals spanning different "setID"s and keeping them differentiated from each other, just add the setID as a column and also add to the group by clause as well.