Return a ranking from tables with MySQL - mysql

Here my table structure:
___Rooms:
|--------|------------|
| ROO_Id | ROO_Name |
|--------|------------|
| 1 | Room 1 |
| 2 | Room 2 |
| 3 | Room 3 |
|--------|------------|
___Bookings:
|--------|------------|
| BOO_Id | BOO_RoomId |
|--------|------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
|--------|------------|
___BillableDatas:
|--------|---------------|------------|------------|
| BIL_Id | BIL_BookingId | BIL_Date | BIL_Item |
|--------|---------------|------------|------------|
| 1 | 1 | 2017-02-21 | Night |
| 2 | 1 | 2017-02-22 | Night |
| 3 | 1 | 2017-02-23 | Night |
| 4 | 1 | 2017-02-24 | Night |
| 5 | 2 | 2017-02-30 | Night |
| 6 | 2 | 2017-02-31 | Night |
| 7 | 1 | 2017-02-31 | Night |
|--------|---------------|------------|------------|
I would like to know the most popular room.
The desired result should be:
|------------|------------|------------|
| ROO_Name | Night Nb | Percentage |
|------------|------------|------------|
| Room 1 | 5 | 71.42 |
| Room 2 | 2 | 28.57 |
| Room 3 | 0 | 0 |
|------------|------------|------------|
What I already tried:
SELECT r.ROO_Id
, Sum(CASE WHEN BOO_Id IS NULL THEN 0 ELSE 1 END) NumBookings
, Concat(
Format(
Sum(CASE WHEN BOO_Id IS NULL THEN 0 ELSE 1 END)
/ TotalBookings
* 100
, 0) ) AS PercentageTotal
FROM ( ___Rooms r LEFT JOIN ___Bookings b ON r.ROO_Id = b.BOO_RoomId
) INNER JOIN (SELECT BOO_HotelId
, Count(*) AS TotalBookings
FROM ___Bookings
GROUP BY BOO_HotelId
) AS TotalHotelBookings
ON r.ROO_HotelId = TotalHotelBookings.BOO_HotelId
WHERE r.ROO_HotelId = :hotel_id
GROUP BY r.ROO_Id
ORDER BY NumBookings DESC
But it doesn't work actually.
You could use the SQL Fiddle:
http://sqlfiddle.com/#!9/390b1

try this
select Roo_Name,coalesce(bookid,0) as nightdb,coalesce(bookid * 10/Boo_Id,0) as percentage
from ___Rooms r1
left join
(select count(BOO_RoomId) as book, BOO_Id
from ___Bookings group by BOO_Id) b1
on r1.Roo_Id = b1.Boo_id
left join
(select count(Bil_BookingId) as bookid,BIL_BookingId
from ___BillableDatas
group by BIL_BookingId) b2
on b2.BIL_BookingId = b1.BOO_Id group by r1.Roo_Name;
DEMO

Related

How to select values from the previous row based on two columns where the value columns can alternate

