“ where-in”子句中的强制条件匹配

时间:2019-08-06 09:09:47

标签: sql postgresql where-clause where-in

考虑一个简单的where子句

select * from table_abc where col_a in (1,2,3)

我知道目前的状况

  • 如果没有1,2,3,我将不会得到任何结果
  • 如果存在1,2,3,我将获得与1,2,3相关的所有结果
  • 如果存在1且不存在2,3,我将仅获得与1相关的结果。

我的问题是我们是否可以针对以下条件执行查询

  • 如果存在1且不存在2,3,我仍应获得与1,2,3相关的所有结果
  • 但是,如果没有1,2,3,我将不会得到任何结果

    换句话说,我可以在where-in子句中将某个值设置为强制值吗?我们如何更改当前查询?

编辑:如评论中所指出,我忘记添加表结构。最好也解释一下用例。

表1:管理员

ID  admin_id
-------------
1      001      
2      002 

表2:事件

ID  event_id
-------------
1      110      
2      220 

表3:Admins_Events

admin_id  event_id
-------------
001        110
001        220
002        220 

现在,作为过滤的一部分,假设我有查询

SELECT "admins"."admin_id", "events"."event_id" FROM "admins" 
LEFT JOIN "admins_events" ON "admins_events"."admin_id" = "admins"."admin_id" 
LEFT JOIN "events" ON "events"."event_id" = "admins_events"."event_id" 
WHERE (events.event_id IN (110) AND admins.admin_id IN (001))

目前,我得到的结果为

admin_id  event_id
-------------
001        110

在我想要的地方

admin_id  event_id
-------------
001        110
001        220

即使我没有在where-in子句中传递它,我仍然必须显示与管理员相关的其他事件。我当时想每次都传递所有event_id并与必需的event_id匹配,并且还与其余的event_ids匹配,以防找到必需的event_id。

SELECT "admins"."admin_id", "events"."event_id" FROM "admins" 
LEFT JOIN "admins_events" ON "admins_events"."admin_id" = "admins"."admin_id" 
LEFT JOIN "events" ON "events"."event_id" = "admins_events"."event_id" 
WHERE (events.event_id IN (mandatory[110], 220) AND admins.admin_id IN (001))

如何更改查询?

3 个答案:

答案 0 :(得分:1)

听起来像在您的示例中,您想要与事件110关联的所有与管理员相关的事件。在Mysql中,我将使用以下查询来执行此操作,该查询将管理员与事件关联两次:一次过滤所需的事件,然后一次获取所有其他事件。

但是,在您的示例中,您根本不需要查询中的admins表,因为您只需要可以直接从admins_events表中获取的admin ID。如果您的真实“管理员”表还具有您想要的其他属性(名称,位置等),这些属性在admins_events连接表中不可用,则我将其保留。

具体查询是:

SELECT "admins"."admin_id", "events"."event_id" FROM "admins" 
JOIN "admins_events" ON "admins_events"."admin_id" = "admins"."admin_id" 
JOIN "events" ON "events"."event_id" = "admins_events"."event_id"
JOIN "admins_events" AS "specific_admins_events" ON "specific_admins_events"."admin_id" = "admins"."admin_id" 
JOIN "events" AS "specific_events" ON "specific_events"."event_id" = "specific_admins_events"."event_id"
WHERE (specific_events.event_id IN (110))

答案 1 :(得分:1)

EXISTS子句中使用WHERE添加另一个条件:

SELECT a.admin_id, e.event_id 
FROM Admins a 
LEFT JOIN Admins_Events ae ON ae.admin_id = a.admin_id 
LEFT JOIN Events e ON e.event_id = ae.event_id 
WHERE (e.event_id IN (110, 220) AND a.admin_id IN (001))
AND EXISTS (
  SELECT 1 FROM Admins_Events
  WHERE event_id = 110 AND admin_id = a.admin_id
)

请参见demo
结果:

| admin_id | event_id |
| -------- | -------- |
| 1        | 110      |
| 1        | 220      |

答案 2 :(得分:0)

首先,您只需要admin_events表。

然后方法使用窗口函数:

SELECT ae.*
FROM (SELECT ae.*,
             SUM(CASE WHEN ae.event_id IN (110) THEN 1 ELSE 0 END) OVER (PARTITION BY ae.admin_id) as num_110
      FROM admins_events ae
     ) ae
WHERE ae.admin_id IN ('001') AND -- assume this is a string
      num_110 > 0 AND
      ae.event_id IN (110, 220);