mysql sub query for find grade - mysql

I have tabel like this
+----+-------+------------+-------+
| No | NIK | Nama | Nilai |
+----+-------+------------+-------+
| 1 | 06001 | Syafruddin | 70 |
| 2 | 20000 | Maman | 90 |
| 3 | 30000 | Linda | 40 |
| 4 | 40000 | Tesa | 71 |
+----+-------+------------+-------+
+-------------+-------+------------------+
| Range_Nilai | Point | Keterangan |
+-------------+-------+------------------+
| 0 s/d 50 | E | Tidak Lulus |
| 51 s/d 80 | C | Cukup |
| 81 s/d 100 | A | Sangat Memuaskan |
+-------------+-------+------------------+
and I want to get my results like this
but my results like this
when I try to change my query like this
THEN (SELECT b.Point,b.Keterangan FROM range_nilai b where b.Range_Nilai='0 s/d 50')
I got error 'Operand should contain 1 column(s)'
can someone help me pls?
this my fiddle
SELECT a.*,
( CASE
WHEN a.nilai >=0 && a.Nilai<=50
THEN (SELECT Point FROM range_nilai where Range_Nilai='0 s/d 50')
WHEN a.nilai >50 && a.Nilai<=80
THEN (SELECT Point FROM range_nilai where Range_Nilai='51 s/d 80')
WHEN a.nilai >80 && a.Nilai<=100
THEN (SELECT Point FROM range_nilai where Range_Nilai='81 s/d 100')
ELSE NULL
END
) as Point,
( CASE
WHEN a.nilai >=0 && a.Nilai<=50
THEN (SELECT Keterangan FROM range_nilai where Range_Nilai='0 s/d 50')
WHEN a.nilai >50 && a.Nilai<=80
THEN (SELECT Keterangan FROM range_nilai where Range_Nilai='51 s/d 80')
WHEN a.nilai >80 && a.Nilai<=100
THEN (SELECT Keterangan FROM range_nilai where Range_Nilai='81 s/d 100')
ELSE NULL
END
) as Keterangan
FROM nilai a
this my last query I have.
may someone have more better query than me?

You can join the tables and use the function SUBSTRING_INDEX() in the ON clause:
select n.*, r.Point, r.Keterangan
from nilai n inner join range_nilai r
on n.Nilai
between
substring_index(r.Range_Nilai, ' s/d ', 1)
and
substring_index(r.Range_Nilai, ' s/d ', -1)
See the demo.
Results:
| No | NIK | Nama | Nilai | Point | Keterangan |
| --- | ----- | ---------- | ----- | ----- | ---------------- |
| 1 | 6001 | Syafruddin | 70 | C | Cukup |
| 2 | 20000 | Maman | 90 | A | Sangat Memuaskan |
| 3 | 30000 | Linda | 40 | E | Tidak Lulus |
| 4 | 40000 | Tesa | 71 | C | Cukup |

Related

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
*/
;

Return only the higher ID from a MySQL query

I have 2 tables:
___Rooms
|--------|------------|
| ROO_Id | ROO_Number |
|--------|------------|
| 22 | 101 |
| 23 | 102 |
| 24 | 201 |
|--------|------------|
___Bookings
|--------|------------|------------|------------|-------------------|
| BOO_Id | BOO_RoomId | BOO_DateCI | BOO_DateCO | BOO_ArrivalStatus |
|--------|------------|------------|------------|-------------------|
| 34 | 22 | 2018-07-17 | 2018-07-20 | checkin |
| 35 | 23 | 2018-07-17 | 2018-07-18 | checkout |
| 36 | 24 | 2018-07-19 | 2018-07-21 | none |
| 37 | 23 | 2018-07-18 | 2018-07-21 | none |
|--------|------------|------------|------------|-------------------|
My goal is to have the following report:
The date of the report is today : 2018-07-18.
|------------|----------------|-------------------|
| ROO_Number | BOO_LiveStatus | BOO_ArrivalStatus |
|------------|----------------|-------------------|
| 101 | in-house | checkin |
| 102 | none | no |
| 201 | none | no |
|------------|----------------|-------------------|
I put a SQLFidde here :
http://sqlfiddle.com/#!9/bb6a30/4
Actually, I'm very near but I have a little problem.
I need to have only one row per room. For room #102, I have two successive bookings and my query returns me two rows for it whereas it should return me the booking with the higher id (BOO_Id).
My last try was this one:
SELECT
ROO_Id,
IF(BOO_DateCI <= '2018-07-18' AND BOO_DateCO >= '2018-07-18', "in-house", "no")
AS BOO_LiveStatus,
IFNULL(BOO_ArrivalStatus, "0")
AS BOO_ArrivalStatus,
BOO_Id,
FROM ___Rooms
LEFT JOIN ___Bookings
ON ___Rooms.ROO_id = ___Bookings.BOO_RoomId
AND '2018-07-18' BETWEEN ___Bookings.BOO_DateCI AND ___Bookings.BOO_DateCO
WHERE ROO_Status != 'inactive'
ORDER BY
ROO_Number
Could you please help me please ?
Thanks a lot.
YOu should add an inner join on the max(BOO_DateCI) group by BOO_RoomId
SELECT
ROO_Id,
IF(BOO_DateCI <= '2018-07-18' AND BOO_DateCO >= '2018-07-18', "in-house", "no")
AS BOO_LiveStatus,
IFNULL(BOO_ArrivalStatus, "0")
AS BOO_ArrivalStatus,
BOO_Id
FROM ___Rooms
inner join (
select BOO_RoomId,max(BOO_DateCI) max_BOO_DateCI
from ___Bookings
group by BOO_RoomId
) t on t.BOO_RoomId = ___Rooms.ROO_id
LEFT JOIN ___Bookings
ON ___Rooms.ROO_id = ___Bookings.BOO_RoomId
AND '2018-07-18' BETWEEN ___Bookings.BOO_DateCI AND ___Bookings.BOO_DateCO
AND t.max_BOO_DateCI= ___Bookings.BOO_DateCI
ORDER BY
ROO_Number

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

