2015-04-17 36 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