I have the following tables,
select * from department;
+--------------+--------------+--------+------------+---------------+
| departmentid | name | budget | startdate | administrator |
+==============+==============+========+============+===============+
| 101 | Computer Sci | 1000 | 2010-12-26 | XYZ |
| 102 | ECE | 500 | 2015-02-15 | ABC |
| 103 | EEE | 1500 | 2016-08-25 | PQR |
| 104 | Mech | 2500 | 2017-08-22 | LMN |
+--------------+--------------+--------+------------+---------------+
select * from course;
+----------+-------------------+---------+--------------+
| courseid | title | credits | departmentid |
+==========+===================+=========+==============+
| 1001 | Data structures | 12 | 101 |
| 1002 | Algorithms | 12 | 101 |
| 1003 | Graphics | 20 | 101 |
| 2001 | DSP | 20 | 102 |
| 2002 | Matlab | 20 | 102 |
| 2003 | Maths | 10 | 102 |
| 3001 | CAD | 10 | 104 |
| 4001 | Power electronics | 10 | 103 |
| 4002 | Semi conductors | 20 | 103 |
+----------+-------------------+---------+--------------+
select * from student_grade;
+--------------+----------+----------+-------+
| enrollmentid | courseid | personid | grade |
+==============+==========+==========+=======+
| 1 | 1001 | 1 | A |
| 2 | 1002 | 1 | B |
| 3 | 1003 | 1 | A |
| 4 | 3001 | 3 | A |
| 5 | 3001 | 2 | B |
| 6 | 4001 | 4 | A |
| 7 | 4002 | 4 | A |
+--------------+----------+----------+-------+
select * from person;
+----------+----------+-----------+------------+----------------+
| personid | lastname | firstname | hiredate | enrollmentdate |
+==========+==========+===========+============+================+
| 1 | Goudar | Anil | 2016-08-16 | 2016-08-17 |
| 2 | Goudar | Sunil | 2018-09-16 | 2018-09-27 |
| 3 | Dambal | Abhi | 2018-05-07 | 2018-06-17 |
| 4 | Desai | Arun | 2018-05-07 | 2018-06-17 |
| 5 | Xam | Sam | 2018-12-08 | 2018-12-08 |
| 6 | Chatpati | Mangal | 2018-10-10 | 2018-10-08 |
| 9 | Shankar | Dev | 2018-10-10 | 2018-10-08 |
| 10 | Shankar | Mahadev | 2018-08-10 | 2018-08-11 |
+----------+----------+-----------+------------+----------------+
Now I am trying to get the department details with number of students belonging to the department.
And here is my query,
select d.departmentid, d.name, sg.personid from department d inner join course c on c.departmentid = d.departmentid inner join student_grade sg on sg.courseid = c.courseid;
+--------------+--------------+----------+
| departmentid | name | personid |
+==============+==============+==========+
| 101 | Computer Sci | 1 |
| 101 | Computer Sci | 1 |
| 101 | Computer Sci | 1 |
| 104 | Mech | 3 |
| 104 | Mech | 2 |
| 103 | EEE | 4 |
| 103 | EEE | 4 |
+--------------+--------------+----------+
But I want to get the count(distinct(personid)) for each department like group by clause. But I am getting the error with the following query.
select d.departmentid, d.name, count(distinct(sg.personid)) from department d inner join course c on c.departmentid = d.departmentid inner join student_grade sg on sg.courseid = c.courseid;
Cannot use non GROUP BY column 'departmentid' in query results without an aggregate function
Please help me, where I am going wrong.
you have to use group by as you used aggregate funtion
select d.departmentid, d.name,
count(distinct(sg.personid))
from department d inner join course c on c.departmentid = d.departmentid inner join student_grade sg on sg.courseid = c.courseid;
group by d.departmentid, d.name
Use this:-
select d.departmentid, d.name, count(distinct(sg.personid)) from department d inner join course c on c.departmentid = d.departmentid inner join student_grade sg on sg.courseid = c.courseid group by d.departmentid, d.name;
Related
I have following statement that is used to select some fields from MySQL DB
select finance_budget_issue.budget_date, SUM(finance_budget_issue.amount) AS amount, finance_vote.office_id as vote_office_id, finance_office.office_head as head,
finance_office.office_name AS office_name,
finance_budget.ref_no, finance_budget_issue.view_status, tbl_signature.office_head as sign_office_head, tbl_signature.name AS name,
tbl_signature.post AS post, tbl_signature.sign_id
from finance_budget_issue
inner join finance_budget on finance_budget.budget_id=finance_budget_issue.budget_id
left join finance_vote on finance_budget_issue.vote_id=finance_vote.vote_id
left join finance_vote_description on finance_vote.description=finance_vote_description.vote_description_id
left join finance_office on finance_budget_issue.office=finance_office.office_id
left join tbl_signature on finance_office.office_id=tbl_signature.office_id
The statement is working fine, but didn't outs the following fields
tbl_signature.office_head as sign_office_head,
tbl_signature.name AS name,
tbl_signature.post AS post
What may be going wrong ? I think that I used incorrect Joins. Can anyone help ?
Tables as follows :
finance_office
+----+-----------+-------------+------+
| id | office_id | office_name | head |
+----+-----------+-------------+------+
| 1 | 48 | A | SS |
| 2 | 69 | B | VV |
+----+-----------+-------------+------+
finance_vote
+---------+-----------+----------------+
| vote_id | office_id | vote |
+---------+-----------+----------------+
| 1 | 48 | 320-1-2-1-1001 |
| 2 | 48 | 320-2-2-2-2002 |
| 3 | 69 | 319-1-2-1-1001 |
| 4 | 69 | 319-1-2-2-1102 |
| 5 | 30 | 318-1-1-2-1101 |
+---------+-----------+----------------+
tbl_signature
+---------+-----------+---------+------------+-------------+
| sign_id | office_id | name | post | office_head |
+---------+-----------+---------+------------+-------------+
| 1 | 48 | Noel | Accountant | Manager |
| 2 | 69 | Jhon | Accountant | Manager |
| 3 | 30 | Micheal | Accountant | Manager |
+---------+-----------+---------+------------+-------------+
finance_budget
+-----------+--------+-------------+
| budget_id | ref_no | budget_date |
+-----------+--------+-------------+
| 1 | Acc/01 | 2020-01-20 |
| 2 | Acc/02 | 2020-01-22 |
+-----------+--------+-------------+
finance_budget_issue
+----+-----------+--------+---------------+-----------------+
| id | budget_id | amount | budget_status | transfer_status |
+----+-----------+--------+---------------+-----------------+
| 1 | 1 | 75000 | issues | Approved |
| 2 | 1 | 22000 | issues | Approved |
| 3 | 2 | 65000 | issues | Approved |
+----+-----------+--------+---------------+-----------------+
Desired Output
+--------+----------------+------+--------+------------------+------+------------+
| amount | vote_office_id | head | ref_no | sign_office_head | name | post |
+--------+----------------+------+--------+------------------+------+------------+
| 75000 | 48 | SS | Acc/01 | Manager | Noel | Accountant |
| 22000 | 48 | SS | Acc/01 | Manager | Noel | Accountant |
| 65000 | 69 | VV | Acc/02 | Manager | Jhon | Accountant |
+--------+----------------+------+--------+------------------+------+------------+
Generated Output (Incorrect)
+--------+----------------+------+--------+------------------+------+------+
| amount | vote_office_id | head | ref_no | sign_office_head | name | post |
+--------+----------------+------+--------+------------------+------+------+
| 75000 | 48 | SS | Acc/01 | | | |
| 22000 | 48 | SS | Acc/01 | | | |
| 65000 | 69 | VV | Acc/02 | | | |
+--------+----------------+------+--------+------------------+------+------+
This is easier to read:
SELECT i.budget_date
, SUM(i.amount) amount
, v.office_id vote_office_id
, o.office_head head
, o.office_name
, b.ref_no
, i.view_status
, s.office_head sign_office_head
, s.name
, s.post
, s.sign_id
FROM finance_budget_issue i
JOIN finance_budget b
ON b.budget_id = i.budget_id
LEFT
JOIN finance_vote v
ON v.vote_id = i.vote_id
LEFT
JOIN finance_vote_description d
ON d.vote_description_id = v.description
LEFT
JOIN finance_office o
ON i.office = o.office_id
LEFT
JOIN tbl_signature s
ON s.office_id = o.office_id
You have an aggregate function (and non-aggregated columns) but no GROUP BY clause; that's not going to work. You have a LEFT JOINed table from which you select no columns; that's pointless.
For further help, see Why should I provide an MCRE for what seems to me to be a very simple SQL query
Given the following tables:
Staff
+------------+--------+
| employeeID | name |
+------------+--------+
| 100100 | Kelly |
| 101010 | John |
| 222222 | Stuart |
+------------+--------+
Academics
+------------+----------+
| employeeID | degreeID |
+------------+----------+
| 100100 | PhD |
| 101010 | Eng |
| 222222 | Sci |
+------------+----------+
Class
+------------+-----------+-----------+
| employeeID | studentID | subjectID |
+------------+-----------+-----------+
| 100100 | 998 | BUS_18_2 |
| 100100 | 921 | BUS_18_2 |
| 100100 | 901 | BUS_18_2 |
| 100100 | 934 | BUS_19_1 |
| 100100 | 964 | BUS_19_2 |
| 100100 | 934 | LED_19_1 |
| 100100 | 964 | LED_19_2 |
| 101010 | 901 | COE_19_2 |
| 101010 | 874 | COE_19_2 |
| 101010 | 823 | COE_19_2 |
| 222222 | 212 | FTR_17_2 |
| 222222 | 102 | FTR_17_1 |
| 222222 | 684 | FTR_18_1 |
+------------+-----------+-----------+
Return a list of name and degreeIDs of all staff not holding a class in 2019
I've tried various methods around constructing nested having statements to detect if a staff member has worked in multiple years (based on counting subjectIDs), but thats more or less 'hardcoding' it and new entries could corrupt such a method (as seen in the example).
Expected result
+------------+------------+
| name | degreecode |
+------------+------------+
| stuart | sci |
+------------+------------+
Use correlated subquery with not exists
select distinct name, degreeid
from staff a join academics b on a.employeeid=b.employeeid
join class c on a.employeeid=c.employeeid
where not exists
(select 1 from class c1 where c.employeeid=c1.employeeid and subjectID like '%_19%')
The basic idea is not exists. However, your data model seems to be missing information on what classes are offered in 2019. Assuming that class has this information:
select s.name, a.degreeid
from staff s join
academics a
on s.employeeid = a.employeeid
where not exists (select 1
from class c
where c.employeeid = s.employeeid and
c.year = 2019
);
I have the following tables:
clients:
| id | name | code | zone |
--------------------------------
| 1 | client 1 | a1b1 | zone1|
| 2 | client 2 | a2b2 | zone2|
contacts:
| id_contact | first_name | last_name |
----------------------------------------
| 11 | first1 | last1 |
| 22 | first2 | last2 |
| 33 | first3 | last3 |
| 44 | first4 | last4 |
client_contacts:
| id_client | id_contact |
--------------------------
| 1 | 11 |
| 1 | 22 |
| 1 | 33 |
| 2 | 11 |
| 2 | 44 |
offers:
| id_offer | id_client | value |
--------------------------
| 111 | 1 | 100 |
| 222 | 1 | 200 |
| 333 | 1 | 300 |
| 444 | 2 | 400 |
I would like through a optimal select to obtain:
| id_client | name | code | zone | contacts_pers | total_offer_value |
----------------------------------------------------------------------------
| 1 | client 1 | a1b1 | zone1 | first1 last1; | 600 |
first2 last2;
first3 last3;
| 2 | client 2 | a2b2 | zone2 | first1 last1; | 400 |
first4 last4;
I know how to get the desired result with "group_concat" and stored procedures for "total_offer_value". But how to get the desired result from a single efficient select?
SELECT c.id, c.name, c.code, c.zone, GROUP_CONCAT(DISTINCT CONCAT(co.first_name, " ", c.last_name) SEPARATOR ";") AS contact_pers, func_total_offer_value(c.id) AS total_offer_value
FROM clients c
LEFT OUTER JOIN (client_contacts cc, contacts co) ON ( c.id = cc.id_client AND cc.id_contact = co.id_contact )
GROUP BY c.id
I'm new here, someone would have a possible solution to a problem I could not solve with subquery, any idea how to solve the problem?
Basically I need all patients "pa_name", most current exam for each "field: pe_d2" Like "Expected Result:"
I tried to make a sketch of the result, might help understand the problem ...
The "pacient_exams" table has very many records, the query needs to be very fast.
Thanks in advance for possible solutions! []
patient_exams
+-------+----------+----------+------------+------------+
| pe_id | pe_pa_id | pe_ex_id | pe_d1 | pe_d2 |
+-------+----------+----------+------------+------------+
| 1 | 1 | 1 | 2014-05-19 | 2016-05-19 |
| 2 | 1 | 2 | 2014-05-19 | 2015-05-19 |
| 3 | 1 | 3 | 2014-05-26 | 2014-11-26 |
| 4 | 1 | 3 | 2014-05-19 | 2014-11-19 |
| 5 | 1 | 4 | 2013-05-19 | 2013-11-19 |
| 6 | 1 | 4 | 2014-05-19 | 2014-11-19 |
| 7 | 3 | 1 | 2013-08-19 | 2014-08-19 |
| 8 | 3 | 1 | 2014-05-01 | 2017-05-01 |
| 9 | 4 | 2 | 2013-05-02 | 2014-05-02 |
| 10 | 4 | 2 | 2013-11-01 | 2014-05-01 |
| 11 | 4 | 4 | 2013-05-02 | 2014-05-02 |
| 12 | 4 | 4 | 2013-11-01 | 2014-05-01 |
+-------+----------+----------+------------+------------+
patient exams
+-------+---------+ +-------+---------+
| pa_id | pa_name | | ex_id | ex_name |
+-------+---------+ +-------+---------+
| 1 | John M. | | 1 | Exam 1 |
| 2 | Slater | | 2 | Exam 2 |
| 3 | Jonny | | 3 | Exam 3 |
| 4 | Jessy | | 4 | Exam 4 |
| ... | ... | | ... | ... |
+-------+---------+ +-------+---------+
Expected Result:
+-------+---------+---------+------------+------------+
| pe_id | pa_name | ex_name | pe_d1 | pe_d2 |
+-------+---------+---------+------------+------------+
| 9 | Jessy | Exam 2 | 2013-05-02 | 2014-05-02 |
| 11 | Jessy | Exam 4 | 2013-05-02 | 2014-05-02 |
| 1 | John M. | Exam 1 | 2014-05-19 | 2016-05-19 |
| 2 | John M. | Exam 2 | 2014-05-19 | 2015-05-19 |
| 3 | John M. | Exam 3 | 2014-05-26 | 2014-11-26 |
| 6 | John M. | Exam 4 | 2014-05-26 | 2014-11-26 |
| 8 | Jonny | Exam 1 | 2014-05-01 | 2017-05-01 |
+-------+---------+---------+------------+------------+
You need to first get the latest records from the patient_exams table and then join all the 3 tables with the filtered results, like this:
SELECT pe_id, pa_name, ex_name, pe_d1, pe_d2
FROM patient_exams pe
JOIN patient p
ON pe.pe_pa_id = p.pa_id
JOIN exams e
ON pe.pe_ex_id = e.ex_id
JOIN (
SELECT pe_pa_id, pe_ex_id, MAX(pe_d2) AS max_pe_d2
FROM patient_exams
GROUP BY pe_pa_id, pe_ex_id
) AS t
ON pe.pe_pa_id = t.pe_pa_id
AND pe.pe_ex_id = t.pe_ex_id
AND pe.pe_d2 = t.max_pe_d2
ORDER BY pa_name, ex_name
Demo/Solution
Thanks to everyone, works fine!
You can use joins among your tables,for the max exam date you need an additional self join to patient_exams with a subquery to get the maxima of exam date i.e max(pe_d2)
select
pe.pe_id,
p.pa_name ,
e.ex_name ,
pe.pe_d1 ,
pe.pe_d2
from exams e
join patient_exams pe on(e.ex_id = pe.pe_ex_id)
join patient p on(p.pa_id= pe.pe_pa_id)
join (select `pe_pa_id`, `pe_ex_id` ,max(pe_d2) pe_d2
from patient_exams
group by `pe_pa_id`, `pe_ex_id`) pee
on (pe.`pe_pa_id`= pee.`pe_pa_id` and
pe.`pe_ex_id` = pee.`pe_ex_id` and
pe.pe_d2 = pee.pe_d2
)
order by p.pa_name ,pee.pe_d2 desc
Demo
I have three tables; doctor, person, and appointment.
doctor table:
+-----------+----------+---------+----------------+----------------+
| doctor_id | phone_no | room_no | date_qualified | date_appointed |
+-----------+----------+---------+----------------+----------------+
| 50 | 1234 | 1 | 1963-09-01 | 1991-05-10 |
| 51 | 1235 | 2 | 1973-09-12 | 1991-05-10 |
| 52 | 1236 | 3 | 1990-10-02 | 1993-04-01 |
| 53 | 1237 | 4 | 1965-06-30 | 1994-03-01 |
+-----------+----------+---------+----------------+----------------+
person table
+-----------+----------+-----------+---------------+------+
| person_id | initials | last_name | date_of_birth | sex |
+-----------+----------+-----------+---------------+------+
| 100 | T | Williams | 1972-01-12 | m |
| 101 | J | Garcia | 1981-03-18 | f |
| 102 | W | Fisher | 1950-10-22 | m |
| 103 | K | Waldon | 1942-06-01 | m |
| 104 | P | Timms | 1928-06-03 | m |
| 105 | A | Dryden | 1944-06-23 | m |
| 106 | F | Fogg | 1955-10-16 | f |
| 150 | T | Saj | 1994-06-17 | m |
| 50 | A | Cameron | 1937-04-04 | m |
| 51 | B | Finlay | 1948-12-01 | m |
| 52 | C | King | 1965-06-06 | f |
| 53 | D | Waldon | 1938-07-08 | f |
+-----------+----------+-----------+---------------+------+
appointment table
+-----------+------------+------------+-----------+---------------+
| doctor_id | patient_id | appt_date | appt_time | appt_duration |
+-----------+------------+------------+-----------+---------------+
| 50 | 100 | 1994-08-10 | 10:00:00 | 10 |
| 50 | 100 | 1994-08-16 | 10:50:00 | 10 |
| 50 | 102 | 1994-08-21 | 11:20:00 | 20 |
| 50 | 103 | 1994-08-10 | 10:10:00 | 10 |
| 50 | 104 | 1994-08-10 | 10:20:00 | 20 |
| 52 | 102 | 1994-08-10 | 10:00:00 | 10 |
| 52 | 105 | 1994-08-10 | 10:10:00 | 10 |
| 52 | 150 | 2014-03-10 | 12:00:00 | 15 |
| 53 | 106 | 1994-08-10 | 11:30:00 | 10 |
+-----------+------------+------------+-----------+---------------+
I need to create a query to produce a list of doctor IDs and their names with the number of appointments they have.
I have already created a statement to produce a list of doctor IDs with the number of appointments they have but im not sure how to produce a list with doctor IDs and their names.
The statement that I have now is:
select doctor.doctor_id, count(appointment.appt_time) as no_appt
from doctor
left join appointment
on doctor.doctor_id = appointment.doctor_id
group by doctor.doctor_id;
Please Help.
You need an additional join to the person table. Apparently, the doctor_id is the link. Yuck. This should be an explicit column rather than a re-use of the id.
select d.doctor_id, p.initials, p.last_name, count(appointment.appt_time) as no_appt
from doctor d left join
appointment a
on d.doctor_id = a.doctor_id left join
person p
on d.doctor_id = p.person_id
group by d.doctor_id, p.initials, p.last_name;
In MySQL, you don't actually need to add the two columns to the group by, but it is good practice to do so.
select doctor.doctor_id, person.initials, person.last_name, count(appointment.appt_time) as no_appt
from doctor
left join appointment on doctor.doctor_id = appointment.doctor_id
left join person on person.person_id = appointment.patient_id
group by doctor.doctor_id;
your SQL is nearly there - you just need to add a JOIN to the Person table to get the initial and last_name of the doctors - like this:
SELECT
d.doctor_id,
p.initials,
p.last_name,
COUNT(a.*)
FROM [person] p
JOIN [doctor] d ON p.person_id = d.doctor_id
LEFT JOIN [appointment] a ON a.doctor_id = d.doctor_id
GROUP BY d.doctor_id, p.initials, p.last_name
Hope this helps