Inner queries on a single table with IN and NOT IN conditions

你。 提交于 2019-12-20 04:40:09

问题


This is a modification to my previously answered question

I have data in the table like below:

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

I would like to get user ids that ONLY have 13 and 15. So based on the example above, I should only get back USER D

The query below was provided in my previous answer and the NOT IN part was added by me, however, that doesn't achieve the goal..

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

回答1:


Assuming the combination of user_id and role_id is unique, you could do something like

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

If the combination of user_id and role_id is not unique, then the distinct in your original count is necessary and things get a bit more challenging.




回答2:


To get only 13 and 15, do the following:

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

This checks that 13 and 15 are in the user_id set. It then checks that nothing else is in the set.

I realize that using the having clause with the case statement seems awkward at first. However, you can express lots of logic about different combinations of things in the set.




回答3:


I want the users that have role_id of 13 AND 15 (and nothing else)

One way to do it:

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;

This assumes (role_id, user_id) to be unique.

It's a special case of relational division. We have assembled a ton of ways to deal with that recently (for PostgreSQL and MySQL, but most of it is basic SQL that works for Oracle just as well):
How to filter SQL results in a has-many-through relation

Another variant with NOT EXISTS:

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)
   );



回答4:


Didn't actually test it, but something like this should work:

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

In plain English: ignore all rows of a user for which there is any row containing undesirable ROLE_ID (NOT EXISTS), then proceed to ensure user has all of the desirable ROLE_IDs.

NOTE: DISTINCT is not necessary if there is a key on {ROLE_ID, USER_ID}.


To get users that have only (13, 15), and nothing else, without knowing in advance what is "else", just replace the ROLE_ID IN (11, 14) in the inner query with ROLE_ID NOT IN (13, 15).




回答5:


Extending my answer to your original question, you might try

(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)

Both INTERSECT and MINUS are specific to ORACLE, so the other solutions are more generic, whereas this is more readable and easier to modify.

Don't have access to an ORACLE db so not tested.



来源:https://stackoverflow.com/questions/12169409/inner-queries-on-a-single-table-with-in-and-not-in-conditions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!