Row count MySQL with three tables - php

My MySQL DB looks like this
**table_schools**
id | name
1 | school_1
2 | school_2
**table_classes**
id | class | school_id
1 | a | 1
2 | b | 1
3 | c | 2
4 | d | 2
5 | e | 2
**table_students**
id | name | class_id
1 | Nick | 1
2 | Tom | 2
3 | Kevin | 3
4 | Jane | 4
5 | Mark | 5
6 | Tim | 5
7 | Lynn | 5
I would like to have an output like this:
school_name | class_count | student_count
school_1 | 2 | 2
school_2 | 3 | 5
Is there a way to do this in ONE sql query? And how?

SELECT s.name, COUNT(DISTINCT c.id) AS classes, COUNT(st.id) AS students
FROM table_schools s
LEFT JOIN
table_classes c
ON c.school_id = s.id
LEFT JOIN
table_students st
ON st.class_id = c.id
GROUP BY
s.id

SELECT table_schools.name, COUNT(table_classes.name) AS classes, COUNT(table_students.id) AS students
FROM table_schools
LEFT JOIN table_classes ON table_schools.id = table_classes.school_id
LEFT JOIN table_students ON table_students.class_id = table_classes.id
GROUP BY table_schools.id, table_classes.id
ORDER BY table_schools.name

Related

MySql Query for one to many relationship

Facing issue in mysql query, tried with mysql join but not getting expected output.
I want all class, all student record with total ratingscore.Each Class has Many Student. Student has Many or none scholarship
Class table looks like this
+---------------------+
| id classname |
+---------------------+
| 1 10 |
| 2 11 |
| 3 12 |
+---------------------+
Student table looks like, classid is foreign key
+------------------------------------+
| id classid studentname |
+------------------------------------+
| 1 1 xembine |
| 2 1 denial |
| 3 2 suzone |
| 4 3 rosh |
| 5 2 broad |
| 6 1 bell |
| 7 3 martin |
| 8 1 jroff |
+------------------------------------+
rating table looks like, studentid is foreign key
+------------------------------------+
| id studentid ratingscore |
+------------------------------------+
| 1 1 4000 |
| 2 1 10000 |
| 3 5 20000 |
| 4 2 1000 |
| 5 6 2222 |
| 6 1 5000 |
| 7 6 12000 |
| 8 3 3800 |
| 9 5 7500 |
+------------------------------------+
Here : No student from class 3, got any ratingscore yet.so need that student has zero ratingscore.
Expected Output:-
+-------------------------------------------------------------+
| studentname studentid classid classname ratingscore |
+-------------------------------------------------------------+
| xembine 1 1 10 19000 |
| denial 2 1 10 1000 |
| suzone 3 2 11 3800 |
| rosh 4 3 12 0 |
| broad 5 2 11 27500 |
| bell 6 1 10 2222 |
| martin 7 3 12 0 |
| jroff 8 1 10 0 |
+-------------------------------------------------------------+
select s.studentname, s.id as studentid,s.classid,c.classname,sum(ifnull(r.ratingscore,0)) as ratingscore from student s
join class c on c.id=s.classid
left outer join rating r on r.studentid=s.id
group by s.studentname,r.studentid,s.classid,c.classname
Have you try this ?
SELECT s.studentname, s.studentid, c.classid, c.classname, SUM(r.ratingscore)
FROM student as s
INNER JOIN class c on c.classid = s.classid
LEFT OUTER JOIN ratingscore rs ON s.studentid = rs.studentid
GROUP BY s.studentname, s.studentid, c.classid, c.classname
ORDER BY s.studentid
If there is student without class, you have to change inner join to left outer join
SELECT s.studentname AS studentname, s.id AS studentid, c.id AS classid, c.classname AS classname, SUM(r.ratingscore) AS ratingscore
FROM student AS s
INNER JOIN class AS c ON c.id = s.classid
LEFT JOIN rating r ON r.studentid = s.id
GROUP BY s.id
ORDER BY s.id

display all time appointments and reserve

