2015-04-17 95 views
2

A Person可以有许多Degree记录。hasMany关系的潜在复杂查询;这可以做到吗?

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

(编辑:我已经隐藏了简单许多额外的字段)

+----------+-------------------------------+------+-----+---------+----------------+ 
| 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'度。

我正在努力如何将这些要求纳入查询。对于第一个要求,主查询需要事先知道用户拥有什么程度。我需要一个子查询吗?

规则还需要参与主查询(以及加载度数的第二个查询)。

+0

只是一个小评论,这是列,而不是场... – jarlh

+0

我只是复制从MySQL的'describe'命令 – Brian

+0

哈哈输出,对不起......不知道他们有自己的条件... – jarlh

回答

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” /“博士”的问题增加了一些并发症:

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 
+0

“度”表比我显示的要复杂得多,所以除了类型外(还有年份,论文等),所以我不认为你提供的第一个查询会适用,因为我需要为每个学位提供更多信息 – Brian

+0

我会使用HAVING INSTR(group_concat(d。类型),'MA')> 0 AND INSTR(group_concat(d.type),'phd')= 0(或与LOCATE相同) – StanislavL

+0

@StanislavL。 。 。没有理由做一个'group_concat()',这是一个比简单的'sum()'更昂贵的操作。 –

0

答案是基于戈登·利诺夫的答案。

您可以使用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