1

这是对我之前回答的问题的修改

我在下表中有数据:

ROLE_ID | USER_ID
------------------
 14     | USER A
 15     | USER A
 11     | USER B
 13     | USER D
 13     | USER A
 15     | USER B
 15     | USER D
 12     | USER C
 15     | USER C

我想获得只有 13 和 15 的用户 ID。所以根据上面的例子,我应该只回来USER D

下面的查询是在我之前的回答中提供的,这NOT IN部分是我添加的,但是,这并没有达到目标..

select user_id
  from my_table
 where role_id in (13,15) AND role_id not in (11,14)
 group by user_id.
having count(distinct role_id) = 2
4

5 回答 5

4

获得13 和 15,请执行以下操作:

select user_id
from my_table
group by user_id
having max(case when role_id = 13 then 1 else 0 end) = 1 and  -- has 13
       max(case when role_id = 15 then 1 else 0 end) = 1 and  -- has 15
       max(case when role_id not in (13, 15) then 1 else 0 end) = 0 -- nothing else

这将检查 13 和 15 是否在 user_id 集中。然后它检查集合中没有其他内容。

我意识到在 case 语句中使用 having 子句一开始似乎很尴尬。但是,您可以表达关于集合中事物的不同组合的大量逻辑。

于 2012-08-29T01:02:36.677 回答
2

假设 和 的组合user_idrole_id唯一的,您可以执行类似的操作

select user_id
  from my_table
 where role_id in (13,15,11,14) 
 group by user_id.
having sum( case when role_id in (13,15) then 1 else 0 end) = 2
   and sum( case when role_id in (11,14) then 1 else 0 end) = 0

如果 和 的组合user_id不是role_id唯一的,那么distinct在你的原件count中是必要的,事情变得更具挑战性。

于 2012-08-29T00:37:51.657 回答
0

将我的答案扩展到您的原始问题,您可以尝试

(SELECT user_id FROM table WHERE role_id=13
       INTERSECT
SELECT user_id FROM table WHERE role_id=15)
       MINUS
SELECT user_id FROM table WHERE role_id IN (11, 14)

两者INTERSECTMINUS都是特定于ORACLE的,因此其他解决方案更通用,而这更具可读性且更易于修改。

无权访问 ORACLE 数据库,因此未经测试。

于 2012-08-29T09:11:11.067 回答
0

并没有实际测试它,但这样的事情应该可以工作:

SELECT USER_ID
FROM MY_TABLE T1
WHERE
    ROLE_ID IN (13, 15)
    AND NOT EXISTS (
        SELECT *
        FROM MY_TABLE T2
        WHERE
            T1.USER_ID = T2.USER_ID
            AND ROLE_ID IN (11, 14)
    )
GROUP BY USER_ID
HAVING COUNT(DISTINCT ROLE_ID) = 2

简而言之:忽略用户的所有行,其中任何行包含不需要的 ROLE_ID ( NOT EXISTS),然后继续确保用户具有所有需要的 ROLE_ID。

注意:如果 {ROLE_ID, USER_ID} 上有键,则不需要 DISTINCT。


要获取只有 (13, 15) 且没有其他内容的用户,在事先不知道什么是“else”的情况下,只需将ROLE_ID IN (11, 14)内部查询中的. 替换为ROLE_ID NOT IN (13, 15).

于 2012-08-29T01:53:14.497 回答
0

我想要角色 ID 为 13 和 15 的用户(仅此而已)

一种方法:

SELECT t13.user_id
FROM   my_table t13
JOIN   my_table t15 ON t13.user_id = t15.user_id
LEFT   JOIN my_table tx ON tx.user_id = t13.user_id AND tx.role_id NOT IN (13,15)
WHERE  t13.role_id = 13
AND    t15.role_id = 15
AND    tx.user_id IS NULL;

这假设(role_id, user_id)是唯一的。

这是关系划分的一个特例。我们最近收集了很多方法来处理这个问题(对于 PostgreSQL 和 MySQL,但其中大部分是同样适用于 Oracle 的基本 SQL):
How to filter SQL results in a has-many-through relationship

另一个不存在的变体:

SELECT t13.user_id
FROM   my_table t13
JOIN   my_table t15 ON t13.user_id = t15.user_id
WHERE  t13.role_id = 13
AND    t15.role_id = 15
AND    NOT EXISTS (
   SELECT 1
   FROM   my_table tx
   WHERE  tx.user_id = t13.user_id
   AND    tx.role_id NOT IN (13,15)
   );
于 2012-08-29T01:34:02.797 回答