My system for appointments has some managers(Ex. doctor), and I intend for all appointment times to display in a table so appointments are filled or empty with the name of the user
Create a table for times appointments :
+-----------+-----------+
| id | time
+-----------+------------
| 1 | 10:00 |
| 2 | 10:30 |
| 3 | 11:00 |
| 4 | 11:30 |
| 5 | 12:00 |
| 6 | 12:30 |
| 7 | 13:00 |
| 8 | 13:30 |
| 9 | 14:00 |
+-----------+-----------+
manager table
+-----------+-------------+-----------+
| id | name | phone |
+-----------+-------------+-----------+
| 1 | alex | 123456 |
| 2 | dany | 123456 |
user table :
+----+------+-------+-----------+
| id | manager_id | name | phone |
+----+------------+------+-----------+
| 1 | 1 | John | 123456 |
| 2 | 1 | Sara | 123456 |
| 3 | 2 | lorem | 123456 |
+----+------+-------+-----------+
and order table(for appointments)
+----+------+-------+------------------+-----------+
| id | manager_id | userid | reserveid| datereserve
+----+------------+------+-------------+-----------+
| 1 | 1 | 1 | 1 |2016/12/28
| 2 | 1 | 2 | 2 |2016/12/28
| 3 | 2 | 3 | 3 |2016/12/28
+----+------+-------+-----------+-----------+------+
Now I want to display reserved time in a table in which appointments filled or empty with the name of the user
like :
Similar this photo
I Joined all of tables in query but can't display similar photo and fetch data:(
How can I implement it?
SELECT
m.name,
a.time,
u.phone,
u.name <- if u.name or u.phone is NULL, then appointment is free now
FROM manager as m
CROSS JOIN appointments as a
LEFT JOIN order as o ON o.manager_id = m.id AND o.appointmentsid = a.id
LEFT JOIN user as u ON u.id = o.userid
#for some doctor
WHERE m.id = DoctorID
I would suggest another table
create table status(id int, name varchar(50));
and insert values (1, "reserved"), (2, "free").
select t.time, s.name, m.name, u.name, u.phone
from time t left join status s on t.id = s.id
left join order o on o.appointmentsid = t.id
left join manager m on o.manager_id = m.id
left join users u on o.userid = u.id;

MySQL getting total number of enquiries for each branch

I have three tables and they are the following
User Table
+---------+-----------+--------+
| user_id | user_name | branch |
+---------+-----------+--------+
| 1 | John | 1 |
| 2 | Jim | 2 |
| 3 | Jern | 3 |
| 4 | Jack | 1 |
| 5 | Jery | 2 |
| 6 | Tom | 3 |
| 7 | Sona | 1 |
| 8 | Tina | 3 |
+---------+-----------+--------+
Branch Table
+-----------+----------------+
| branch_id | branch_name |
+-----------+----------------+
| 1 | IT |
| 2 | SALES |
| 3 | Administration |
+-----------+----------------+
Enquiry Table
+------------+---------------+---------+
| enquiry_id | enquiry_name | user_id |
+------------+---------------+---------+
| 1 | enqury_test1 | 1 |
| 2 | enqury_test2 | 2 |
| 3 | enqury_test3 | 1 |
| 4 | enqury_test4 | 3 |
| 5 | enqury_test5 | 2 |
| 6 | enqury_test6 | 5 |
| 7 | enqury_test7 | 1 |
| 8 | enqury_test8 | 2 |
| 9 | enqury_test9 | 4 |
| 10 | enqury_test10 | 6 |
| 11 | enqury_test11 | 2 |
| 12 | enqury_test12 | 7 |
+------------+---------------+---------+
From the above tables its clear that, each branch contains a number of users.
These users post multiple enquiries.
I need to get the total number of enquiries in each branch as
branch id => number of enquiries
I have tried various queries. But i couldn't get the result. Any one can help?
I am using MySQL and i need a single query to do this.
Thanks in advance
You need count and group by
select
b.branch_id,
count(e.user_id) as `total_enq`
from Branch b
left join User u on u.branch = b.branch_id
left join Enquiry e on e.user_id = u.user_id
group by b.branch_id
The query you have to perform to get you desired result is like this :-
$query = "SELECT u.branch, COUNT(u.user_id) AS `total_enquires`
FROM enquiry e INNER JOIN user u ON e.user_id = u.user_id
GROUP BY u.branch"
This will help you,and i think you don't need to join branch table as user table already contain branch_id.
This is the query
SELECT `branch`,`branch_name`,count(`user`.`user_id`),count(`enquiry_id`) FROM `user` inner join `branch` on `user`.`branch`=`branch`.`branch_id` inner join `enquiry` on `user`.`user_id`=`enquiry`.`user_id` group by `branch`
try it here
http://sqlfiddle.com/#!9/cf3eb/1
SELECT
bt.branch_id
,COUNT(enquiry_id) AS total_enquiry
FROM
enquiry_table et
INNER JOIN user_table ut on ut.user_id = et.user_id
INNER JOIN branch_table bt ON bt.branch_id = ut.branch
WHERE
1=1
GROUP BY
bt.branch_id
you can try this

Custom MySQL Ordering

