hasMany关系的潜在复杂查询;可以这样做吗?

时间:2015-04-17 13:55:40

标签: mysql sql

Person可以有多条Degree条记录。

+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| firstName | varchar(60)  | NO   |     | NULL    |                |
| lastName  | varchar(100) | NO   |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+

Degree (编辑:为了简单起见,我隐藏了许多其他字段)

+----------+-------------------------------+------+-----+---------+----------------+
| Field    | Type                          | Null | Key | Default | Extra          |
+----------+-------------------------------+------+-----+---------+----------------+
| id       | int(11)                       | NO   | PRI | NULL    | auto_increment |
| personID | int(11)                       | NO   | MUL | NULL    |                |
| type     | enum('PhD','MSE','MEng','MA') | NO   |     | NULL    |                |
+----------+-------------------------------+------+-----+---------+----------------+

在网页上,我想显示人员及其学位信息的列表(除了他们的类型之外,还有其他信息,我只是为了简单而没有包含它)。我相信这必须在N + 1个查询中完成。首先,选择所有具有学位的人的查询:

SELECT DISTINCT person.id
FROM person
JOIN degree ON degree.personID = person.id

然后在迭代每个结果时,直接查询他们的学位:

SELECT * FROM degree WHERE personID = :personID

然而,我的生活并非那么简单。我有两个额外的要求:

  1. 允许根据学位过滤页面。例如:“仅向具有'MA'学位的人展示”,“仅向具有'MSE'学位的人展示。”
  2. 如果此人没有“博士”学位,则仅显示“MA”学位。
  3. 我正在努力将这些要求纳入查询。对于第一个要求,主查询需要事先知道用户具有的程度。我在这里需要一个子查询吗?

    规则也需要以某种方式涉及主查询(以及加载度数的第二个查询)。

2 个答案:

答案 0 :(得分:2)

您不需要多次查询。我假设您想要列表中的度数,例如:

SELECT p.id, group_concat(d.type)
FROM person p JOIN
     degree d
     ON d.personID = p.id
GROUP BY p.id

对于过滤,您可以使用having。例如,以下内容总是会返回博士学位:

HAVING sum(d.degree = 'phd') > 0

" MA" /" PhD"问题增加了一些复杂性:

SELECT p.id,
       (case when sum(d.degree = 'phd') > 0
             then group_concat(case when d.type <> 'ma' then d.type end)
             else group_concat(d.type)
        end) as degrees
FROM person p JOIN
     degree d
     ON d.personID = p.id
GROUP BY p.id

答案 1 :(得分:0)

答案是基于Gordon Linoff的回答。

您可以使用Gordon的方法首先过滤掉人(在子查询中),然后在一个查询中加入他们的学位。

SELECT degree.* 
FROM degree JOIN
    (SELECT p.id as personID, group_concat(d.type) as deg_info
    FROM person p JOIN
         degree d
         ON d.personID = p.id
    GROUP BY p.id
    HAVING INSTR(deg_info, 'MA')>0 
           AND INSTR(deg_info, 'phd')=0) filter ON degree.personId=filter.personID