DB2 SQL nested queries - sql

I need to list the first name and last name of the youngest patient that is prescribed penicillin, using nested queries. Here is what I have
SELECT P.FIRST_NAME, P.LAST_NAME, MIN(P.AGE) AS AGE
FROM PATIENT AS P
WHERE P.PATIENT_NO IN(
SELECT PRE.PATIENT_NO
FROM PRESCRIPTION AS PRE
WHERE MEDICATION_CODE IN (
SELECT M.MEDICATION_CODE
FROM MEDICATION AS M
WHERE MEDICATION_DESC = 'Penicillin'))
GROUP BY P.FIRST_NAME, P.LAST_NAME
HAVING MIN(P.AGE);
The results come back with the two people that are prescribed penicillin, not just the youngest.

Why do you have to use nested queries?
In any case, the having clause is not doing what you want. You can get what you want by doing this:
SELECT P.FIRST_NAME, P.LAST_NAME, MAX(P.AGE) as AGE
FROM PATIENT AS P
WHERE P.PATIENT_NO IN (
SELECT PRE.PATIENT_NO
FROM PRESCRIPTION AS PRE
WHERE MEDICATION_CODE IN (
SELECT M.MEDICATION_CODE
FROM MEDICATION AS M
WHERE MEDICATION_DESC = 'Penicillin'
)
)
GROUP BY P.FIRST_NAME, P.LAST_NAME
ORDER BY MAX(P.AGE)
FETCH FIRST 1 ROWS ONLY;
EDIT:
Actually, I agree with FloChanz, and the group by is probably not necessary (unless you need to remove duplicates):
SELECT P.FIRST_NAME, P.LAST_NAME, P.AGE
FROM PATIENT AS P
WHERE P.PATIENT_NO IN (
SELECT PRE.PATIENT_NO
FROM PRESCRIPTION AS PRE
WHERE MEDICATION_CODE IN (
SELECT M.MEDICATION_CODE
FROM MEDICATION AS M
WHERE MEDICATION_DESC = 'Penicillin'
)
)
ORDER BY P.AGE
FETCH FIRST 1 ROWS ONLY;

I guess that some inner join might be better like this :
SELECT P.FIRST_NAME, P.LAST_NAME, P.AGE
FROM MEDICATION AS M
INNER JOIN PRESCRIPTION AS PRE on PRE.MEDICATION_CODE = M.MEDICATION_CODE
INNER JOIN PATIENT AS P on P.PATIENT_NO = PRE.PATIENT_NO
WHERE M.MEDICATION_DESC = 'Penicillin'
ORDER BY P.AGE
FETCH FIRST 1 ROWS ONLY;

Figured it out. Thanks for all the suggestions
SELECT P.FIRST_NAME, P.LAST_NAME
FROM PATIENT AS P
WHERE P.AGE IN (
SELECT MIN(P.AGE)
FROM PATIENT AS P
WHERE P.PATIENT_NO IN(
SELECT PRE.PATIENT_NO
FROM PRESCRIPTION AS PRE
WHERE MEDICATION_CODE IN (
SELECT M.MEDICATION_CODE
FROM MEDICATION AS M
WHERE MEDICATION_DESC = 'Penicillin')));

Related

Remove duplicate rows from answer of below query

