SQL Query COUNT SELECT - mysql

I need to generate table as stated below. I have these samples but it doesn't work. Any please help.
SELECT id, room, bed,
bed -(SELECT count(bed) FROM tb_student WHERE room_id = id) as FREE
FROM tb_rooms
tb_rooms
+----+-------+-----+
| ID | ROOM | BED |
+----+-------+-----+
| 1 | A111 | 4 |
| 2 | A112 | 2 |
| 3 | A113 | 2 |
| 4 | A114 | 2 |
+----+-------+-----+
tb_student
+----+---------+----------+
| ID | STUD_ID | ROOM_ID |
+----+---------+----------+
| 1 | 211 | 3 |
| 2 | 212 | 1 |
| 3 | 213 | 1 |
| 4 | 214 | 2 |
+----+----------+---------+
I need something like this...
+----+-------+------+-----+
| ID | ROOM | BED |FREE |
+----+-------+------+-----+
| 1 | A111 | 4 | 2 |
| 2 | A112 | 2 | 1 |
| 3 | A113 | 2 | 1 |
| 4 | A114 | 2 | 2 |
+----+-------+------+-----+

try this
SELECT id as id, room as room, bed as bed,
bed -( SELECT count(Room_ID) FROM tb_student where room_id = soh.id) as FREE
FROM tb_rooms soh
good luck

hello john your query right only create alias of your table
see here your query :
SELECT id as id, room as room, bed as bed,
bed -( SELECT count(*) FROM tb_student where room_id = tr.id) as FREE
FROM tb_rooms tr

You can try this:
SELECT
r.ID,
r.ROOM,
r.BED,
r.BED - COUNT(DISTINCT s.ID) AS FREE
FROM tb_rooms AS r
LEFT JOIN tb_student AS s ON r.ID = s.ROOM_ID
GROUP BY r.ID, r.ROOM, r.BED
Here is the SQLFIDDLE.

Related

SQL search merge

I'm trying to merge two select sentence. Is it possible ?
I have three tables :
score
+------+---------+-------+
| ID | SUBJECT | SCORE |
+------+---------+-------+
| 1 | Chinese | 65 |
| 1 | English | 75 |
| 2 | Chinese | 60 |
| 2 | English | 70 |
| 3 | Chinese | 80 |
| 3 | English | 50 |
+------+---------+-------+
student
+------+----------+--------+
| ID | CLASS_ID | NAME |
+------+----------+--------+
| 1 | 1 | TOM |
| 2 | 1 | ANNA |
| 3 | 2 | JOHN |
+------+----------+--------+
class
+------+----------+
| ID | NAME |
+------+----------+
| 1 | 5th |
| 2 | 6th |
+------+----------+
mysql> select class.NAME as CLASS_NAME, student.NAME from class inner join student on student.CLASS_ID = class.ID;
+------------+--------+
| CLASS_NAME | NAME |
+------------+--------+
| 5th | TOM |
| 6th | ANNA |
| 6th | JOHN |
+------------+--------+
mysql> select SUM(SCORE) as total from score group by ID;
+-------+
| total |
+-------+
| 140 |
| 130 |
| 130 |
+-------+
Could I merge two select sentence let it be
+------------+--------+-------+
| CLASS_NAME | NAME | total |
+------------+--------+-------+
| 5th | TOM | 140 |
| 6th | ANNA | 130 |
| 6th | JOHN | 130 |
+------------+--------+-------+
Or is there any better search sentence to do this well?
I try use two sentence to merge , but can't have a good idea.
mysql> select class.NAME as CLASS_NAME, student.NAME from class inner join student on student.CLASS_ID = class.ID;
mysql> select SUM(SCORE) as total from score group by ID;
hope it can be merge success or have another answer to do this well.
You can use inner join to merge the second query. Below query takes in consideration that the join condition will be score.id with student.id
select c.name as class_name,
st.name ,
sc.total
from class c
inner join student st on st.class_id = c.id
inner join ( select id,
SUM(SCORE) as total
from score
group by id
) as sc on sc.id=st.id ;
https://dbfiddle.uk/tauTGBFO

MySQL Count Comma Delimited

