SQL Select rows with max value from joined table - mysql

I have these 3 tables like that:
lecturers:
+-------------+---------+
| id-lecturer | name |
+-------------+---------+
| 1 | Johnson |
| 2 | Smith |
| ... | ... |
| ... | ... |
+-------------+---------+
subjects:
+------------+---------+
| id-subject | name |
+------------+---------+
| 1 | Math |
| 2 | Physics |
| ... | ... |
| ... | ... |
+------------+---------+
exams:
+---------+-------------+------------+------------+
| id-exam | id-lecturer | id-subject | date |
+---------+-------------+------------+------------+
| 1 | 5 | 1 | 1990-05-05 |
| 2 | 7 | 1 | ... |
| 3 | 5 | 3 | ... |
| ... | ... | ... | ... |
+---------+-------------+------------+------------+
When i try to do the first SELECT:
SELECT e.`id-lecturer`, e.`id-subject`, COUNT(e.`id-lecturer`) AS `exams-num`
FROM exams e
JOIN subjects s ON e.`id-subject`=s.`id-subject`
JOIN lecturers l ON e.`id-lecturer`=l.`id-lecturer`
GROUP BY e.`id-lecturer`, e.`id-subject`
I get the right answer. It shows something like that:
+-------------+------------+-----------+
| id-lecturer | id-subject | exams-num |
+-------------+------------+-----------+
| 0001 | 1 | 4 |
| 0001 | 3 | 1 |
| 0001 | 4 | 1 |
| 0001 | 5 | 1 |
| 0002 | 1 | 2 |
| 0002 | 2 | 1 |
| 0002 | 4 | 1 |
| 0002 | 6 | 3 |
+-------------+------------+-----------+
Now i want to show only the max number for every lecturer, my code is:
SELECT it.`id-lecturer`, it.`id-subject`, MAX(it.`exams-num`) AS `exams-number`
FROM (
SELECT e.`id-lecturer`, e.`id-subject`, COUNT(e.`id-lecturer`) AS `exams-num`
FROM egzaminy e
JOIN subjects s ON e.`id-subject`=s.`id-subject`
JOIN lecturers l ON e.`id-lecturer`=l.`id-lecturer`
GROUP BY e.`id-lecturer`, e.`id-subject`) it
GROUP BY it.`id-lecturer`
output:
+-------------+------------+--------------+
| id-lecturer | id-subject | exams-number |
+-------------+------------+--------------+
| 0001 | 1 | 4 |
| 0002 | 1 | 3 |
| 0003 | 1 | 2 |
| 0004 | 1 | 5 |
| 0005 | 2 | 1 |
+-------------+------------+--------------+
I get the correct numbers of the max values for each lecturer, but the subjects id doesn't match, it always takes the first row's id. How can I make it to match correctly these two fields in every row?

I guess you can simply use the same query for further conditions like below.
Select t.Lecturer_id,max(t.exams-num) from
(SELECT e.id-lecturer as Lecturer_id, e.id-subject as Subject_id,
COUNT(e.id-lecturer) AS exams-num
FROM exams e
JOIN subjects s ON e.id-subject=s.id-subject
JOIN lecturers l ON e.id-lecturer=l.id-lecturer
GROUP BY e.id-lecturer, e.id-subject ) as t
group by t.Lecturer_id

Related

Mysql 2 select staments with value from statement 1 used in statement 2

How to join these to in one sql statement?
I have these 2 simple tables.
3_Referee_Matches
+------------------------------------+
| ID | CountryCode | RefereeUrlCode |
| 1 | eng | mike-jean |
| 2 | eng | mike-jean |
| 3 | eng | mike-jean |
| 4 | eng | mike-jean |
| 5 | spa | hulo-pape |
| 6 | ita | enri-tolsi |
| 7 | ita | enra-ean |
| 8 | ita | enra-ean |
+------------------------------------+
3_Players
+----------------------------------------------------+
| ID | MatchID | Name | PlayerUrlCode | Yellow |
| 1 | 1 | Mike Bell | mike-bell | 1 |
| 2 | 2 | Mike Bell | mike-bell | 1 |
| 3 | 3 | Thoms Tim | thoms-tim | 1 |
| 4 | 4 | Jean Claod | jean-claod | 0 |
| 5 | 33 | Thoms Tim | thoms-tim | 1 |
| 6 | 44 | Fis Most | fis-most | 0 |
| 7 | 54 | Geni Toens | geni-toens | 1 |
| 8 | 67 | Geni Toens | geni-toens | 1 |
+----------------------------------------------------+
Today i use these 2 select. But need help to combine them into one.
select 1:
SELECT rm.*, p.PlayerUrlCode AS VALUEtoBEusedAGAIN, COUNT(p.ID) AS YellowCounter
FROM 3_Referee_Matches rm
JOIN 3_Players p ON rm.ID = p.MatchID
WHERE rm.CountryCode = 'eng' AND rm.RefereeUrlCode = 'mike-jean'
AND p.Yellow>0
GROUP BY p.Name
select 2:
SELECT COUNT(rm.ID) AS Counter
FROM 3_Referee_Matches rm
JOIN 3_Players p ON rm.ID = p.MatchID
WHERE rm.RefereeUrlCode='mike-jean'
AND p.PlayerUrlCode='VALUEtoBEusedAGAIN'
Result should be like this:
+--------------------------------------+
| Name | YellowCounter | Counter |
| Mike Bell | 2 | 2 |
| Jean Claod | 1 | 1 |
+--------------------------------------+
Showing that Mike Bell Got 2 yellow cards in 2 matches.
Your first query is nearly there. First, remove the extraneous columns from the select clause. count the number of "players" (really player information for each match) and sum their yellow cards.
select
p.name,
sum(yellow) as YellowCounter,
count(p.id) as Counter
from 3_Referee_Matches rm
join 3_Players p on rm.ID = p.MatchID
where rm.CountryCode = 'eng'
and rm.RefereeUrlCode = 'mike-jean'
group by p.name;
+------------+---------------+---------+
| name | YellowCounter | Counter |
+------------+---------------+---------+
| Mike Bell | 2 | 2 |
| Thoms Tim | 1 | 1 |
| Jean Claod | 0 | 1 |
+------------+---------------+---------+
I assume the example has Thoms and Jean reversed.

