Sql HAVING子句中的逻辑,用于按结果获取一个组的多个值

Sql HAVING子句中的逻辑,用于按结果获取一个组的多个值,sql,oracle,Sql,Oracle,假设我有一个包含如下数据的表: ROLE_ID | USER_ID | CODE --------------------------------- 14 | USER A | 001 15 | USER A | 002 11 | USER B | 004 13 | USER D | 005 13 | USER A | 001 15 | USER B | 009 15 | U

假设我有一个包含如下数据的表:

ROLE_ID | USER_ID  |  CODE
---------------------------------
 14     | USER A   |   001
 15     | USER A   |   002
 11     | USER B   |   004
 13     | USER D   |   005
 13     | USER A   |   001
 15     | USER B   |   009
 15     | USER D   |   005
 12     | USER C   |   004
 15     | USER C   |   008
 13     | USER D   |   007
 15     | USER D   |   007
我想获得只有13和15个角色ID的用户ID和代码。因此,基于上述数据,我想返回以下内容

USER D |  005
USER D |  007
我有下面的查询,但是,它只返回一个,而不是两个

   SELECT a.user_id, a.code
   FROM my_table a
   WHERE a.ROLE_ID in (13,15,11,14)
   group by a.USER_ID, a.code
    having sum( case when a.role_id in (13,15) then 1 else 0 end) = 2
    and sum( case when a.role_id in (11,14) then 1 else 0 end) = 0  
   ORDER BY USER_ID
上述查询只会带来

USER D |  005
而不是

USER D |  005
USER D |  007

有时,只听自己的英语单词就可以翻译成最容易阅读的SQL:

SELECT DISTINCT a.user_id, a.code
   FROM my_table a
   WHERE a.user_id in 
       (SELECT b.user_id
       FROM my_table b
       WHERE b.ROLE_ID = 13)
    AND a.user_id in 
       (SELECT b.user_id
       FROM my_table b
       WHERE b.ROLE_ID = 15)
   AND a.user_id NOT IN 
       (SELECT b.user_id
       FROM my_table b
       WHERE b.ROLE_ID NOT IN (13,15))
我会:

SELECT a.user_id, a.code 
FROM my_table a
GROUP BY a.user_id, a.code 
HAVING sum(case when a.role_id in (13, 15) then 1 else 3 end) = 2

正如所证明的,您的查询完全按照您的期望工作。你的项目数据中一定有一些东西在你的问题的伪造数据中没有表现出来

我确实支持您在问题中执行的pivot,但我会将其编写为一个求和表达式,以减少聚合数据的迭代次数。不管优化器是否正在将子查询转换为多个联接,我当然不赞成

您的轴心条件:

我的建议是:

在迭代聚合数据时,您可以保留符合条件的行的计数+1,并在每次评估后跳转到不符合条件的结果+3。这样,只有一次通过聚合,而不是两次

SELECT USER_ID, CODE
FROM my_table
WHERE ROLE_ID IN (13,15,11,14)
GROUP BY USER_ID, CODE
HAVING SUM(CASE WHEN ROLE_ID IN (13,15) THEN 1
                WHEN ROLE_ID IN (11,14) THEN 3 END) = 2
表达这些HAVING子句作用的另一种方式是:

要求第一种情况满足两次,第二种情况永远不满足

或者,上述HAVING条款可以写得不那么优雅:

HAVING SUM(CASE ROLE_ID
           WHEN 13 THEN 1
           WHEN 15 THEN 1
           WHEN 11 THEN 3
           WHEN 14 THEN 3
           END) = 2
免责声明1:我不会在[oracle]标记池中游泳,我没有研究如何使用PIVOT执行此操作

免责声明2:我的上述建议假设角色ID在分组的用户ID+代码聚合数据中是唯一的。附带案件:

一个给定的组包含ROLE_ID=13、ROLE_ID=13和ROLE_ID=15,那么当然总数将至少为3,并且该组将被取消资格。 一个给定的组只包含ROLE_ID=15和ROLE_ID=15,那么当然总数将是2,并且该组将被无意中限定。 为应对此类情况,请设置三个单独的最大条件

HAVING MAX(CASE WHEN ROLE_ID = 13 THEN 1 END) = 1
   AND MAX(CASE WHEN ROLE_ID = 15 THEN 1 END) = 1
   AND MAX(CASE WHEN ROLE_ID IN (11,14) THEN 1 END) IS NULL

它看起来工作得很好:我不知道sqlfiddle。很棒的网站。我给出的例子是我表格的子集。因为,它起作用了,我将尝试添加表中存在的更多列。我不知道oracle,但我很难相信三个子查询比透视更好。此答案不包含所有必需的条件。此答案不包含所有必需的条件。
HAVING SUM(CASE ROLE_ID
           WHEN 13 THEN 1
           WHEN 15 THEN 1
           WHEN 11 THEN 3
           WHEN 14 THEN 3
           END) = 2
HAVING MAX(CASE WHEN ROLE_ID = 13 THEN 1 END) = 1
   AND MAX(CASE WHEN ROLE_ID = 15 THEN 1 END) = 1
   AND MAX(CASE WHEN ROLE_ID IN (11,14) THEN 1 END) IS NULL