我从这里开始: 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并显示在结果中,但这不是所期望的。
我确信在这种情况下有一种“硬编码”方式来捕获这些条件,但是属性集和可能的搜索量非常大,所以我需要一个通用的解决方案。
提前致谢!
答案 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 强>