Assistance with SQL query - sql

Suppose we have 2 tables :
Patients (ID, name)
Patients_Treatments (PatientID, treatment_code)
I would like the query to retrieve all the patients who received at least all the treatments of patient with id='999999999'
I've tried many combinations and nothing worked, all I've got is patients who got at least one of '9999999999' treatments.

One method uses a self join and comparison in the having clause:
select pt2.patientId
from patient_treatments pt join
patient_treatments pt2
on pt.treatment_code = pt2.treatment_code and pt.patientid <> pt2.patientid
where pt.id = '999999999'
group by pt2.patientId
having count(pt2.treatment_code) = (select count(*) from patient_treatments pt where pt.id = '999999999');
Note: this version assumes that there are no duplicates in Patient_Treatments.
If you have duplicates in the data, you can use count(distinct):
having count(distinct pt2.treatment_code) = (select count(distinct pt.treatment_code) from patient_treatments pt where pt.id = '999999999');

The idea is
(1) Select treatment codes belonging to patient "999999999"
(2) Select only treatment records whose treatment code matches one of the treatment codes belonging to patient "999999999"
(3) Group these by patient_id
(4) Use a HAVING statement and COUNT (DISTINCT) to select only those Patient ID's which have the same number of different treatment codes as patient "999999999".
select pt.Patient_ID,count(distinct pt.treatment_code)
from
Patient_treatments pt
inner join
(select distinct treatment_code
from
Patient_treatments pt
where pt.Patient_ID="999999999"
)t1
on t1.treatment_code=pt.treatment_code
where pt.Patient_ID<>"999999999"
group by pt.Patient_ID
having count(distinct pt.treatment_code)=
(select count(distinct treatment_code)
from
Patient_treatments pt
where pt.Patient_ID="999999999"
);
With the following schema, only patient 1 is selected:-
Create table Patient_Treatments
(
Patient_ID varchar(10),
Treatment_code varchar(10)
);
Insert into Patient_Treatments
values
("1","abc"),
("1","def"),
("1","def"),
("1","ghi"),
("2","abc"),
("2","def"),
("2","def"),
("3","ghi"),
("999999999","abc"),
("999999999","def"),
("999999999","ghi"),
("999999999","ghi")
http://sqlfiddle.com/#!9/03a84b

Related

PostgreSQL JOIN in aggregate function

Treatment table schema
id
doctor_id
location_id
patient_id
...
I need to be able to group patient treatments based on location and list all the doctors that were treating the patient for the specific location.
SELECT id,
(SELECT STRING_AGG(t.initials::text, ',') FROM (
SELECT DISTINCT treatments.doctor_id, doctors.initials FROM
treatments LEFT JOIN doctors ON doctors.id = treatments.doctor_id) t
) as treating_doctors_initials
GROUP BY treatments.patient_id, treatments.location_id
The problem is that this returns the same initials for all records -> it does perform the join I guess or maybe I am misunderstanding the aggregate function.

SQL - Select highest value when data across 3 tables

I have 3 tables:
Person (with a column PersonKey)
Telephone (with columns Tel_NumberKey, Tel_Number, Tel_NumberType e.g. 1=home, 2=mobile)
xref_Person+Telephone (columns PersonKey, Tel_NumberKey, CreatedDate, ModifiedDate)
I'm looking to get the most recent (e.g. the highest Tel_NumberKey) from the xref_Person+Telephone for each Person and use that Tel_NumberKey to get the actual Tel_Number from the Telephone table.
The problem I am having is that I keep getting duplicates for the same Tel_NumberKey. I also need to be sure I get both the home and mobile from the Telephone table, which I've been looking to do via 2 individual joins for each Tel_NumberType - again getting duplicates.
Been trying the following but to no avail:
-- For HOME
SELECT
p.PersonKey, pn.Phone_Number, pn.Tel_NumberKey
FROM
Persons AS p
INNER JOIN
xref_Person+Telephone AS x ON p.PersonKey = x.PersonKey
INNER JOIN
Telephone AS pn ON x.Tel_NumberKey = pn.Tel_NumberKey
WHERE
pn.Tel_NumberType = 1 -- e.g. Home phone number
AND pn.Tel_NumberKey = (SELECT MAX(pn1.Tel_NumberKey) AS Tel_NumberKey
FROM Person AS p1
INNER JOIN xref_Person+Telephone AS x1 ON p1.PersonKey = x1.PersonKey
INNER JOIN Telephone AS pn1 ON x1.Tel_NumberKey = pn1.Tel_NumberKey
WHERE pn1.Tel_NumberType = 1
AND p1.PersonKey = p.PersonKey
AND pn1.Tel_Number = pn.Tel_Number)
ORDER BY
p.PersonKey
And have been looking over the following links but again keep getting duplicates.
SQL select max(date) and corresponding value
How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
SQL Server: SELECT only the rows with MAX(DATE)
Am sure this must be possible but been at this a couple of days and can't believe its that difficult to get the most recent / highest value when referencing 3 tables. Any help greatly appreciated.
select *
from
( SELECT p.PersonKey, pn.Phone_Number, pn.Tel_NumberKey
, row_number() over (partition by p.PersonKey, pn.Phone_Number order by pn.Tel_NumberKey desc) rn
FROM
Persons AS p
INNER JOIN
xref_Person+Telephone AS x ON p.PersonKey = x.PersonKey
INNER JOIN
Telephone AS pn ON x.Tel_NumberKey = pn.Tel_NumberKey
WHERE
pn.Tel_NumberType = 1
) tt
where tt.rn = 1
ORDER BY
tt.PersonKey
you have to use max() function and then you have to order by rownum in descending order like.
select f.empno
from(select max(empno) empno from emp e
group by rownum)f
order by rownum desc
It will give you all employees having highest employee number to lowest employee number. Now implement it with your case then let me know.

