2013-05-17 62 views
2

我開始在這裏: MySQL select one field from table WHERE condition is in multiple rowsMySQL的從屬性表中選擇一個字段WHERE條件是多行

這工作得很好 - 謝謝!

額外的複雜性是,我需要在一個搜索中搜索多個屬性內的

這是數據快照。該attribute_ids是:

1 - language 
18 - phone1 
19 - phone2 
20 - phone3 

的樣本數據

 
+-----+------------+--------------+------------------------+ 
| id | contact_id | attribute_id | stored_attribute_value | 
+-----+------------+--------------+------------------------+ 
| 15 |   1 |   1 | english    | 
| 83 |   5 |   1 | english    | 
| 153 |   9 |   1 | english    | 
| 197 |   11 |   1 | english    | 
| 250 |   3 |   1 | english    | 
| 267 |   13 |   1 | tagalog    | 
| 303 |   15 |   1 | spanish    | 
| 374 |   19 |   1 | spanish    | 
| 469 |   17 |   1 | spanish    | 
| 490 |   21 |   1 | spanish    | 
| 507 |   7 |   1 | english    | 
| 9 |   1 |   18 | 983-296-3660   | 
| 77 |   5 |   18 | 123-300-3985   | 
| 147 |   9 |   18 | 215-857-7105   | 
| 191 |   11 |   18 | 123-216-8501   | 
| 244 |   3 |   18 | 478-786-4450   | 
| 261 |   13 |   18 | 802-118-7211   | 
| 297 |   15 |   18 | 998-370-4612   | 
| 367 |   19 |   18 | 203-435-4023   | 
| 463 |   17 |   18 | 945-519-5355   | 
| 481 |   21 |   18 | 425-675-8912   | 
| 501 |   7 |   18 | 123-712-6946   | 
| 11 |   1 |   19 | 123-653-3722   | 
| 79 |   5 |   19 | 396-609-5772   | 
| 149 |   9 |   19 | 261-899-1470   | 
| 193 |   11 |   19 | 673-452-9545   | 
| 246 |   3 |   19 | 760-700-5826   | 
| 263 |   13 |   19 | 123-701-7931   | 
| 299 |   15 |   19 | 123-445-5874   | 
| 369 |   19 |   19 | 711-657-8183   | 
| 465 |   17 |   19 | 123-130-2816   | 
| 483 |   21 |   19 | 123-391-1234   | 
| 503 |   7 |   19 | 123-568-1263   | 
| 485 |   21 |   20 | 123-428-6610   | 
+-----+------------+--------------+------------------------+ 

所以,如果我是尋找與語言 '英語' 的所有聯繫人和PHONE1像 '123%',查詢將是:

SELECT `contact_id` 
FROM (`contact_attribute_value`) 
WHERE (`attribute_id` = '18' AND `stored_attribute_value` LIKE '123%') 
OR (`attribute_id` = '1' AND `stored_attribute_value` = 'english') 
GROUP BY `contact_id` HAVING COUNT(*) = 2 

而且我會得到3結果返回:5,7,和11這是正確的。

挑戰是我想在搜索界面中創建一個通用電話字段,這樣如果用戶搜索電話號碼,他們將同時搜索所有三個電話字段。

所以,我寫了下面的查詢:

SELECT `contact_id` 
FROM (`contact_attribute_value`) 
WHERE (`attribute_id` = '18' AND `stored_attribute_value` LIKE '123%') 
OR (`attribute_id` = '19' AND `stored_attribute_value` LIKE '123%') 
OR (`attribute_id` = '20' AND `stored_attribute_value` LIKE '123%') 
OR (`attribute_id` = '1' AND `stored_attribute_value` = 'english') 
GROUP BY `contact_id` HAVING COUNT(*) = 2 

概念的作品,但也有在它打破了條件。

第一個條件是當一個聯繫人的語言爲'english'並且兩個電話號碼匹配'123%'時。在這裏,聯繫人的計數爲3,並且不顯示在結果中。

第二種情況是當聯繫人的語言不等於「英語」,並且有兩個電話號碼匹配時,如「123%」。在這種情況下,聯繫人的計數爲2,並顯示在結果中,但這不是我們所期望的。

我確定在這種情況下,這些條件有一個「硬編碼」的陷印方式,但屬性和可能的​​搜索集合相當大,所以我需要一個可通用的解決方案。

在此先感謝!

回答

1

只是考慮到你的榜樣,你解釋的情況下,我會說,最簡單的方法來解決這個而不做兩個查詢與子查詢:

