如何选择两列应在多行上匹配的不同行?

时间:2013-10-11 20:23:22

标签: mysql sql

我有一张这样的表:

id | user_id | param_id | param_value  
1      1          44          google
2      1          45         adTest
3      1          46         Campaign
4      1          47          null
5      1          48          null
6      2          44          google
7      2          45         adAnotherTest
8      2          46         Campaign2
9      2          47         null
10     2          48         null  

我想获取所有user_ids,其中(param_id = 44 AND param_value = google)AND(param_id = 45 AND param_value = adTest)。所以上面的where子句应该只给出user_id = 1而不是user_id = 2。他们都在param_id 44谷歌,但只有用户1在param_id = 45时有param_value adTest。

问题在于未来可以添加更多的参数。我需要找到一个动态查询。在这里我尝试过:

SELECT DISTINCT up.user_id FROM user_params AS up

                    LEFT JOIN user_params AS upp ON up.id = upp.id

                    WHERE up.param_id IN (?,?) 

                    AND upp.param_value IN (?,?)

3 个答案:

答案 0 :(得分:3)

SELECT DISTINCT up.user_id 
FROM user_params AS up
LEFT JOIN user_params AS upp ON up.id = upp.id
group by up.user_id
having sum(param_id = 44 AND param_value = 'google') >= 1
and sum(param_id = 45 AND param_value = 'adTest') >= 1

答案 1 :(得分:2)

另一种方式:

SELECT  -- DISTINCT 
    up1.user_id 
FROM 
    user_params AS up1
  JOIN
    user_params AS up2 
      ON up1.user_id = up2.user_id
WHERE
    up1.param_id = 44 AND up1.param_value = 'google'
  AND 
    up2.param_id = 45 AND up2.param_value = 'adTest' ;

如果DISTINCT上存在UNIQUE约束,则您不需要(user_id, param_id)

为提高效率,请在(param_id, param_value, user_id)

上添加索引

你正在处理的问题被称为“关系部门”,@ Erwin Brandstetter在这里有一个很好的答案: How to filter SQL results in a has-many-through relation ,有很多方法可以编写这样的查询,以及性能测试。

测试是在Postgres完成的,因此有些查询甚至不在MySQL中运行,但至少有一半的查询运行,并且其中许多查询的效率相似。

答案 2 :(得分:0)

如果你想优化它,应该给出相同的结果,而不需要LEFT JOIN表扫描(感谢juergen d有部分

SELECT
 user_id

FROM 
 user_params

WHERE
  param_id IN(44, 45)
 AND
  param_value IN('google', 'adTest')

GROUP BY
 user_id 

HAVING 
    sum(param_id = 44 AND param_value = 'google') >= 1
  AND
    sum(param_id = 45 AND param_value = 'adTest') >= 1
;

请参阅http://sqlfiddle.com/#!2/17b65/4了解演示