我有一个现有网站,其数据库设计不正确且包含大量记录,因此我们无法更改数据库结构。
当前问题的数据库主要包含4个表,用户,问题,选项和答案。有一组标准的问题和选项,但对于每个用户,每组问题和选项的答案表中都有一行。数据库结构和示例数据可在SQL fiddle获得。
现在作为高级搜索的新要求,我需要通过应用多个搜索过滤器来查找用户。示例输入和预期输出在SQL Fiddle的注释中给出。
我试图应用所有类型的连接,交叉但总是以某种方式失败。有人可以帮我写正确的查询,最好是轻量级/优化连接,因为DB包含大量记录(10000多个用户,100多个问题,500多个选项和500000+记录在答案表中)?
编辑:基于两个答案,我使用了以下查询
SELECT u.id, u.first_name, u.last_name
FROM users u
JOIN answers a ON a.user_id = u.id
WHERE (a.question_id = 1 AND a.option_id IN (3, 5))
OR (a.question_id = 2 AND a.option_id IN (8))
GROUP BY u.id, u.first_name, u.last_name
HAVING
SUM(CASE WHEN (a.question_id = 1 AND a.option_id IN (3, 5)) THEN 1 ELSE 0 END) >=1
AND SUM(CASE WHEN (a.question_id = 2 AND a.option_id IN (8)) THEN 1 ELSE 0 END) >= 1;
请注意:在真实数据库中,user_id
表的question_id
,option_id
和answers
列已编入索引。
在SQL Fiddle上运行查询。
SQL Fiddle代表dnoeth的答案。
SQL Foddle对于calcinai的回答。
答案 0 :(得分:1)
使用OR将所有 n 过滤器添加到WHERE中并使用AND在HAVING(SUM(CASE))中重复它们:
SELECT u.id, u.first_name, u.last_name
FROM users u JOIN answers a
ON a.user_id = u.id
JOIN questions q
ON a.question_id = q.id
JOIN question_options o
ON a.option_id = o.id
WHERE (q.question = 'Language known' AND o.OPTION IN ('French','Russian'))
OR (q.question = 'height' AND o.OPTION = '1.51 - 1.7')
GROUP BY u.id, u.first_name, u.last_name
HAVING
SUM(CASE WHEN (q.question = 'Language known' AND o.OPTION IN ('French','Russian')) THEN 1 ELSE 0 END) >=1
AND
SUM(CASE WHEN (q.question = 'height' AND o.OPTION = '1.51 - 1.7') THEN 1 ELSE 0 END) >= 1
;
我将您的联接更改为更易读的标准SQL语法。
答案 1 :(得分:1)
这需要对动态过滤器进行一些调整,但你真正想做的是按ID搜索,因为它意味着更少的连接和更快的查询。
这会产生您期望的结果。我假设搜索过滤器是基于数据库中的off选项生成的,因此不是将实际值传回给查询,而是传递ID。
多个内部联接将支持多个AND条件并自动减少结果集。
SELECT * FROM users u
INNER JOIN answers a ON a.user_id = u.id
AND (a.question_id, a.option_id) IN ((1,3),(1,5)) # q 1: Lang, answer 3/5: En/Ru
INNER JOIN answers a2 ON a2.user_id = u.id
AND (a2.question_id, a2.option_id) = (2,8) # q 2: Height, answer 8: 1.71...
GROUP BY u.id;
我建议确保搜索的用户名为(user_id,question_id,option_id):
ALTER TABLE `answers` ADD INDEX idx_search(`user_id`, `question_id`, `option_id`);
否则它应该使用连接的主键(如果正确定义),所以它会很快。