SQL table select

I have two tables:
Patients where I have patient_ID as primary key and other details.
Patients_Treatments where I have patient_ID from Patients as foreign key, treatment_code, and other columns.
I am requested to find all the patient's treatment codes that have the same treatment_code as patient whose id is 999.
I'm sitting for two days trying to find a solution and I just can't manage to think of something. It seems simple but I just can't find a solution.
Example:
The expected output are the details (Details means first name, last name, and patient ID) of: Tal Shalom Dan Shabtay Elad Gigi
If you are looking for the Treatment_Code and Patient information for the patients that share a Treatment_Code belonging to Patient_Id: 999, this should get you those results:
Select T.Treatment_Code, P.First_Name, P.Last_Name, P.Patient_Id
From Patients_Treatments T
Join Patients P On P.Patient_Id = T.Patient_Id
Where T.Patient_Id In
(
Select T1.Patient_Id
From Patients_Treatments T
Join Patients_Treatments T1 On T1.Treatment_Code = T.Treatment_Code
And T1.Patient_ID <> T.Patient_Id
Where T.Patient_Id = 999
)

Adding 0 or null to missing fields

I have the following tables:
student(sid, sname)
teacher(tid, tname)
enrollment(sid, cid, tid)
course(cid, course)
rank(sid, tid, grade, date, valid)
I need to calculate the average grade of all the teachers (data is in rank table), when only the grade from the most recent date counts (and if it's invalid - ignore it).
I wrote the following query, and it's working nice. The problem is that I also need the average for ALL the teachers, including those who were not ranked yet/their rank is invalid (their average grade will be 0 in that case, and I'll have to count their students like I did for the others).
I think it's something with LEFT OUTER JOIN, but all the examples I see online have only two tables in FROM, and I can't figure out the right syntax in my case.
SELECT teacher.tid,
tname,
AVG(grade) AS avgGrade,
COUNT(DISTINCT enrollment.sid) AS studCount
FROM rank,
teacher,
enrollment,
( SELECT rank.sid, rank.tid, MAX(date) AS maxDate
FROM rank
GROUP BY sid, tid
) lastGrades
WHERE teacher.tid=enrollment.tid
AND rank.tid=teacher.tid
AND rank.tid=lastGrades.tid
AND rank.sid=lastGrades.sid
AND rank.date=lastGrades.maxDate
AND valid = TRUE
GROUP BY teacher.tid, tname
You could use a subquer to look up the latest rank per (teacher, student) combination. Use a left join to count enrollments that have not been ranked:
select t.tid
, t.tname
, avg(r.grade) as AverageRank
, count(distinct e.sid) as StudentCount
from teacher t
join enrollment e
on t.tid = e.tid
left join
rank r
on r.tid = t.tid
and r.sid = e.sid
and r.valid = true
and r.date =
(
select max(date)
from rank r2
where r2.sid = r.sid
and r2.tid = r.tid
and r2.valid = true
)
group by
t.tid
, t.tname
Example without data at SQL Fiddle.
The table design is kind of strange. You'd expect a student to enroll in a course, not in a teacher!

Find the latest date of two tables with matching primary keys

I have two tables tables, each with primary keys for different people and the contact dates in each category.I am trying to find the most recent contact date for each person, regardless of what table its in. For example:
CustomerService columns: CustomerKey, DateContacted
CustomerOutreach columns: CustomerKey, DateContacted
And I'm just trying to find the very latest date for each person.
Use something like this.
You need to combine the two tables. You can do this by a union. There will be duplicates, but you just group by the customerKey and then find the Max DateContacted
SELECT * INTO #TEMP FROM (
SELECT
CustomerKey
, DateContacted
FROM CustomerService CS
UNION
SELECT
CustomerKey
, DateContacted
FROM CustomerOutreach CS
)
SELECT
CustomerKey
, MAX(DateContacted)
FROM #TEMP
GROUP BY
CustomerKey
Join your tables on primary keys and make a conditional projection.
Select cs.CustomerKey,
CASE WHEN cs.DateContacted <= co.DateContacted
THEN co.DateContacted
ELSE cs.DateContacted END
from CustomerService cs inner join CustomerOutreach co
on cs.CustomerKey = co.CustomerKey
I would do something like this.
Select b.customerKey, b.dateContacted
from (
select a.customerKey, a.DateContacted, Row_Number() over (Partition by customerKey order by DateContacted desc) as RN
from (
Select c.customerKey,
case when (s.DateContacted > o.dateContacted) then s.dateContacted else o.datecontacted end as DateContacted
from Customer c
left outer join customerService s on c.customerKey = s.customerKey
left outer join customerOutreach o on c.customerKey = s.customerKey
where s.customerKey is not null or o.customerKey is not null
)a
)b
where b.RN = 1
This solution should take care of preventing the case of having duplicates if both tables have the same max DateContacted.
http://sqlfiddle.com/#!3/ca968/1