我有一个名为medicine的表和一个名为Medication_symptoms的相关子表
医学
MediId, Name
1, MedA
2, MedB
3, MedC
Medication_symptoms
MedSympId, Medicine (MedId), Symptom (symptomId)
1, MedA (1), Symptom A (1)
2, MedA (1), Symptom B (2)
3, MedB (2), Symptom B (2)
4, MedB (2), Symptom C (3)
5, MedC (3), Symptom D
我有另一张名为Patient and Patient_Symptoms的表
病人
PatientId, Name
1, Patient A
2, Patient B
3, Patient C
4, Patient D
Patient_Symptom
PatientSymptomId, PatientId, SymptomId
1, Patient A(1), Symptom A (1)
2, Patient A(1), Symptom B (2)
3, Patient B(2), Symptom B (2)
4, Patient B(2), Symptom D (4)
5, Patient D(4), Symptom D (4)
鉴于上述信息,我需要得到符合患者所有症状的药物:(我会逐个拉1个患者的信息)
Patient A - Med A (as he has symptom a and b and Med is for symptom A and B)
Patient B - None! (as he has symptoms b and d and there is no medicine for symptoms B and D)
Patient D - Med C (as med C is for symptom D only and Patient D has only symptom D)
注意症状是一个单独的表:
症状
Symptom Id, Name
1, Symptom A
2, Symptom B
3, Symptom C
4, Symptom D
5, Symptom E
什么是这样的查询?
注意:我已经编写了这个例子。在我正在做的事情中,我有一个记录A,带有一组属性(其中属性存储为记录A的记录行)。我需要将该记录A与另一个记录C匹配,该记录与A具有完全相同的属性集。(有意义吗?)
中的脚本创建表格和一些示例数据答案 0 :(得分:5)
您可以将not exists
和full join … null
结合起来选择所有不会 - 不是 - (双阴性)药物治疗患者症状的药物 - 因此该药物确实具有所有治疗方法
select * from medicine m
where not exists (
select 1 from patient_symptom ps
full join medication_symptoms ms on ps.SymptomId = ms.SymptomId
and ps.PatientId = :myPatientIdHere
and ms.MedId = m.MedId
where (ms.SymptomId is null or ps.symptomId is null)
)
使用条件聚合排除任何不治疗患者症状的药物的另一种方法
select ms.MedId
from patient_symptom ps
join medication_symptoms ms on ps.SymptomId = ms.SymptomId
where ps.patientId = :myPatientIdHere
group by ms.MedId, ps.patientId
having count(ms.symptomId) = (select count(*) from patient_symptom ps2
where ps2.patientId = ps.patientId)
and count(ms.symptomId) = (select count(*) from medication_symptoms ms2
where ms2.MedId = ms.MedId)
<强>更新强>
如果您使用full join
,则可以使用条件聚合来确保完整联接的任何一侧都没有空值,以确保“1:1匹配”。
select t1.MedId
from (
select * from
patient_symptom ps
cross join medicine m
where patientId = :myPatientId
) t1
full join medication_symptoms ms on t1.SymptomId = ms.SymptomId
and t1.MediId = ms.MediId
group by t1.MedId
having count(case when t1.SymptomId is null or ms.SymptomId is null then 1 end) = 0
答案 1 :(得分:2)
FuzzyTree发布了多个答案。这是他的第一个查询,包含了我必须进行的所有更改才能使其工作。他的查询#2也有效。
SELECT *
FROM medicine m
WHERE NOT EXISTS (
SELECT 1
FROM (
SELECT ms.symptomId
FROM Medication_Symptoms ms
WHERE ms.medId = m.medid
) ms1
FULL JOIN (
SELECT ps.SymptomId
FROM Patient_Symptom ps
WHERE ps.PatientId = 7
) ps1 ON ps1.SymptomId = ms1.SymptomId
WHERE (
ps1.SymptomId IS NULL
OR ms1.symptomId IS NULL
)
)
我们发现以下查询比上面的查询更快(这是由同事发现并查看挂钟时间和查询计划,这个更快)< / p>
select m.Name
from Medicine m
where m.Id in (
select ms.MedicineId
from Medication_Symptom ms
inner join (select SymptomId
from Patient_Symptom
where PatientId = 7) ps on ps.SymptomId = ms.SymptomId
group by ms.MedicineId
having count(*) = (select count(SymptomId)
from Patient_Symptom
where PatientId = 7)
intersect
select ms.MedicineId
from Medication_Symptom ms
group by ms.MedicineId
having count(*) = (select count(SymptomId)
from Patient_Symptom
where PatientId = 7)
)
最后,此查询返回所有患者的数据:
select po.Name, m.Name
from Medicine m, patient po
where m.Id in (
select ms.MedicineId
from Medication_Symptom ms
inner join (select SymptomId
from Patient_Symptom
where PatientId = po.Id) ps on ps.SymptomId = ms.SymptomId
group by ms.MedicineId
having count(*) = (select count(SymptomId)
from Patient_Symptom
where PatientId = po.Id)
intersect
select ms.MedicineId
from Medication_Symptom ms
group by ms.MedicineId
having count(*) = (select count(SymptomId)
from Patient_Symptom
where PatientId = po.Id)
)