MySQL list all records in left table with Join

I have two tables, one includes vehicle data & other includes fuel data as follows:
tbl_vehicle
+------------+--------+
| vehicle_id | reg_no |
+------------+--------+
| 1 | ABC |
| 2 | DEF |
| 3 | GHI |
| 4 | JKA |
| 5 | LMN |
| 6 | OPQ |
+------------+--------+
tbl_direct_fuel
+---------+------------+----------+------------+
| fuel_id | vehicle_id | fuel_qty | date |
+---------+------------+----------+------------+
| 100 | 1 | 10 | 2019-10-01 |
| 101 | 1 | 12 | 2019-10-02 |
| 102 | 2 | 20 | 2019-10-03 |
| 103 | 3 | 15 | 2019-10-03 |
| 104 | 2 | 25 | 2019-10-04 |
+---------+------------+----------+------------+
I tried to get all records of left table with relevant records of right table. Used following Query.
select("reg_no,sum(fuel_qty) as total")
->from('tbl_direct_fuel')
->join('tbl_vehicle', 'tbl_direct_fuel.vehicle=tbl_vehicle.vehicle_id', 'left')
->group_by ('reg_no')
The above code shows only the following output.
+--------+----------+
| reg_no | total |
+--------+----------+
| ABC | 22 |
| DEF | 45 |
| GHI | 15 |
+--------+----------+
But I need all the vehicles with un-fueled vehicles as follows.
Desired output
+--------+----------+
| reg_no | total |
+--------+----------+
| ABC | 22 |
| DEF | 45 |
| GHI | 15 |
| JKA | 0 |
| LMN | 0 |
| OPQ | 0 |
+--------+----------+
You would to invert the tables in the left join, so that vehicules with no fueling do appear in the resultset (as it is, your left join allows for fueling without vehicules, which does not look like a relevant use case).
I would also recommend prefixing the column names with the table they come from to avoid ambiguity.
Finally, to return 0 (instead of null) for the vehicules that had no fueling, you can use coalesce().
select("tbl_vehicle.reg_no, coalesce(sum(fuel_qty), 0) fuel_qty")
->from('tbl_vehicle')
->join('tbl_direct_fuel', 'tbl_direct_fuel.vehicle = tbl_vehicle.vehicle_id', 'left')
->group_by ('tbl_vehicle.vehicle_id')
Try:
select t1.reg_no, t2.fuel_total
from tbl_vehicle t1
left join (
select vehicle_id, sum(fuel_qty) fuel_total
from tbl_direct_fuel
group by vehicle_id
) t2 on t1.vehicle_id = t2.vehicle_id

How to get count of combinations from database?

How to get count of combinations from database?
I have to database tables and want to get the count of combinations. Does anybody know how to put this in a database query, therefore I haven't a db request for each trip?
Trips
| ID | Driver | Date |
|----|--------|------------|
| 1 | A | 2015-12-15 |
| 2 | A | 2015-12-16 |
| 3 | B | 2015-12-17 |
| 4 | A | 2015-12-18 |
| 5 | A | 2015-12-19 |
Passengers
| ID | PassengerID | TripID |
|----|-------------|--------|
| 1 | B | 1 |
| 2 | C | 1 |
| 3 | D | 1 |
| 4 | B | 2 |
| 5 | D | 2 |
| 6 | A | 3 |
| 7 | B | 4 |
| 8 | D | 4 |
| 9 | B | 5 |
| 10 | C | 5 |
Expected result
| Driver | B-C-D | B-D | A | B-C |
|--------|-------|-----|---|-----|
| A | 1 | 2 | - | 1 |
| B | - | - | 1 | - |
Alternative
| Driver | Passengers | Count |
|--------|------------|-------|
| A | B-C-D | 1 |
| A | B-D | 2 |
| A | B-C | 1 |
| B | A | 1 |
Has anybody an idea?
Thanks a lot!
Try this:
SELECT Driver, Passengers, COUNT(*) AS `Count`
FROM (
SELECT t.ID, t.Driver,
GROUP_CONCAT(p.PassengerID
ORDER BY p.PassengerID
SEPARATOR '-') AS Passengers
FROM Trips AS t
INNER JOIN Passengers AS p ON t.ID = p.TripID
GROUP BY t.ID, t.Driver) AS t
GROUP BY Driver, Passengers
The above query will produce the alternative result set. The other result set can only be achieved using dynamic sql.
Demo here