SELECT DISTINCT contact_id 
FROM contact_attribute_value AS c 
WHERE c.attribute_id IN (18, 19, 20) 
AND c.stored_attribute_value LIKE '123%' 
AND EXISTS (SELECT * 
      FROM contact_attribute_value AS c1 
      WHERE c1.contact_id = c.contact_id AND c1.attribute_id = 1 
      AND c1.stored_attribute_value = 'english') 

與此查詢,首先我們檢查聯繫人是否有以123開頭的任何數字,然後子查詢負責檢查聯繫人是否有英語作爲他的語言。

DISTINCT關鍵字刪除重複,所以不再需要分組。

+0

不錯的一個。所以如果我要添加另一個屬性,我需要添加另一個子查詢,例如地址。事實上,我可以把我所有的條件放在他們自己的子查詢中。我試了一下,它的工作原理。我假設每個子查詢的性能都是成本的。 –

+0

對於您的查詢中的每個* orthogonal *屬性,您需要額外的子查詢,是的。是的,他們被認爲是昂貴的,但idk多少錢。您可能想要確定您擁有的不同選項的時間,以便更好地瞭解性能。您的模式似乎很好地概括了一些東西並節省了空間,但對於您公開的問題,最好將其規範化,這將使您的查詢更容易設計(除非您有其他理由保留當前模式)。 – asermax

+0

ok - 因此在運行一些測試之後,看起來這個模式的子查詢比group/having結構更快。考慮到數據的性質以及它在整個應用程序中的重用,這個模式是最合理的。 ....所以感謝您對此的幫助。非常感激。並感謝@peterm以及一個出色的解決方案,可以爲其他人解決同樣的問題。 –

1

如果我理解你正確地嘗試

SELECT c1.contact_id 
    FROM contact_attribute_value c1 LEFT JOIN contact_attribute_value c2 
    ON c1.contact_id = c2.contact_id 
    AND c2.attribute_id = '18' LEFT JOIN contact_attribute_value c3 
    ON c1.contact_id = c3.contact_id 
    AND c3.attribute_id = '19' LEFT JOIN contact_attribute_value c4 
    ON c1.contact_id = c4.contact_id 
    AND c4.attribute_id = '20' 
WHERE c1.attribute_id = '1' AND c1.stored_attribute_value = 'english' 
    AND (c2.stored_attribute_value LIKE '123%' 
    OR c3.stored_attribute_value LIKE '123%' 
    OR c4.stored_attribute_value LIKE '123%') 

SQLFiddle

UPDATE改進版本與使用條件計數HAVING

SELECT `contact_id` 
    FROM `contact_attribute_value` 
GROUP BY `contact_id` 
HAVING SUM(CASE WHEN `attribute_id` = '1' 
        AND `stored_attribute_value` = 'english' THEN 1 ELSE 0 END) = 1 
    AND (SUM(CASE WHEN `attribute_id` = '18' 
        AND `stored_attribute_value` LIKE '123%' THEN 1 ELSE 0 END) 
     +SUM(CASE WHEN `attribute_id` = '19' 
        AND `stored_attribute_value` LIKE '123%' THEN 1 ELSE 0 END) 
     +SUM(CASE WHEN `attribute_id` = '20' 
        AND `stored_attribute_value` LIKE '123%' THEN 1 ELSE 0 END)) > 0 
; 

SQLFiddle

+0

彼得 - 非常感謝您的查詢!兩件事情:1)我列出的數據有點不正確,因爲我顯示錯誤的字段。現在是正確的。 2)雖然你的查詢可能工作,但我有大約50個字段進行搜索,生成這樣的查詢的複雜性將難以管理。我相信我可以通過點擊兩次數據庫來解決這個問題,但我希望避免這種情況。附:我無法弄清楚如何在我的評論中添加換行符! –

+0

@KevinHowardGoldberg更新了查詢和sqlfiddle以符合您更新的數據。並添加了您的查詢的改進版本。 **順便說一句,正確的結果集是1,5,7,11。現在,無論如何,您需要搜索的字段數量相當快。您可以考慮將其包裝在存儲過程中,以保持應用程序層的複雜性。對不起,您不能在評論中添加換行符。 – peterm

+0

感謝您的更新。這是正確的結果集 - 是的。我可以看到如何擴展它,並且合理。這是一個比其他解決方案更復雜的查詢 - 我想知道它是否更有效,因爲它是一個查詢而不是多個子查詢。 –

相關問題