2009-12-23 72 views
1

我正在處理一個包含人員的MySQL數據庫。我的問題是,(我將簡化,使我的觀點):簡單的MySQL問題

我有三個表:

Persons(id int, birthdate date) 
PersonsLastNames(id int, lastname varchar(30)) 
PersonsFirstNames(id int, firstname varchar(30)) 

id是公共密鑰。對於姓氏和名字,有單獨的表格,因爲一個人可以有許多名字和許多姓氏。

我想做一個查詢,返回所有人,比如說,一個姓。如果我有

select birthdate, lastname, firstname from Persons, PersonsLastNames, 
PersonsFirstNames where Persons.id = PersonsLastNames.id and 
Persons.id = PersonsFirstNames.id and lastName = 'Anderson' 

去我最終喜歡

1/1/1970 Anderson Steven //Person 1 
1/1/1970 Anderson David //Still Person 1 
2/2/1980 Smith Adam  //Person 2 
3/3/1990 Taylor Ed  //Person 3 

當呈現這樣的表,我想有

1/1/1970 Anderson Steven David 
2/2/1980 Smith Adam [possibly null?] 
3/3/1990 Taylor Ed [possibly null?] 

如何加入表推陳出新結果集中的列是否需要爲一個人保存幾個名字或姓氏?

+0

這是什麼實際應用?一個人什麼時候有多個姓和名?由於你描述的關係是多對多的,所以你要找的結果可以有任意數量的列。 – Ken 2009-12-23 02:10:40

+0

@Ken - 它可以存在於「已知別名」意義上。 – Dereleased 2009-12-23 02:22:10

+0

您可能會考慮將此問題重命名爲「MySQL - 如何從JOIN返回動態列?」幫助未來的人們尋找類似的問題。 – philfreo 2009-12-23 02:27:12

回答

1

您的應用程序真的需要處理每人無限的名/姓?我不知道你的具體需求,但看起來可能有點極端。而不管...

既然你不能真的有返回的列的動態數量,你可以做這樣的事情:

SELECT birthdate, lastname, GROUP_CONCAT(firstname SEPARATOR '|') AS firstnames 
FROM Persons, PersonsLastNames, PersonsFirstNames 
WHERE Persons.id = PersonsLastNames.id 
AND Persons.id = PersonsFirstNames.id 
GROUP BY Persons.id 

這將每有一個姓氏的人返回一行,與(無限制)由管道(|)符號分隔的名字,GROUP_CONCAT函數。

birthdate    lastname firstnames 
---     ---  --- 
1970-01-01 00:00:00 Anderson Steven|David 
1980-02-02 00:00:00 Smith  Adam 
1990-03-03 00:00:00 Taylor  Ed 
+1

是的GROUP_CONCAT使我想要的輸出!謝謝!有多達800萬人的數據庫效率如何? – 2009-12-23 02:45:51

+0

我假設你實際上每個人都不會有很多名字,甚至10個也會很多,對吧?如果是這樣的話,我相信GROUP_CONCAT函數不會有任何性能問題,相反它會是簡單的連接和分組。有了正確的指數,我認爲這應該沒問題。注意:一定要看看'group_concat_max_len'設置。 – philfreo 2009-12-23 03:19:18

1

SQL不支持查詢選擇列表中的動態列數。您必須準確定義儘可能多的列(儘管有*通配符)。

我建議您將多個名稱作爲而不是列。然後編寫一些應用程序代碼來遍歷結果集,並做出想要做的任何事情來呈現結果集。

1

簡短的回答是,你不能。你總是必須選擇固定數量的列。但是,通過使用ON關鍵字,可以大大改進查詢的語法。例如:

SELECT 
    birthdate, 
    firstName, 
    lastName 
FROM 
    Persons 
    INNER JOIN PersonsLastNames 
     ON Persons.id = PersonsLastNames.id 
    INNER JOIN PersonsFirstNames 
     ON Persons.id = PersonsFirstNames.id 
WHERE 
    lastName = 'Anderson' 
GROUP BY 
    lastName, firstName 
HAVING 
    count(lastName) = 1 

當然,我查詢包括在最後,只有擁有隻有一個特定的姓氏的人會抓住一些額外的規定,但你總是可以刪除這些文件。

現在,你可以做的就是選擇其中一個最大數量要檢索和做這樣的事情:

SELECT 
    birthdate, 
    lastName, 
    PersonsFirstNames.firstName, 
    IFNULL(p.firstName,''), 
    IFNULL(q.firstName,'') 
FROM 
    Persons 
    INNER JOIN PersonsLastNames 
     ON Persons.id = PersonsLastNames.id 
    INNER JOIN PersonsFirstNames 
     ON Persons.id = PersonsFirstNames.id 
    LEFT JOIN PersonsFirstNames p 
     ON Persons.id = p.id 
     AND p.firstName <> PersonsFirstNames.firstName 
    LEFT JOIN PersonsFirstNames q 
     ON Persons.id = q.id 
     AND q.firstName <> PersonsFirstNames.firstName 
     AND q.firstName <> p.firstName 
GROUP BY 
    lastName 

但我真的不建議。最好的辦法是檢索多行,然後在您使用/開發的任何應用程序中迭代它們。

請確保在開始之前閱讀了JOIN類型(左對內),如果您還不熟悉的話。希望這可以幫助。

編輯:在這種情況下,您可能還想考慮一個稍微複雜的GROUP BY子句,例如,

GROUP BY 
    Persons.id, lastName