MySQL从Attributes表中选择一个字段WHERE条件在多行中

时间:2013-05-17 21:12:39

标签: mysql

我从这里开始: MySQL select one field from table WHERE condition is in multiple rows

这很好用 - 谢谢!

额外的复杂性是我需要在单个搜索中在多个属性中搜索

这是一个数据快照。 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           |
+-----+------------+--------------+------------------------+

因此,如果我要搜索所有使用“english”语言和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并显示在结果中,但这不是所期望的。

我确信在这种情况下有一种“硬编码”方式来捕获这些条件,但是属性集和可能的搜索量非常大,所以我需要一个通用的解决方案。

提前致谢!

2 个答案:

答案 0 :(得分:2)

考虑到您的示例和您解释的条件,我会说,在不进行两次查询的情况下解决此问题的最简单方法是使用子查询:

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关键字会删除重复项,因此无需再进行分组。

答案 1 :(得分: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

更新使用条件计数

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