簡體   English   中英

多對多關系SELECT問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM