2

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

这工作正常 - 谢谢!

额外的复杂性是我需要在一次搜索搜索多个属性。

这是数据快照。attribute_ids 是:

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

样本数据

+-----+------------+--------------+--------------- ---------+
| 编号 | 联系方式 | 属性 ID | 存储属性值 |
+-----+------------+--------------+--------------- ---------+
| 15 | 1 | 1 | 英语 |
| 83 | 5 | 1 | 英语 |
| 153 | 9 | 1 | 英语 |
| 197 | 11 | 1 | 英语 |
| 250 | 3 | 1 | 英语 |
| 267 | 13 | 1 | 他加禄语 |
| 303 | 15 | 1 | 西班牙语 |
| 第374章 19 | 1 | 西班牙语 |
| 第469章 17 | 1 | 西班牙语 |
| 490 | 21 | 1 | 西班牙语 |
| 507 | 7 | 1 | 英语 |
| 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

从概念上讲,这是可行的,但在某些情况下它会中断。

第一个条件是联系人的语言为“英语”和两个电话号码匹配,如“123%”。此处联系人的计数为 3,并且未显示在结果中。

第二个条件是当联系人的语言不等于“英语”并且还有两个电话号码匹配时,例如“123%”。在这种情况下,联系人的计数为 2 并显示在结果中,但这不是我们想要的。

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

提前致谢!

4

2 回答 2

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不再需要分组。

于 2013-05-18T04:54:44.583 回答
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

于 2013-05-17T22:18:43.430 回答