**List all directors who directed 5000 movies or more, in descending order of the number of movies they directed
The use of Distinct before d.name doesnot help.
result = pd.read_sql_query("SELECT d.name,count(*) as num
FROM PERSON d, M_DIRECTOR md
WHERE d.Pid = md.Pid
GROUP BY d.Pid,d.name
HAVING COUNT(*) >= 10
order by count(*) desc
",conn)
You must use proper explicit joins between the tables and count on distinct movies:
select
p.name,
count(distinct d.mid) num
from person p
inner join m_director d on d.pid = p.pid
inner join movie m on m.mid = d.mid
group by p.pid, p.name
having num >= 10
order by num desc
Probably you have duplicate records in Person table - people with the same name but different ids. Try to group just by name and not by id
result = pd.read_sql_query("SELECT d.name,count(*) as num
FROM PERSON d, M_DIRECTOR md
WHERE d.Pid = md.Pid
GROUP BY d.name
HAVING COUNT(*) >= 10
order by count(*) desc
",conn)

need help writing subquery

I'm using a health database and trying to display patients who have visited the health facility more than two times. The basic query I have so far is
SELECT FirstName, LastName
FROM PATIENT
I know I have to use a subquery in there somehow, but I don't know if I need to use Count or any other operators to find patients visiting more than two times.
you could use a join with visit and count for distinct(VisitDate) filtering using having for the count > 1
SELECT FirstName, LastName , count(distinct VisitDate)
FROM PATIENT
inner join VISIT on VISIT.patientID = PATIENT.PatientID
group by FirstName, LastName
having count(distinct VisitDate) > 1
use aggregate function count and having clause for comparison
SELECT P.FirstName, P.LastName,COUNT(V.VisitID) as numberOfVisit
FROM VISIT V
JOIN PATIENT P ON P.PatientID = V.PatientID
GROUP BY V.PatientID, P.FirstName, P.LastName
HAVING COUNT(V.VisitID) > 2
By using sub query you can also get same result but no need that 1st query is more appropriate
select * from (
SELECT P.FirstName, P.LastName,COUNT(V.VisitID) as numberOfVisit
FROM VISIT V
JOIN PATIENT P ON P.PatientID = V.PatientID
GROUP BY V.PatientID, P.FirstName, P.LastName
) as T where T.numberOfVisit>2
select x.FirstName,x.LastName from (
SELECT a.FirstName, a.LastName,count(*) n
FROM PATIENTa,visit b
where a.patientid = b.patientid
group by a.FirstName, a.LastName having count(*) > 2
) x

SQL explicit join filter condition

Using this relational schema, patient ID and staff ID are foreign keys with id.staff and pid.patient being unique keys:
staff(ID, fname, lname, role)
patient(pID, pFname, pLname, bdate, address, phone)
appointment(aptID, patientID, staffID, aptDate, aptTime)
procedures(procNum, pName, price)
aptDetail(aptID, procNo)
So say if I wanted to list the names of patients with appointments with a specific staff member, i.e John Smith, how would I do that explicitly?
I've managed implicitly, but I know this is kind of frowned upon, but I can't reach it without using WHERE statements.
Any help would be appreciated, any time I try and use INNER JOIN I seem to hit a wall if it's not a simple join.
Is this the type of query you're looking for?
select distinct pFname, pLname
from patient p
join appointment a on p.pID = a.patientID
join staff s on a.staffID = s.ID
where s.fname = 'John' and s.lname = 'Smith'
You can use inner join
select
a.pID
, a.pFname
, a.pLname
, a.bdate
, a.address
, a.phone
, b.aptDate
, b.aptTime
, c.fname
, c.lname
, c.role
from patient a
INNER JOIN appointment b on b.patientID = a.pID
INNER JOIN staff c on b.staffID = c.ID on concat(fname, ' ', lname ) ='John Smith'
Something like the following should work fine:
SELECT p.*
FROM appointment AS a
INNER JOIN staff AS s ON a.staffID = s.pID
INNER JOIN patient AS p ON a.patientID = p.pID
WHERE s.ID = <yourstaffid>;
select staff.fname, staff.role,
patient.pfname, plname, appoitment.aotdate
from staff, patient, appointment
where patient.pid=appointment.patientId
and staff.id=appointment.staffid

Please help this SQL query

Tables:
Doctor(doctor_id, name, address, tel, specialty)
Patient(patient_id, name, numsecu, doctor_reference)
Visit(doctor, patient, date_visit)
The question is show the patients who have seen every specialty doctors.
I do this way but I don't know how to check that the patients have seen every specialty doctors.
select distinct p.nom, m.specialite
from patient p, visite v, medecin m
where p.patient_id = v.patient
and v.medecin = m.medecin_id
group by p.nom, m.specialite
Made a bit of an assumption here that "specialty doctors" are identified by a non-null specialite column in the medecin table.
EDIT: Added JOIN to medecin in the main query to filter the visits to only specialty doctors.
SELECT p.nom
FROM patient p
INNER JOIN visite v
ON p.patient_id = v.patient
INNER JOIN medicin m
ON v.medecin = m.medecin_id
WHERE m.specialite IS NOT NULL
GROUP BY p.nom
HAVING COUNT(DISTINCT m.medecin_id) = (SELECT COUNT(*)
FROM medecin
WHERE specialite IS NOT NULL)

SQL Unique Values

I have this query that joins 3 table. It appears to be working but I am getting duplicates. How can I remove the duplicates?
SELECT FIRST 100 e.email_id, e.location_id, e.email, l.location_type, p.salutation,
p.fname, p.lname
FROM email e, location l, person p
WHERE e.location_id = l.location_id
AND l.per_id = p.per_id
The simple answer is to add DISTINCT to your query.
SELECT FIRST 100 DISTINCT e.email_id, e.location_id, e.email, l.location_type, p.salutation, p.fname, p.lname
FROM email e, location l, person p
WHERE e.location_id = l.location_id
AND l.per_id = p.per_id
use Distinct
SELECT FIRST 100 Distinct e.email_id, e.location_id,
e.email, l.location_type, p.salutation,
p.fname, p.lname
FROM email e, location l, person p
WHERE e.location_id = l.location_id AND l.per_id = p.per_id
Since you are doing straight inner joins, you only get duplicate entries in the result set if there are duplicate entries in the input tables.
SELECT FIRST 100 e.email_id, e.location_id, e.email, l.location_type, p.salutation,
p.fname, p.lname
FROM email AS e
JOIN location AS l ON e.location_id = l.location_id
JOIN person AS p ON l.per_id = p.per_id
The most likely place for there to be trouble is in the 'location' table. You could establish that with a query such as:
SELECT location_id, per_id, COUNT(*)
FROM location
GROUP BY location_id, per_id
HAVING COUNT(*) > 1;
If this returns any data, then you have a pointer to where the trouble is. You should then examine why you don't have a unique constraint on the combination of location_id, per_id.