I have a query that needs a custom sorting, trimmed down to the bare minimums something like:
SELECT u.*, p.*, p.id as product_id
FROM users u, products p
WHERE u.id = p.user_id
ORDER BY product_id DESC
And I get returned a set of rows like:
UserID ProductID
2 5
2 4
3 3
1 2
1 1
But I want it to actually sort SOMETHING like this (so no 2 UserIDs are adjacent to eachother):
UserID ProductID
1 2
2 4
3 3
2 5
1 1
Is this even possible with MySQL, or do I need some PHP magic?
A canonical way of solving this problem is by enumerating the duplicate rows and then ordering by that value:
select t.*
from (SELECT u.*, p.*, p.id as product_id,
row_number() over (partition by u.id order by (select NULL)) as seqnum
FROM users u join
products p
on u.id = p.user_id
) t
order by seqnum, id;
This will work, as long as no one user has a really long sequence (as in your example).
There is no "always-works" solution, because it is easy to come up with a situation where your goal is not possible.
Here fetch your sorted results into an array. Then do something like this.
$records = $res->fetchAll();
$count = count($records);
$records = array_chunk($records, ceil(count($records)/2);
$unsorted = array();
for($x = 0; $x < $count; $x++){
$unsorted[] = $records[$x%2][floor($x/2)];
}
Consider the following...
CREATE TABLE sortable(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,player_id INT NOT NULL);
INSERT INTO sortable(player_id) VALUES (1),(1),(2),(3),(4),(3),(3),(2),(1),(2),(4),(4);
SELECT * FROM sortable;
+----+-----------+
| id | player_id |
+----+-----------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 4 |
| 6 | 3 |
| 7 | 3 |
| 8 | 2 |
| 9 | 1 |
| 10 | 2 |
| 11 | 4 |
| 12 | 4 |
+----+-----------+
SELECT x.*,COUNT(*) rank FROM sortable x JOIn sortable y ON y.player_id = x.player_id AND y.id <= x.id GROUP BY x.id ORDER BY player_id,rank;
+----+-----------+------+
| id | player_id | rank |
+----+-----------+------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 9 | 1 | 3 |
| 3 | 2 | 1 |
| 8 | 2 | 2 |
| 10 | 2 | 3 |
| 4 | 3 | 1 |
| 6 | 3 | 2 |
| 7 | 3 | 3 |
| 5 | 4 | 1 |
| 11 | 4 | 2 |
| 12 | 4 | 3 |
+----+-----------+------+
SELECT x.*,COUNT(*) rank FROM sortable x JOIn sortable y ON y.player_id = x.player_id AND y.id <= x.id GROUP BY x.id ORDER BY rank;
+----+-----------+------+
| id | player_id | rank |
+----+-----------+------+
| 1 | 1 | 1 |
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 4 | 1 |
| 2 | 1 | 2 |
| 8 | 2 | 2 |
| 6 | 3 | 2 |
| 11 | 4 | 2 |
| 9 | 1 | 3 |
| 10 | 2 | 3 |
| 7 | 3 | 3 |
| 12 | 4 | 3 |
+----+-----------+------+
So if your problem is just that you dont want two records with same id should not come next to each other wha I can think simplest is use
SELECT u.*, p.*, p.id as product_id
FROM users u, products p
WHERE u.id = p.user_id
ORDER BY user_id%2 DESC
Or you can even use other number than 2 to meet any certain order you want....

SQL query statement table joins

I have a problem with a SQL query and the resultset being returned not being what I expected.
I have these three tables that I am trying to relate.
events_detail
__________________
| ID | start_date |
| 1 | 2012-08-09 |
| 2 | 2013-02-13 |
| 3 | 2012-12-12 |
| 4 | 2013-01-21 |
| 5 | 2012-12-25 |
-------------------
where ID is the primary key
events_category_relationship
__________________________
| ID | event_id | cat_id |
| 1 | 1 | 1 |
| 2 | 2 | 4 |
| 3 | 3 | 2 |
| 4 | 4 | 2 |
| 5 | 5 | 3 |
--------------------------
where ID is primary key
events_category_detail
__________________________________
| ID | name | description |
| 1 | Europe | Kings and castles! |
| 2 | USA | Freedoms |
| 3 | China | Made in China |
| 4 | UK | Big Brother |
------------------------------------
where ID is primary key
What I need to do is grab only 1 event from each category and sorted by date of earliest appearance. So what I should expect in my result is the following
Result Set
________________________________________________________________
| e_id | start_date | c_id | category_name | category_desc |
| 1 | 2012-08-09 | 1 | Europe | Kings and castles! |
| 3 | 2012-12-12 | 2 | USA | Freedoms |
| 5 | 2012-12-25 | 3 | China | Made in China |
| 2 | 2013-02-13 | 4 | UK | Big Brother |
-----------------------------------------------------------------
My SQL query that I tried looks like this
SELECT e.id, e.start_date, c.category_name, c.category_desc
FROM events_detail e
JOIN events_category_relationship r ON r.event_id = e.id
JOIN events_category_detail c ON c.id = r.cat_id
ORDER BY date(e.start_date)
This just joins the 3 tables and returns the result in order by date. What I am stuck on is making it so that only one of each category is displayed like the desired result set above. I have tried using DISTINCT c.category_name and GROUP BY c.category_name, but none of them works.
Any help or advice will be greatly appreciated.
You will want to use a subquery to get the min(start_date) for each name and description. You will then use this result to join back to your events_details table to get the id associated with the data in the subquery:
SELECT e.id,
d.start_date,
d.name,
d.description
FROM events_detail e
INNER JOIN
(
select min(e.start_date) Start_date,
c.name,
c.description
from events_detail e
INNER JOIN events_category_relationship r
ON r.event_id = e.id
INNER JOIN events_category_detail c
ON c.id = r.cat_id
group by c.name, c.description
) d
on e.start_date = d.Start_date
ORDER BY date(e.start_date)
See SQL Fiddle with Demo

Categories