mySQL query don't return me the expected results

I have a problem with this query:
SELECT *,
GROUP_CONCAT(COALESCE(STX_Amount, "0")) AS ApplicableTaxesRate,
GROUP_CONCAT(COALESCE(STX_TaxeName, "0")) AS ApplicableTaxesName
FROM ___BillableDatas
JOIN ___Invoices ON ___BillableDatas.BIL_BookingId=___Invoices.IVC_BookingId
JOIN ___Bookings ON ___BillableDatas.BIL_BookingId=___Bookings.BOO_Id
JOIN ___Inventory ON ___BillableDatas.BIL_Item=___Inventory.INV_Id
LEFT JOIN ___SalesTaxes ON FIND_IN_SET(STX_Id, BIL_ApplicableTaxes) > 0
WHERE BIL_HotelId='AAA00' AND IVC_Id=14 AND BIL_Id IN (IVC_Elements)
ORDER BY BIL_Id ASC
From this sqlFiddle (http://sqlfiddle.com/#!9/b2016) and with my actual datas, this query returns me only one row whereas it should returns me 3 (3 because IVC_Elements contains 3 different ids).
--
The desired output should be the following:
|----------|----------|------------|----------|----------|--------------|--------------------|---------------------|
| BIL_Id | IVC_Id | BIL_Date | BIL_Rate | BIL_Type | BIL_Quantity | INV_Name | BIL_ApplicableTaxes |
|----------|----------|------------|----------|----------|--------------|--------------------|---------------------|
| 31 | 14 | 2017-03-15 | 130.00 | Night | 1 | | |
| 32 | 14 | 2017-03-13 | 130.00 | Night | 1 | | |
| 33 | 14 | 2017-03-17 | 130.00 | Night | 1 | | |
| 45 | 14 | 2017-11-01 | 100.00 | Item | 5 | Lit supplémentaire | 11 |
| 50 | 14 | 2017-03-16 | 12.00 | Item | 2 | Petit-déjeuner | |
|----------|----------|------------|----------|----------|--------------|--------------------|---------------------|
Any help please ?
Why IN on WHERE clause does not work
Because you are storing a coma delimited string on IVC_Elements and, I'm sorry, but you cannot use it on this way:
WHERE FIELD IN (FIELD_WITH_COMA_DELIMITED_VALUES);
IN clause requires a list of values
If fact, if you use current value '31,32,33' it returns ID=31 that is the only one it can evaluate, however try to change it by '32,31,33' and you'll obtain row ID=32.
How can you solve it: Change it by:
FIND_IN_SET(BIL_Id, IVC_Elements) > 0
Change your query on this way:
SELECT BIL_Id, IVC_Id, DATE_FORMAT(BIL_Date, "%Y-%m-%d") BIL_Date, BIL_Rate, BIL_Type,
BIL_Quantity, COALESCE(INV_Name, '') INV_Name, BIL_ApplicableTaxes
FROM ___BillableDatas
JOIN ___Invoices
ON ___BillableDatas.BIL_BookingId = ___Invoices.IVC_BookingId
JOIN ___Bookings
ON ___BillableDatas.BIL_BookingId = ___Bookings.BOO_Id
LEFT JOIN ___Inventory
ON ___BillableDatas.BIL_Item = ___Inventory.INV_Id
LEFT JOIN ___SalesTaxes
ON FIND_IN_SET(BIL_ApplicableTaxes, STX_Id) > 0
WHERE BIL_HotelId='AAA00'
AND IVC_Id=14
AND FIND_IN_SET(BIL_Id, IVC_Elements) > 0
ORDER BY BIL_Id ASC
;
This is the result:
+--------+--------+------------+----------+----------+--------------+----------+---------------------+
| BIL_Id | IVC_Id | BIL_Date | BIL_Rate | BIL_Type | BIL_Quantity | INV_Name | BIL_ApplicableTaxes |
+--------+--------+------------+----------+----------+--------------+----------+---------------------+
| 31 | 14 | 2017-03-15 | 130,00 | Night | 1 | | |
+--------+--------+------------+----------+----------+--------------+----------+---------------------+
| 32 | 14 | 2017-03-16 | 130,00 | Night | 1 | | |
+--------+--------+------------+----------+----------+--------------+----------+---------------------+
| 33 | 14 | 2017-03-17 | 130,00 | Night | 1 | | |
+--------+--------+------------+----------+----------+--------------+----------+---------------------+
Check it here: http://rextester.com/BMX51701

Return a ranking from tables with 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