搜索其子级符合谓词的父记录

时间:2013-03-06 20:33:18

标签: sql sqlite

假设我有一个父数据库和子数据库,并且孩子会保留一些父母发生的事情的运行记录:

create table patient (
   fullname text not null,
   admission_number integer primary key
);

create table history (
   note text not null,
   doctor text not null,
   admission_number integer references patient (admission_number)
);

(只是一个例子,我没有做医疗申请)。

history将有相同admission_number的许多记录:

admission_number      doctor    note
------------------------------------
3456                  Johnson   Took blood pressure
7828                  Johnson   EKG 120, temp 99.2
3456                  Nichols   Drew blood
9001                  Damien    Discharged patient
7828                  Damien    Discharged patient with Rx

所以,我的问题是,我如何构建一个查询,让我可以和/或/不搜索patient记录的注释字段,例如,如果我想查找每个患者的历史包含“血压”和“出院”。

现在我一直在selecthistoryadmission_number分组,将所有注释与group_concat(note)合并,然后在{{{{}}进行搜索1}},因此:

having

这是有效的,但它使得某些细节非常复杂 - 例如,我希望能够提出诸如“每个患者的历史都包含”血压“和Damien博士的病史说”出院的事情, “在我的基本查询之上建立这样的资格非常混乱。

有没有更好的方法来表达我的基本查询?

3 个答案:

答案 0 :(得分:1)

为什么不使用JOIN操作?

e.g。 考虑到,患者表包含以下数据:

INSERT INTO patient VALUES('Bob', 3456);
INSERT INTO patient VALUES('Mary', 7828);
INSERT INTO patient VALUES('Lucy', 9001);

运行查询:

SELECT DISTINCT p.fullname, p.admission_number FROM patient p
INNER JOIN history h ON p.admission_number = h.admission_number
WHERE note LIKE '%blood pressure%' OR note LIKE '%Discharged%';

得到你:

fullname = Bob
admission_number = 3456

fullname = Lucy
admission_number = 9001

fullname = Mary
admission_number = 7828

并运行以下查询:

SELECT DISTINCT p.fullname, p.admission_number FROM patient p
INNER JOIN history h ON p.admission_number = h.admission_number
WHERE note LIKE '%blood pressure%';

得到你:

fullname = Bob
admission_number = 3456

答案 1 :(得分:1)

我有一些东西 - 使用EXISTS来构建这些更简洁:

select * from patients where 
    exists ( 
      select 1 from history where
        history.admission_number == patients.admission_number
        AND
        history.note LIKE '%blood pressure%'
    )
    AND
    exists (
        select 1 from history where
        history.admission_number == patients.admission_number
        AND 
        history.note LIKE '%discharged%'
        AND
        history.doctor == 'Damien'
    );

那好多了,现在我可以构建非常细粒度的谓词。

答案 2 :(得分:1)

这与您的EXISTS方法类似,但以不同方式计算子查询。 这可能会更快,也可能不会更快,具体取决于表和索引的组织方式,以及查询的选择性。

SELECT *
FROM patient
WHERE admission_number IN (SELECT admission_number
                           FROM history
                           WHERE note LIKE '%blood pressure%')
  AND admission_number IN (SELECT admission_number
                           FROM history
                           WHERE note LIKE '%discharged%'
                             AND doctor = 'Damien')

或者,您可以使用compound subquery(计算交叉点一次可能比为每条记录执行IN两次更快):

SELECT *
FROM patient
WHERE admission_number IN (SELECT admission_number
                           FROM history
                           WHERE note LIKE '%blood pressure%'
                           INTERSECT
                           SELECT admission_number
                           FROM history
                           WHERE note LIKE '%discharged%'
                             AND doctor = 'Damien')