获取包含所有子记录的记录

时间:2015-08-17 23:37:41

标签: sql sql-server

我有一个名为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具有完全相同的属性集。(有意义吗?)

您可以使用http://pastebin.com/kaqdtHf3

中的脚本创建表格和一些示例数据

2 个答案:

答案 0 :(得分:5)

您可以将not existsfull 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)
    )