From the following game table of sports matches:
+-----+-----------+---------------+----------+-------+-------+---------+---------+
| id_ | date_time | tournament_id | round_id | p1_id | p2_id | p1_stat | p2_stat |
+-----+-----------+---------------+----------+-------+-------+---------+---------+
| 1 | NULL | 1 | 4 | 1 | 3 | 2 | 3 |
| 2 | NULL | 1 | 5 | 1 | 4 | 4 | 6 |
| 3 | NULL | 1 | 9 | 1 | 5 | 6 | 9 |
| 4 | NULL | 1 | 10 | 2 | 1 | 8 | 12 |
| 5 | NULL | 2 | 4 | 1 | 2 | 10 | 15 |
| 6 | NULL | 2 | 5 | 4 | 1 | 12 | 18 |
+-----+-----------+---------------+----------+-------+-------+---------+---------+
I'm trying to get the stats for each player for their previous match. The output should look like this:
+-----+--------------+--------------+
| id_ | prev_p1_stat | prev_p2_stat |
+-----+--------------+--------------+
| 1 | NULL | NULL |
| 2 | 2 | NULL |
| 3 | 4 | NULL |
| 4 | NULL | 6 |
| 5 | 12 | 8 |
| 6 | 6 | 10 |
+-----+--------------+--------------+
However, the date_time column is quite often blank and id_ is not date sequential. The tournament table does have a date_time column which is always populated:
+-----+------------+
| id_ | date_time |
+-----+------------+
| 1 | 1997-01-01 |
| 2 | 1997-01-06 |
+-----+------------+
This means the tournament date_time can be used in conjunction with game round_id to determine the previous match.
I've found the following answers here and here but they both focus on a single table and don't have the added complexity of having to determine whether the p1_stat or the p2_stat should be selected.
I've got as far as this query:
SELECT
g.id_ AS game_id,
CASE
WHEN g.p1_id = sq_p1.p1_id THEN sq_p1.p1_stat
ELSE sq_p1.p2_stat
END AS prev_p1_stat,
CASE
WHEN g.p1_id = sq_p2.p1_id THEN sq_p2.p1_stat
ELSE sq_p2.p2_stat
END AS prev_p2_stat
FROM
test.game AS g
JOIN
test.tournament AS t ON t.id_ = g.tournament_id
LEFT OUTER JOIN
(SELECT
g.id_ AS match_id,
t.date_time AS tournament_date,
g.round_id,
g.p1_id,
g.p2_id,
g.p1_stat,
g.p2_stat
FROM
test.game AS g
JOIN test.tournament AS t ON t.id_ = g.tournament_id) AS sq_p1 ON (sq_p1.p1_id = g.p1_id
OR sq_p1.p2_id = g.p1_id)
AND (sq_p1.tournament_date = t.date_time
AND sq_p1.round_id < g.round_id
OR sq_p1.tournament_date < t.date_time)
LEFT OUTER JOIN
(SELECT
g.id_ AS match_id,
t.date_time AS tournament_date,
g.round_id,
g.p1_id,
g.p2_id,
g.p1_stat,
g.p2_stat
FROM
test.game AS g
JOIN test.tournament AS t ON t.id_ = g.tournament_id) AS sq_p2 ON (sq_p2.p1_id = g.p1_id
OR sq_p2.p2_id = g.p1_id)
AND (sq_p2.tournament_date = t.date_time
AND sq_p2.round_id < g.round_id
OR sq_p2.tournament_date < t.date_time)
ORDER BY t.date_time , g.round_id
But this isn't even close to what I'm looking for :(
I've created a dbfiddle.
One other thing that's perhaps worth mentioning... I intend to use a couple of versions of this query in a union query such that the final result (including all columns for reference) will look like this:
+-----+------------+-----------+-------------+-------------+---------------+------------------+--------------------+
| id_ | player_num | player_id | opponent_id | player_stat | opponent_stat | player_prev_stat | opponent_prev_stat |
+-----+------------+-----------+-------------+-------------+---------------+------------------+--------------------+
| 1 | 1 | 1 | 3 | 2 | 3 | NULL | NULL |
| 1 | 2 | 3 | 1 | 3 | 2 | NULL | NULL |
| 2 | 1 | 1 | 4 | 4 | 6 | 2 | NULL |
| 2 | 2 | 4 | 1 | 6 | 4 | NULL | 2 |
| 3 | 1 | 1 | 5 | 6 | 9 | 4 | NULL |
| 3 | 2 | 5 | 1 | 9 | 6 | NULL | 4 |
| 4 | 1 | 2 | 1 | 8 | 12 | NULL | 6 |
| 4 | 2 | 1 | 2 | 12 | 8 | 6 | NULL |
| 5 | 1 | 1 | 2 | 10 | 15 | 12 | 8 |
| 5 | 2 | 2 | 1 | 15 | 10 | 8 | 12 |
| 6 | 1 | 4 | 1 | 12 | 18 | 6 | 10 |
| 6 | 2 | 1 | 4 | 18 | 12 | 10 | 6 |
+-----+------------+-----------+-------------+-------------+---------------+------------------+--------------------+
Perhaps it makes more sense to do a union and then engineer the previous stats?
For some final info, the actual game table has about 1.5m rows and the actual tournament table has about 30k rows. I'm using MySQL 8.0.26.
Kudos to #Barmer for the direction - here's the query I created using LAG():
WITH union_matches AS (
SELECT
g.id_ AS match_id,
t.date_time AS tournament_date,
g.round_id AS round_id,
1 AS player_num,
g.p1_id AS player_id,
g.p2_id AS opponent_id,
g.p1_stat AS player_stat,
g.p2_stat AS opponent_stat
FROM
game AS g
JOIN
tournament AS t ON t.id_ = g.tournament_id
UNION SELECT
g.id_ AS match_id,
t.date_time AS tournament_date,
g.round_id AS round_id,
2 AS player_num,
g.p2_id AS player_id,
g.p1_id AS opponent_id,
g.p2_stat AS player_stat,
g.p1_stat AS opponent_stat
FROM
game AS g
JOIN
tournament AS t ON t.id_ = g.tournament_id
)
SELECT
match_id,
player_num,
player_id,
opponent_id,
player_stat,
opponent_stat,
LAG(player_stat, 1) OVER (PARTITION BY player_id ORDER BY tournament_date, round_id) AS wrong_player_prev_stat,
LAG(opponent_stat, 1) OVER (PARTITION BY opponent_id ORDER BY tournament_date, round_id) AS wrong_opponent_prev_stat
FROM
union_matches
ORDER BY
tournament_date, round_id, player_num
And a link to the dbfiddle.

How to get data status wise after grouping?

I want to get count of different statuses for bookings for each event and some other data. Each row should represent an event.
So I have an events table and a bookings table.
Events table has id, name, max_allowed
Bookings table has id,event_id,status
Status can be booked, canceled, waitlisted.
I want to get data for all events with the count for each status.
So I need these columns -
event_id
booked_count
canceled_count
waitlisted_count
remaining_slots - (max_allowed - booked_count)
occupancy_rate - booked_count/max_allowed
Sample data:
Events
| id | name | max_allowed |
|---- |--------- |------------- |
| 1 | Yoga | 5 |
| 2 | Boxing | 2 |
| 3 | Pilates | 5 |
Bookings
| id | event_id | status |
|---- |---------- |------------ |
| 1 | 1 | booked |
| 2 | 1 | booked |
| 3 | 2 | booked |
| 4 | 2 | canceled |
| 5 | 2 | booked |
| 6 | 2 | waitlisted |
| 7 | 3 | booked |
| 8 | 3 | booked |
| 9 | 3 | booked |
Output:
| event_id | booked_count | canceled_count | waitlisted_count | remaining_slots | occupancy_rate |
|---------- |-------------- |---------------- |------------------ |----------------- |---------------- |
| 1 | 2 | 0 | 0 | 3 | 0.4 |
| 2 | 2 | 1 | 1 | 0 | 1 |
| 3 | 3 | 0 | 0 | 2 | 0.6 |
Use conditional aggregation:
select t.*,
greatest(0, t.max_allowed - t.booked_count + t.canceled_count - t.waitlisted_count) remaining_slots,
least(t.max_allowed, t.booked_count - t.canceled_count + t.waitlisted_count) / t.max_allowed occupancy_rate
from (
select e.id, e.name, e.max_allowed,
sum(status = 'booked') booked_count,
sum(status = 'canceled') canceled_count,
sum(status = 'waitlisted') waitlisted_count
from Events e left join Bookings b
on b.event_id = e.id
group by e.id, e.name, e.max_allowed
) t
Try below query.
with src_data as
(select
event_id,
sum(case when status='booked' then 1 else 0 end ) as booked_count,
sum(case when status='canceled' then 1 else 0 end ) as canceled_count,
sum(case when status='waitlisted' then 1 else 0 end ) as waitlisted_count
from bookings group by event_id
)
select
s.event_id,
s.booked_count,
s.canceled_count,
s.waitlisted_count,
e.max_allowed-s.booked_count,
s.booked_count/e.max_allowed
from events e inner join src_data s
on e.id=s.event_id;

SQL Query problem - difficult query with six tables

I need a help of a sql expert. I have a problem with my sql query. I have six MySQL tables:
pcs_persons (table of players)
+----+------------+------------+
| id | firstname | lastname |
+----+------------+------------+
| 1 | John | McClane |
| 2 | Jack | Marriott |
| 3 | Billy | Bravo |
| 4 | Archie | MacDonald |
+----+------------+------------+
pcs_matchs (table of match results)
+----+-------------------+-------------------+---------+------------+------------+
| id | id_candidate_dom | id_candidate_ext | id_day | id_season | id_compet |
+----+-------------------+-------------------+---------+------------+------------+
| 1 | 1 | 2 | 1 | 1 | 1 |
| 2 | 3 | 4 | 1 | 1 | 1 |
| 3 | 2 | 3 | 2 | 1 | 1 |
| 4 | 4 | 1 | 2 | 1 | 1 |
| 5 | 1 | 7 | 1 | 2 | 3 |
| 6 | 6 | 3 | 2 | 2 | 5 |
+----+-------------------+-------------------+---------+------------+------------+
pcs_lineup (table of those players who were selected to the match squad as starter - type 2, or as substitute - type 3)
+----+-----------+----------+------------+-------+
| id | id_match | id_club | id_person | type |
+----+-----------+----------+------------+-------+
| 1 | 1 | 1 | 1 | 2 |
| 2 | 1 | 1 | 2 | 3 |
| 3 | 1 | 2 | 3 | 2 |
| 4 | 1 | 2 | 4 | 3 |
+----+-----------+----------+------------+-------+
pcs_goals (table of scored goals by players)
| id | id_match | id_person | id_club | goal_min |
+----+-----------+------------+----------+-----------+
| 1 | 1 | 1 | 1 | 23 |
| 2 | 1 | 1 | 1 | 48 |
| 3 | 1 | 3 | 2 | 56 |
| 4 | 1 | 4 | 2 | 89 |
+----+-----------+------------+----------+-----------+
pcs_cards (table of received cards by players)
| id | id_match | id_person | id_club | card_min | card_yellow | card_red |
+----+-----------+------------+----------+-----------+--------------+-----------+
| 1 | 1 | 1 | 1 | 12 | 1 | |
| 2 | 1 | 1 | 1 | 43 | 1 | |
| 3 | 1 | 3 | 2 | 78 | | 1 |
| 4 | 1 | 4 | 2 | 91 | 1 | |
+----+-----------+------------+----------+-----------+--------------+-----------+
pcs_subs (table of substitutions)
| id | id_match | id_club | id_person_in | id_person_out | subs_min |
+----+-----------+----------+---------------+----------------+-----------+
| 1 | 1 | 1 | 7 | 1 | 82 |
| 2 | 1 | 1 | 8 | 2 | 85 |
| 3 | 1 | 2 | 5 | 3 | 89 |
| 4 | 1 | 2 | 6 | 4 | 91 |
+----+-----------+----------+---------------+----------------+-----------+
My current query is here:
SELECT pcs_lineup.id_person, pcs_lineup.id_club, pcs_lineup.type,
pcs_persons.lastname, pcs_persons.firstname, count( pcs_lineup.id_person) AS apps, count(pcs_subs.id_person_in) AS subs
FROM pcs_lineup
JOIN pcs_matchs ON pcs_matchs.id = pcs_lineup.id_match
JOIN pcs_persons ON pcs_persons.id = pcs_lineup.id_person
LEFT JOIN pcs_subs ON pcs_subs.id_person_in = pcs_lineup.id_person
WHERE pcs_lineup.id_club =2
AND pcs_matchs.id_compet =1
AND pcs_matchs.id_season =1
AND pcs_lineup.type = 2 OR pcs_subs.id_person_in IS NOT NULL AND pcs_subs.id_club =2
GROUP BY id_person
My current result structure (list of players who played as member of starting lineup or played as substitutes, players who just sat on the bench not counted)
+-----------+----------+-------+-----------+------------+-------+-------+
| id_person | id_club | type | lastname | firstname | apps | subs |
+-----------+----------+-------+-----------+------------+-------+-------+
I would like to add extra columns (goals, yellow cards, red cards) to the result, but I don't know how.
The structure of desired result:
+-----------+----------+-------+-----------+------------+-------+----------+-------+--------+---------------+------------+
| id_person | id_club | type | lastname | firstname | apps | starter | subs | goals | yellow cards | red_cards |
+-----------+----------+-------+-----------+------------+-------+----------+-------+--------+---------------+------------+
I hope that some expert could help for me, because I have no idea how could I join these tables for the desired result. Many thanks!
Modified code (results are not good)
SELECT pcs_lineup.id_person
,pcs_lineup.id_club
,pcs_lineup.type
,pcs_persons.lastname
,pcs_persons.firstname
,count( pcs_lineup.id_person) AS apps
,CASE WHEN pcs_lineup.type = 2 THEN 'YES' END starter
,count(pcs_subs.id_person_in) AS subs
,count(pcs_goals.goal_min) AS goals
,count(card_yellow) as "Yellow Cards"
,count(card_red) as "Red Card"
FROM pcs_lineup
JOIN pcs_matchs ON pcs_matchs.id = pcs_lineup.id_match
JOIN pcs_persons ON pcs_persons.id = pcs_lineup.id_person
LEFT JOIN pcs_subs ON pcs_subs.id_person_in = pcs_lineup.id_person
LEFT JOIN pcs_goals ON pcs_goals.id_match = pcs_matchs.id
AND pcs_persons.id = pcs_goals.id_person
LEFT JOIN pcs_cards ON pcs_cards.id_match = pcs_matchs.id
AND pcs_cards.id_person = pcs_persons.id
AND pcs_goals.id_club = pcs_cards.id_club
WHERE pcs_lineup.id_club =2
AND pcs_matchs.id_compet =1
AND pcs_matchs.id_season =1
AND pcs_subs.id_person_in IS NOT NULL AND pcs_subs.id_club =2
GROUP BY id_person
You need to join 2 more tables i.e. pcs_goals and pcs_cards -
SELECT pcs_lineup.id_person
,pcs_lineup.id_club
,pcs_lineup.type
,pcs_persons.lastname
,pcs_persons.firstname
,count( pcs_lineup.id_person) AS apps
,CASE WHEN pcs_lineup.type = 2 THEN 'YES' END starter
,count(pcs_subs.id_person_in) AS subs
,count(pcs_goals.goals_min) AS goals
,count(card_yellow) as "Yellow Cards"
,count(card_red) as "Red Card"
FROM pcs_lineup
JOIN pcs_matchs ON pcs_matchs.id = pcs_lineup.id_match
JOIN pcs_persons ON pcs_persons.id = pcs_lineup.id_person
LEFT JOIN pcs_subs ON pcs_subs.id_person_in = pcs_lineup.id_person
LEFT JOIN pcs_goals ON pcs_goals.id_match = pcs_matchs.id
AND pcs_persons.id = pcs_matchs.id_person
LEFT JOIN pcs_cards ON pcs_cards.id_match = pcs_matchs.id
AND pcs_cards.id_person = pcs_persons.id
AND pcs_goals.id_club = pcs_cards.id_club
WHERE pcs_lineup.id_club =2
AND pcs_matchs.id_compet =1
AND pcs_matchs.id_season =1
AND pcs_subs.id_person_in IS NOT NULL AND pcs_subs.id_club =2
GROUP BY id_person
I am not sure what do you mean by starter column.
pcs_subs.id_person_in change to id_person_out

How to fill missing rows on one table (A) from another table (B) with MySQL?

I am setting up a virtual classroom in PHP and MySQL. This classroom consists of courses and each course contains different subjects or modules. The student has to examine each module and, finally, a summary (evaluation board) is made to know if the student has passed the course or not.
Having said that, I have a table in which I store the evaluations of each student, in which I keep inscripcion_id (student - inscription_id), modulo_id (module_id), fecha (date_of_examination), aciertos (number_of_right_answers), ultima_convocatoria (evaluation_last_convocatory) and estado (status).
SQL Fiddle -> here
Through some previously established rules that tell me if a student has passed a module or not, I get the following set of data:
+----------------+-----------+---------------------+----------+---------------------+--------+------------+
| inscripcion_id | modulo_id | fecha | aciertos | ultima_convocatoria | estado | ev |
+----------------+-----------+---------------------+----------+---------------------+--------+------------+
| 890 | 1 | 2018-01-24 22:26:09 | 8 | 2 | 1 | aprobado |
| 890 | 2 | 2018-01-24 22:36:58 | 3 | 3 | 0 | suspendido |
| 890 | 5 | 2018-01-24 22:38:50 | 3 | 1 | 0 | suspendido |
| 890 | 6 | 2018-01-24 22:44:20 | 7 | 3 | 0 | suspendido |
| 891 | 1 | 2018-01-25 09:24:42 | 8 | 1 | 1 | aprobado |
| 891 | 2 | 2018-01-25 10:01:55 | 4 | 8 | 0 | suspendido |
| 891 | 4 | 2018-01-25 10:51:49 | 5 | 3 | 1 | suspendido |
| 891 | 5 | 2018-01-25 10:23:45 | 9 | 1 | 1 | aprobado |
| 891 | 6 | 2018-01-25 11:21:20 | 7 | 3 | 0 | suspendido |
| 896 | 1 | 2018-01-25 11:55:48 | 1 | 1 | 1 | suspendido |
| 898 | 1 | 2018-01-25 14:01:51 | 6 | 1 | 1 | suspendido |
| 907 | 1 | 2018-03-25 16:06:18 | 3 | 1 | 0 | suspendido |
| 907 | 2 | 2018-03-25 16:07:34 | 3 | 1 | 0 | suspendido |
| 907 | 3 | 2018-03-25 16:09:04 | 3 | 1 | 0 | suspendido |
| 907 | 4 | 2018-03-25 16:08:13 | 3 | 1 | 0 | suspendido |
| 907 | 5 | 2018-03-25 16:10:37 | 2 | 1 | 0 | suspendido |
| 907 | 6 | 2018-03-25 16:08:44 | 3 | 1 | 0 | suspendido |
+----------------+-----------+---------------------+----------+---------------------+--------+------------+
This data is obtained through the following query:
SELECT e1.inscripcion_id,
e1.modulo_id,
e1.fecha,
e1.aciertos,
e1.convocatoria AS ultima_convocatoria,
e1.estado,
if (
( e1.modulo_id in (SELECT modulo.modulo_id FROM modulo WHERE modulo.curso_id = 1 AND modulo.categoria_id = 1)
AND e1.aciertos <= 7 )
OR ( e1.modulo_id = (SELECT modulo.modulo_id FROM modulo WHERE modulo.curso_id = 1 AND modulo.categoria_id = 2)
AND e1.aciertos <= 11 ),
"suspendido",
"aprobado"
) AS ev
FROM (
SELECT inscripcion_id,
modulo_id,
MAX(convocatoria) AS max_convocatoria
FROM `evaluacion`
GROUP BY inscripcion_id,
modulo_id
ORDER BY `inscripcion_id` ASC,
`modulo_id` ASC,
`convocatoria` ASC
) AS e2
INNER JOIN evaluacion AS e1
ON e1.inscripcion_id = e2.inscripcion_id
AND e1.modulo_id = e2.modulo_id
AND e1.convocatoria = e2.max_convocatoria
As you can see, the student 890, has made modules 1, 2, 5 and 6. What I want to achieve is that the modules that are still pending, I also get as a result in the previous data set. The exemplification:
+----------------+-----------+---------------------+----------+---------------------+--------+------------+
| inscripcion_id | modulo_id | fecha | aciertos | ultima_convocatoria | estado | ev |
+----------------+-----------+---------------------+----------+---------------------+--------+------------+
| 890 | 1 | 2018-01-24 22:26:09 | 8 | 2 | 1 | aprobado |
| 890 | 2 | 2018-01-24 22:36:58 | 3 | 3 | 0 | suspendido |
| 890 | 3 | NULL | NULL | NULL | NULL | pendiente |
| 890 | 4 | NULL | NULL | NULL | NULL | pendiente |
| 890 | 5 | 2018-01-24 22:38:50 | 3 | 1 | 0 | suspendido |
| 890 | 6 | 2018-01-24 22:44:20 | 7 | 3 | 0 | suspendido |
| 891 | 1 | 2018-01-25 09:24:42 | 8 | 1 | 1 | aprobado |
| 891 | 2 | 2018-01-25 10:01:55 | 4 | 8 | 0 | suspendido |
| 891 | 3 | NULL | NULL | NULL | NULL | pendiente |
| 891 | 4 | 2018-01-25 10:51:49 | 5 | 3 | 1 | suspendido |
| 891 | 5 | 2018-01-25 10:23:45 | 9 | 1 | 1 | aprobado |
| 891 | 6 | 2018-01-25 11:21:20 | 7 | 3 | 0 | suspendido |
| 896 | 1 | 2018-01-25 11:55:48 | 1 | 1 | 1 | suspendido |
| 896 | 2 | NULL | NULL | NULL | NULL | pendiente |
| 896 | 3 | NULL | NULL | NULL | NULL | pendiente |
| 896 | 4 | NULL | NULL | NULL | NULL | pendiente |
| 896 | 5 | NULL | NULL | NULL | NULL | pendiente |
| 896 | 6 | NULL | NULL | NULL | NULL | pendiente |
| ... | | | | | | |
+----------------+-----------+---------------------+----------+---------------------+--------+------------+
The result is that the modules that the student has not yet done have been added, with the new value "pending" for the ev column.
I have no idea how to do this ... I've tried, I searched the internet and nothing :(
What is the final objective? What I want is to obtain a final list with all those students who have the pending course (that is, they have some pending module/s), to send them a reminder email that they have to examine themselves of the remaining modules. To those who have approved or suspended, no email will be sent to them.
Can you help me?
SQL Fiddle -> here
THANK YOU VERY MUCH
Suppose you want to get students with no module in evaluation table as 'pending' like what you provided in the example. The way to get student joining all module is to do a full join on modulo and evaluacion to get full set of distinct inscripcion_id modulo_id. Then left join with your existing query will provide the result you want.
sqlfiddle
SELECT fs.inscripcion_id,
fs.modulo_id,
e3.fecha,
e3.aciertos,
e3.ultima_convocatoria,
e3.estado,
IF(e3.ev IS NULL, "pendiente", e3.ev) AS ev
FROM (SELECT m.modulo_id,
e.inscripcion_id
FROM modulo m,
evaluacion e
GROUP BY m.modulo_id,
e.inscripcion_id) AS fs
LEFT JOIN (SELECT
e1.inscripcion_id,
e1.modulo_id,
e1.fecha,
e1.aciertos,
e1.convocatoria
AS
ultima_convocatoria
,
e1.estado,
IF (( e1.modulo_id IN (SELECT modulo.modulo_id
FROM modulo
WHERE modulo.curso_id = 1
AND modulo.categoria_id =
1)
AND e1.aciertos <= 7 )
OR ( e1.modulo_id = (SELECT modulo.modulo_id
FROM modulo
WHERE
modulo.curso_id = 1
AND modulo.categoria_id = 2)
AND e1.aciertos <= 11 ), "suspendido",
"aprobado")
AS ev
FROM (SELECT inscripcion_id,
modulo_id,
Max(convocatoria) AS max_convocatoria
FROM `evaluacion`
GROUP BY inscripcion_id,
modulo_id
ORDER BY `inscripcion_id` ASC,
`modulo_id` ASC,
`convocatoria` ASC) AS e2
INNER JOIN evaluacion AS e1
ON e1.inscripcion_id = e2.inscripcion_id
AND e1.modulo_id = e2.modulo_id
AND e1.convocatoria = e2.max_convocatoria)
AS e3
ON fs.modulo_id = e3.modulo_id
AND fs.inscripcion_id = e3.inscripcion_id
ORDER BY fs.inscripcion_id,
fs.modulo_id;
For the further question,
You may want to use
SELECT inscripcion_id,
SUM(case when ev = 'aprobado' then 1 else 0 end) as approved_cnt,
SUM(case when ev = 'suspendido' then 1 else 0 end) as suspended_cnt,
SUM(case when ev = 'pendiente' then 1 else 0 end) as pending_cnt
From --the above query...
Group by inscripcion_id
to get the count of status for each student, and then do the logic using those count.
After reviewing the new sqlfiddle
I wrote the query below, I think it should cover what you want
Notice that you more than one evaluation per module, meaning that you'll get more than one status per module
To solve that, you can add a group statement (in comment now)
Or you the different evaluations to your needs...
SELECT
i.inscripcion_id,
c.curso_id,
c.titulo AS curso_titulo,
m.modulo_id,
m.titulo AS modulo_titulo,
IFNULL(ev.estado,0) AS estado,
m.*
FROM
inscripcion i
INNER JOIN curso c ON c.curso_id = i.curso_id
INNER JOIN modulo m ON m.curso_id = c.curso_id
LEFT JOIN evaluacion ev ON ev.modulo_id = m.modulo_id
WHERE
(ev.estado = 0 OR ev.estado IS NULL)
/*
GROUP BY
m.modulo_id
*/
;

Count element between 3 tables with mySQL

I've got these 3 tables:
___Kardex
|--------|---------|-------------|
| KDX_Id | KDX_VIP | KDX_Regular |
|--------|---------|-------------|
| 1 | No | No |
| 2 | No | No |
|--------|---------|-------------|
___BillableDatas
|--------|---------------|
| BIL_Id | BIL_BookingId |
|--------|---------------|
| 1 | 99 |
| 2 | 99 |
| 3 | 100 |
|--------|---------------|
___Bookings
|--------|--------------|
| BOO_Id | BOO_ClientId |
|--------|--------------|
| 99 | 1 |
| 100 | 2 |
|--------|--------------|
I want to loop into ___Kardex and count for each client:
- The number of bookings the client booked (containing in ___Bookings).
- The number of nights the client spent (containing in ___BillableDatas).
So I tried:
SELECT
KDX_Id,
(
SELECT COUNT(BOO_Id)
FROM ___Bookings
WHERE ___Kardex.KDX_Id = ___Bookings.BOO_ClientId
) AS nb_bookings,
(
SELECT COUNT(BIL_Id)
FROM ___BillableDatas
WHERE ___Kardex.KDX_Id = ___Bookings.BOO_ClientId
AND ___Bookings.BOO_Id = ___BillableDatas.BIL_BookingId
) AS nb_bookings
FROM ___Kardex
But I get empty datas.
Could you please help ?
Here the SQLFiddle: http://sqlfiddle.com/#!9/cf1832
The expected result is:
|--------|-------------|-----------|
| KDX_Id | nb_bookings | nb_nights |
|--------|-------------|-----------|
| 1 | 1 | 2 |
| 2 | 1 | 1 |
|--------|-------------|-----------|
Thanks.
Here you go :
SELECT
KDX_Id,
(
SELECT COUNT(BOO_Id)
FROM ___Bookings
WHERE KDX_Id = ___Bookings.BOO_ClientId
) AS nb_bookings,
(
SELECT COUNT(BIL_Id)
FROM ___Bookings, ___BillableDatas
WHERE ___Bookings.BOO_Id = ___BillableDatas.BIL_BookingId
AND KDX_Id = ___Bookings.BOO_ClientId
) AS nb_nights
FROM ___Kardex