在多个条件下加入协会

时间:2016-11-08 20:57:21

标签: sql postgresql

我有两张桌子

Visitor(id, ...)

Tracking(id, visitor_id, field, string_value, boolean_value, string_value, integer_value)

我想返回所有visitors,以查找与{0}}匹配的每个提供条件的人trackings。换句话说,对于每个条件,应该有一个匹配它的相应跟踪记录。

visitor可以包含多个trackings

目前我有以下查询,但当多于1个查询时,它不起作用。

SELECT *
FROM visitors AS v
LEFT JOIN trackings AS t ON t.visitor_id = v.id
WHERE (
    v.app_id = '123'

    // there can be an arbitrary number of these conditions
    AND (t.field = 'admin' AND t.boolean_value)
    AND (t.field = 'users_created' AND t.integer_value > 1)
    ...
    AND (t.field = 'username' AND t.string_value = 'jack')

我在考虑为每个条件做一个IF EXISTS,但是每个条件必须单独执行一个子查询看起来非常昂贵。

有关如何解决这个问题的任何建议吗?

2 个答案:

答案 0 :(得分:1)

如果您希望访问者拥有所有跟踪,请使用group byhaving。这是一个例子:

SELECT v.id
FROM visitors v JOIN
     trackings t
     ON t.visitor_id = v.id
WHERE v.app_id = '123' AND
      ( (t.field = 'admin' AND t.boolean_value) OR
        (t.field = 'users_created' AND t.integer_value > 1) OR
       ...
        (t.field = 'username' AND t.string_value = 'jack')
      )
GROUP BY v.id
HAVING COUNT(*) = <number of conditions>

答案 1 :(得分:1)

如果不希望分组,可能是因为你想要所有列,那么窗口函数可以这样做:

select *
from (
    select *,
        count (
            t.field = 'admin' and t.boolean_value or
            t.field = 'users_created' and t.integer_value > 1 or
            t.field = 'username' and t.string_value = 'jack'
            or null
        ) over (partition by v.id) = 3 as matched
    from
        visitors v
        inner join
        trackings as t on t.visitor_id = v.id
    where v.app_id = '123'
) s
where matched

Window Functions