[英]Many-to-many relationship SELECT issue
我已經簽約工作的應用程序有一個非常煩人的問題。
由於兼容性原因我無法修改的數據庫結構很亂。 它基本上是一個多對多,多對多,一對一的關系 。 它是這樣的:
聯系
---------------------------
| 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 |
-----------------------------------------------------
只要查詢時間相對可接受,我就可以接受任何事情(考慮到結構,如果100000條記錄需要10秒鍾,那么它總比沒有好)
是不是臨時表,存儲過程,我不在乎,只要我不用改變實際的數據庫結構。
相信我,當它成為改造的時候,我很高興把整件事搞砸。
有解決方案嗎,有可能嗎?
提前致謝。
我使用了一對相關的子查詢。 就像是
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
您需要將每個元數據項(標題,作業等)作為單獨的子查詢獲取,然后加入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
,因為目前,查詢只返回同時定義了作業和標題的客戶端。
現在我終於正確地閱讀了這個問題,這是我的兩分錢,因為這是值得的(沒有雙關語意)。
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.