I have 3 tables like this:
table_events
+------+----------+----------------------+
| ID | Title | Employees |
+------+----------+----------------------+
| 1 | Event1 | john,james |
+------+----------+----------------------+
| 2 | Event2 | sarah,jessica |
+------+----------+----------------------+
table_check_in
+------+----------+----------+---------------------+
| ID | Time | EventID | By |
+------+----------+----------+---------------------+
| 1 | 08:30 | 1 | john |
+------+----------+----------+---------------------+
| 2 | 08:30 | 1 | james |
+------+----------+----------+---------------------+
| 3 | 09:30 | 1 | john |
+------+----------+----------+---------------------+
| 4 | 10:30 | 2 | sarah |
+------+----------+----------+---------------------+
| 5 | 10:35 | 2 | sarah |
+------+----------+----------+---------------------+
table_problems
+------+----------------+----------+---------------------+
| ID | Comment | EventID | By |
+------+----------------+----------+---------------------+
| 1 | Broken door | 1 | john |
+------+----------------+----------+---------------------+
| 2 | Slippery floor | 1 | john |
+------+----------------+----------+---------------------+
| 3 | Leaking tap | 1 | john |
+------+----------------+----------+---------------------+
| 4 | Broken window | 2 | jessica |
+------+----------------+----------+---------------------+
| 5 | Broken glass | 2 | jessica |
+------+----------------+----------+---------------------+
I would like to print something like this:
+------+----------+---------------+-------------------+-------------------+
| ID | Title | Employees | Count_Check_In | Count_Problems |
+------+----------+---------------+-------------------+-------------------+
| 1 | Event1 | john,james | john:2,james:1 | john:3,james:0 |
+------+----------+---------------+-------------------+-------------------+
| 2 | Event2 | sarah,jessica | sarah:2,jessica:0 | sarah:0,jessica:2 |
+------+----------+---------------+-------------------+-------------------+
I know this problem would be trivial if the database was designed properly, but we don't have the luxury of an application rewrite at the moment.
You need to initially get all the employees for each event id from check in and problem tables by using a union.
Then left join the counts from each of check in and problems table to the previous result to get the 0 counts as well.
Finally use a group_concat to get the result in one row for each event id.
select te.id,te.title,te.employees
,group_concat(concat(t.`By`,':',coalesce(tccnt.cnt,0))) count_check_in
,group_concat(concat(t.`By`,':',coalesce(tpcnt.cnt,0))) count_problems
from table_events te
left join (select eventid,`By` from table_check_in
union
select eventid,`By`from table_problems) t on te.id = t.eventid
left join (select eventid,`By`,count(*) cnt from table_check_in group by eventid,`By`) tccnt on tccnt.eventid = t.eventid and tccnt.`By`=t.`By`
left join (select eventid,`By`,count(*) cnt from table_problems group by eventid,`By`) tpcnt on tpcnt.eventid = t.eventid and tpcnt.`By`=t.`By`
group by te.id,te.title,te.employees
Sample Demo (thanks to #valex for setting up the schema)
You can use GROUP_CONCAT to get a result. Here is an example. The only thing missed is employees with 0 check ins or problems.
SELECT ID, Title,Employees,
GROUP_CONCAT(DISTINCT CONCAT(check_in.`By`,':',check_in.cnt))
as Count_Check_In,
GROUP_CONCAT(DISTINCT CONCAT(problems.`By`,':',problems.cnt))
as Count_Problems
FROM table_events
LEFT JOIN (SELECT EventID,`By`, COUNT(*) as cnt
FROM table_check_in
GROUP BY EventID,`By`) as check_in
ON table_events.ID = check_in.EventID
LEFT JOIN (SELECT EventID,`By`, COUNT(*) as cnt
FROM table_problems
GROUP BY EventID,`By`) as problems
ON table_events.ID = problems.EventID
GROUP BY table_events.id
Demo

How to SELECT 2 tbls but only 1 row from second tbl with lowest PK in MySQL?

structure:
tbl 1
|car_id(PK)| make | model | year |
-----------------------------------
| 1 | Toyot | Camry | 1999 |
| 2 | Honda | Civic | 2005 |
tbl 2
|img_id(PK)| car_id| img_link |
------------------------------------
| 1 | 1 | tcamry1.jpeg |
| 2 | 1 | tcamry2.jpeg |
| 3 | 1 | tcamry3.jpeg |
| 4 | 2 | hcivic1.jpeg |
| 5 | 2 | hcivic2.jpeg |
My query:
SELECT *
FROM cars c
LEFT JOIN imgs g
ON c.car_id=g.car_id
WHERE 1
Result:
|img_id(PK)| car_id| make | model | year | img_link |
-----------------------------------------------------------
| 1 | 1 | Toyot | Camry | 1999 | tcamry1.jpeg |
| 2 | 1 | Toyot | Camry | 1999 | tcamry2.jpeg |
| 3 | 1 | Toyot | Camry | 1999 | tcamry3.jpeg |
| 4 | 2 | Honda | Civic | 2005 | hcivic1.jpeg |
| 5 | 2 | Honda | Civic | 2005 | hcivic2.jpeg |
I need to get 1 row for each car and have WHERE clause with something like lowest img_id value out of all img_id related to the same car.
Result I want:
|img_id(PK)| car_id| make | model | year | img_link |
-----------------------------------------------------------
| 1 | 1 | Toyot | Camry | 1999 | tcamry1.jpeg |
| 4 | 2 | Honda | Civic | 2005 | hcivic1.jpeg |
Thank you.
UPDATE:
I need something along these lines :-/
SELECT g.id, c.car_id, c.mc_make, c.mc_model, c.mc_year, c.mc_desc
FROM mycars c
INNER JOIN (SELECT * FROM mycars_gallery g WHERE )
ON c.car_id=g.car_id
WHERE g.id = min(g.id)
Try:
SELECT MIN(b.img_id), a.car_id, a.make, a.model, a.year, b.img_link
FROM cars a
LEFT JOIN imgs b ON a.car_id = b.car_id
GROUP BY a.car_id, a.make, a.model, a.year ;
Demo: http://sqlfiddle.com/#!2/1469f/15
Hope this helps.
SELECT *
FROM cars c
LEFT JOIN imgs g
ON c.car_id=g.car_id
WHERE img_id IN(SELECT MIN(img_id)) GROUP BY model
SELECT *
FROM cars c
LEFT JOIN imgs g
ON c.car_id=g.car_id
WHERE 1
GROUP BY g.img_link;
try this.. not sure though.

Select rows with alternate ordered field from another table

Given a *students_exam_rooms* table:
+------------+---------+---------+
| student_id | room_id | seat_no |
+------------+---------+---------+
| 1 | 30 | 1001 |
| 2 | 30 | 1002 |
| 3 | 31 | 2001 |
| 4 | 32 | 2002 |
| 5 | 33 | 3001 |
| 6 | 33 | 3002 |
| 7 | 34 | 4001 |
| 8 | 34 | 4002 |
+------------+---------+---------+
And *students_tbl*:
+------------+-------------+------+
| student_id | studen_name | year |
+------------+-------------+------+
| 1 | Eric | 1 |
| 2 | Mustafa | 1 |
| 3 | Michael | 2 |
| 4 | Andy | 2 |
| 5 | Rafael | 3 |
| 6 | Mark | 3 |
| 7 | Jack | 4 |
| 8 | peter | 4 |
+------------+-------------+------+
How can I select from *students_exam_rooms* ordering by *students_tbl.year* but with one after one like this:
+--------------+------+
| student_name | year |
+--------------+------+
| Eric | 1 |
| Michael | 2 |
| Rafael | 3 |
| Jack | 4 |
| Mustafa | 1 |
| Andy | 2 |
| Mark | 3 |
| Peter | 4 |
+--------------+------+
I'm assuming that you want to order by the "occurrence-count" of the year then the year, e.g. all the first-occurrences of all years first, sorted by year, then all second-occurrences of all years also sorted by year, and so on. That would be a perfect case for emulating other RDBMS' analytic / windowing functions:
select *
from (
select
s.studen_name,
s.year,
ser.*,
(
select 1 + count(*)
from students_tbl s2
where s.year = s2.year
and s.student_id > s2.student_id
) rank
from students_tbl s
JOIN students_exam_rooms ser
ON s.student_id = ser.student_id
) i_dont_really_want_to_name_this
order by rank, year
Here it is against a slightly tweaked version of JW's fiddle: http://www.sqlfiddle.com/#!2/27c91/1
Emulating Analytic (AKA Ranking) Functions with MySQL is a good article that gives more background and explanation.
try any of these below:
SELECT a.studen_name, a.year
FROM students_tbl a
INNER JOIN students_exam_rooms b
ON a.student_id = b.student_id
ORDER BY REVERSE(b.seat_no),
a.year
SQLFiddle Demo
by using Modulo
SELECT a.studen_name, a.year
FROM students_tbl a
INNER JOIN students_exam_rooms b
ON a.student_id = b.student_id
ORDER BY CASE WHEN MOD(b.seat_no, 2) <> 0 THEN 0 ELSE 1 END,
a.year
SQLFiddle Demo
Looks to me like you're trying to sort first by seat and then by year. Looking at your students_exam_rooms table, it looks like you started with a simple seat number and prepended year * 1000. So, if we omit the year, it looks like this:
> select * from fixed_students_exam_rooms;
+------------+---------+---------+
| student_id | room_id | seat_no |
+------------+---------+---------+
| 1 | 30 | 1 |
| 2 | 30 | 2 |
| 3 | 31 | 1 |
| 4 | 32 | 2 |
| 5 | 33 | 1 |
| 6 | 33 | 2 |
| 7 | 34 | 1 |
| 8 | 34 | 2 |
+------------+---------+---------+
And if you had that table, your query is simple:
select
student_name, year
from
modified_student_exame_rooms
left join students_tbl using (student_id)
order by
seat_no, year
;
Using the table as you currently have it, it's only slightly more complicated, assuming the "core seat number" doesn't excede 999.
select
student_name, year
from
modified_student_exame_rooms
left join students_tbl using (student_id)
order by
convert(substr(seat_no, 2), unsigned),
year
;

Include third table in LEFT JOIN query

I have five mysql tables. shops
+----+--------------+--------------+
| id | name | address |
+----+--------------+--------------+
| 1 | Shop1 | Street1 |
| 2 | Shop2 | Street2 |
| 3 | Shop3 | Street3 |
| 4 | Shop4 | Street4 |
+----+--------------+--------------+
fruits
+----+--------------+--------------+
| id | fruit | price |
+----+--------------+--------------+
| 1 | Bannana | 2.5 |
| 2 | Apple | 2.1 |
| 3 | Orange | 1.8 |
| 4 | Plum | 2.2 |
+----+--------------+--------------+
availability
+----+--------------+--------------+
| id | shop_id | fruit_id |
+----+--------------+--------------+
| 1 | 1 | 2 |
| 2 | 2 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
+----+--------------+--------------+
shop_activity
+----+--------------+--------------+--------------+
| id | shop_id | user_id | status |
+----+--------------+--------------+--------------+
| 1 | 2 | 1 | 1 |
| 2 | 3 | 2 | 1 |
| 3 | 1 | 2 | 2 |
| 4 | 2 | 2 | 1 |
+----+--------------+--------------+--------------+
users
+----+--------------+
| id | name |
+----+--------------+
| 1 | Peter |
| 2 | John |
+----+--------------+
I have query
SELECT
availability.shop_id,
shops.name
FROM availability
LEFT JOIN shops
ON availability.shop_id=shops.id
WHERE
fruit_id = 2
As a result I get name list of shops where fruit with id 2 (apple) is available.
What should I do so that I can include shop_activity table in query to get user's status if users.id = 1 beside proper shop. Something like this...
Shop1, NULL
Shop2, status: 1
You could try something like this:
SELECT
availability.shop_id,
shops.name,
shop_activity.status
FROM availability
LEFT JOIN shops
ON availability.shop_id=shops.id
LEFT JOIN shop_activity
ON shop_activity.shop_id = availability.shop_id
and shop_activity.user_id = 1
WHERE
fruit_id = 2
SELECT
availability.shop_id,
shops.name
FROM shops
LEFT JOIN availability ON availability.shop_id=shops.id
LEFT JOIN shop_activity ON shop_activity .shop_id=shops.id
WHERE
fruit_id = 2
and users.id=1
try making shops as the first table in left join
Try the following:
SELECT shops.name, shop_activity.status
FROM shops
INNER JOIN availability ON availability.shop_id = shops.id
AND availability.fruit_id = 2
LEFT JOIN shop_activity ON shops.shop_id = shop_activity.shop_id
AND shop_activity.user_id = 1
This should give you a row for every shop with apples, but the status will show as null for shops where the user has no activity, otherwise shows the status of that user.