MySQL get value using data from three tables

I need to get one value from one table using information from other two.
Here is the structure:
USERS TABLE
+-----------+---------+------------+
| ID | NAME | ZIP |
+-----------+---------+------------+
| 1 | John | 1111-222 |
| 2 | Maria | 2222-555 |
| 3 | José | 3333-505 |
+-----------+---------+------------+
ZIP-MATCH TABLE
+-----------+---------+------------+------------+
| DD | CC | PART1 | PART2 |
+-----------+---------+------------+------------+
| 1 | 1 | 1111 | 101 |
| 1 | 1 | 1111 | 111 |
| 1 | 2 | 1111 | 222 |
| 1 | 3 | 2222 | 333 |
| 2 | 1 | 2222 | 100 |
| 2 | 1 | 2222 | 555 |
| 2 | 2 | 2244 | 222 |
| 2 | 2 | 2244 | 333 |
| 2 | 3 | 2245 | 311 |
| 3 | 1 | 3333 | 111 |
| 3 | 2 | 3333 | 222 |
| 3 | 3 | 3333 | 505 |
+-----------+---------+------------+------------+
AREAS NAME TABLE
+-----------+---------+------------+
| DD | CC | AREA |
+-----------+---------+------------+
| 1 | 1 | Lisboa |
| 1 | 2 | Porto |
| 1 | 3 | Aveiro |
| 2 | 1 | Braga |
| 2 | 2 | Fundão |
| 2 | 3 | Bogas |
| 3 | 1 | Faro |
| 3 | 2 | Leiria |
| 3 | 3 | Covilhã |
+-----------+---------+------------+
What I need to do is a query to get all users from the first table, with all the users data (ID, NAME, ZIP) plus the AREA name.
For this example it would be:
1, John, 1111-222, Porto
2, Maria, 2222-555, Braga
3, José, 3333-505, Covilhã
Thanks in advance,
Miguel.
This is the answer:
SELECT
a.id,
a.name,
a.zip,
c.area
FROM
users a
LEFT JOIN
zip_match b
ON a.zip = concat(b.part1,'-',b.part2)
LEFT JOIN
areas_name c
ON b.dd = c.dd
and b.cc = c.cc;
Assuming your tables were called users, zip_match and areas_name respectively. Not sure of the data types of part1 and part2, they might need to be converted into strings to work in the concat function.
select users.id, users.name, users.zip, areas.area from users u, zipmatch z, areas a
where u.zip = z.part1 + '-' + z.part2
and a.dd = z.dd and a.cc = z.cc
perhaps?

Is there a way in SQL (MySQL) to do a "round robin" ORDER BY on a particular field?

Is there a way in SQL (MySQL) to do a "round robin" ORDER BY on a particular field?
As an example, I would like to take a table such as this one:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 1 | B |
| 1 | C |
| 2 | D |
| 2 | E |
| 2 | F |
| 3 | G |
| 3 | H |
| 3 | I |
+-------+------+
And run a query that produces results in this order:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 2 | D |
| 3 | G |
| 1 | B |
| 2 | E |
| 3 | H |
| 1 | C |
| 2 | F |
| 3 | I |
+-------+------+
Note that the table may have many rows, so I can't do the ordering in the application. (I'd obviously have a LIMIT clause as well in the query).
I'd try something like:
SET #counter = 0;
SELECT (#counter:=#counter+1)%3 as rr, grp, name FROM table ORDER by rr, grp
What you can do is create a temporary column in which you create sets to give you something like this:
+-------+------+-----+
| group | name | tmp |
+-------+------+-----+
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | C | 3 |
| 2 | D | 1 |
| 2 | E | 2 |
| 2 | F | 3 |
| 3 | G | 1 |
| 3 | H | 2 |
| 3 | I | 3 |
+-------+------+-----+
To learn how to create the sets, have a look at this question/answer.
Then its a simple
ORDER BY tmp, group, name
You can use MySQL variables to do this.
SELECT grp, name, #row:=#row+1 from table, (SELECT #row:=0) r ORDER BY (#row % 3);
+------+------+--------------+
| grp | name | #row:=#row+1 |
+------+------+--------------+
| 1 | A | 1 |
| 2 | D | 4 |
| 3 | G | 7 |
| 1 | B | 2 |
| 2 | E | 5 |
| 3 | H | 8 |
| 1 | C | 3 |
| 2 | F | 6 |
| 3 | I | 9 |
+------+------+--------------+