2011-04-13 56 views
3

我有我一直在承包工作中的應用非常惱人的問題。許多一對多的關係SELECT問題

數據庫結構,我不能兼容的原因修改是一塌糊塗。它基本上是多對多對多對多的關係。它是這樣的:

接觸

--------------------------- 
| contact_id | name | ... | 
--------------------------- 
| 1   | foo |  | 
--------------------------- 

metadefinition

----------------------------- 
| metadefinition_id | name | 
----------------------------- 
| 1     | title | 
----------------------------- 
| 2     | job | 
----------------------------- 

contact_metadata

---------------------------- 
| contact_id | metadata_id | 
---------------------------- 
| 1   | 1   | 
---------------------------- 
| 1   | 2   | 
---------------------------- 

------------------------------------------- 
| metadata_id | metadefinition_id | value | 
------------------------------------------- 
| 1   | 1     | mrs | 
------------------------------------------- 
| 2   | 2     | coder | 
------------------------------------------- 

因此,對於單個聯繫人,我想搜索關於這一切,並獲得這樣的:

----------------------------------------------------- 
| contact_id | name | metadata.title | metadata.job | 
----------------------------------------------------- 
| 1   | foo | mrs   | coder  | 
----------------------------------------------------- 

所以,現在是我到目前爲止已經試過。我可以提前獲取metadefinition的列表,這不是一個真正的問題。所以我建立這樣的查詢:

SELECT contact.*,m1.value AS `metadata.title` FROM contact 
    LEFT JOIN contact_metadata ON contact.contact_id = contact_metadata.contact_id 
    LEFT JOIN metadata m1 ON contact_metadata.metadata_id = m1.metadata_id AND m1.metadefinition_id = 1 
    GROUP BY contact_id 

這適用於單個metadefinition,我得到的是這樣的:

-------------------------------------- 
| contact_id | name | metadata.title | 
-------------------------------------- 
| 1   | foo | mrs   | 
-------------------------------------- 

如果我嘗試有兩個,但是:

SELECT contact.*,m1.value AS `metadata.title`,m2.value AS `metadata.job` FROM contact 
    LEFT JOIN contact_metadata ON contact.contact_id = contact_metadata.contact_id 
    LEFT JOIN metadata m1 ON contact_metadata.metadata_id = m1.metadata_id AND m1.metadefinition_id = 1 
    LEFT JOIN metadata m2 ON contact_metadata.metadata_id = m2.metadata_id AND m2.metadefinition_id = 2 
    GROUP BY contact_id 

我得到:

----------------------------------------------------- 
| contact_id | name | metadata.title | metadata.job | 
----------------------------------------------------- 
| 1   | foo | mrs   | NULL   | 
----------------------------------------------------- 

如果我除去GROUP BY子句,當然,我得到:

----------------------------------------------------- 
| contact_id | name | metadata.title | metadata.job | 
----------------------------------------------------- 
| 1   | foo | mrs   | NULL   | 
----------------------------------------------------- 
| 1   | foo | NULL   | coder  | 
----------------------------------------------------- 

我接受任何東西只要查詢時間相對可以接受的(考慮到結構,如果需要10秒100000個記錄它的更好比什麼都沒有)

請問,它是臨時表,存儲過程,我不在乎,只要我不必更改實際的數據庫結構。

相信我,當它將是改造的時候,我很高興把這整個事情放下。

有沒有解決方案,這是可能的嗎?

在此先感謝。

+1

由於MySQL不直接支持[數據透視表](http://msdn.microsoft.com/en-us/library/ms177410.aspx),你將不得不作出的觀點手動創建樞紐([例子](http://en.wikibooks.org/wiki/MySQL/Pivot_table))。請記住,此數據結構沒有任何問題(請參見[規範化](http://en.wikipedia.org/wiki/Database_normalization))。它非常靈活,但在某些情況下可能很難使用。 – 2011-04-13 16:13:52

+1

你沒有給我們足夠的信息來弄清楚你實際上正在做什麼。我沒有看到表結構的問題。這些結果看起來像我期望他們。你想在結果中表現什麼? – 2011-04-13 16:22:22

+0

@ Neil D:看來你沒有看完整個問題。我擁有的所有信息都在:數據庫結構,實際結果,預期結果。如果你仔細閱讀,你可以清楚地看到我得到的結果不是我想要的。至於數據庫結構,它顯然對於它正在嘗試做的事情有點矯枉過正。 – netcoder 2011-04-13 16:39:09

回答

6

我會使用一對相關的子查詢。這裏像

SELECT c.* 
    ,(Select value from metadata m1 
     INNER JOIN contact_metadata cm 
     on cm.metadata_id = m1.metadata_id 
    WHERE m1.metadefinition_id = 1 
     AND cm.contact_id = c.contact_id)AS `metadata.title` 
    ,(Select value from metadata m1 
     INNER JOIN contact_metadata cm 
     ON cm.metadata_id = m1.metadata_id 
    WHERE m1.metadefinition_id = 2 
     AND cm.contact_id = c.contact_id)AS `metadata.job` 
FROM contact c 
WHERE c.contact_id = 1 
+0

@Kevin Peno感謝編輯老兄。 – JustABitOfCode 2011-04-13 16:23:02

+0

謝謝你做到了。現在我需要弄清楚如何在Zend_Db中完成這項工作...呃。至少這個問題是固定的。 – netcoder 2011-04-13 18:38:15

4

您需要將每個元數據項目(標題,作業等)作爲單獨的子查詢獲取,然後加入contact_id以將這些元數據項目彙總到每個聯繫人。就像這樣:

SELECT contact.*, metadata_title, metadata_job FROM contact 
INNER JOIN 
(SELECT contact_id,m.value AS `metadata_title` FROM contact_metadata 
    LEFT JOIN metadata m ON contact_metadata.metadata_id = m.metadata_id AND m.metadefinition_id = 1) metaTitle ON metaTitle.contact_id=contact.contact_id 
INNER JOIN 
(SELECT contact_id,m.value AS `metadata_job` FROM contact_metadata 
    LEFT JOIN metadata m ON contact_metadata.metadata_id = m.metadata_id AND m.metadefinition_id = 2) metaJob ON (metaJob.contact_id=contact.contact_id) 

如果你想允許對不具有特定的元數據項的客戶端的可能性,使用LEFT JOINs相反,截至目前,該查詢將只返回同時擁有工作和標題客戶定義。

+0

+1,使它成爲一個'VIEW',並像表格一樣查詢它。 – 2011-04-13 16:18:38

0

現在,我終於正確讀取的問題,是我的兩分錢,什麼是它的價值(沒有雙關語意)。

SELECT contact.contact_id, contact.name, m1.value AS 'metadata.title', m2.value AS 'metadata.job'  
FROM dbo.contact 
INNER JOIN dbo.contact_metadata cm1 ON cm1.contact_id = cm1.contact_id 
INNER JOIN dbo.metadata m1 ON cm1.metadata_id = m1.metadata_id AND m1.metadefinition_id = 1 
INNER JOIN dbo.contact_metadata cm2 ON contact.contact_id = cm2.contact_id 
INNER JOIN dbo.metadata m2 ON cm2.metadata_id = m2.metadata_id AND m2.metadefinition_id = 2