简体   繁体   中英

MySQL - Select something ONLY where columns contain specific values, and nothing else

I have a messages_users table that contains users participating to a conversation :

conversationId | userId

Since the purpose is that multiple users can get in a conversation, one row equals one user.

There are two types of conversations : conversation with friend, and grouped conversation with multiple users. What distincts them is only the number of people in it.

2 users = conversation with friend

3 or more = grouped conversation

I want to allow users to open a conversation with their friends from their ids (here, 1 and 2). So, I need to make a SQL statement that will retrive a conversation id ONLY where those two users are in.

If I do this, I'll get every conversations that those two users are in (if there are grouped conversations with them, for example)

SELECT convId FROM messages_users WHERE userId IN (1,2)

I tried this but it won't work :

SELECT convId FROM messages_users WHERE userId IN (1,2) HAVING COUNT(userId) = 2

Also tried this, but still it will get me every conversations they are in :

SELECT convId FROM messages_users a INNER JOIN messages_users b ON a.convId = b.convId WHERE a.userId = 1 AND b.userId = 2

The condition that you want is:

SELECT mu.convId
FROM messages_users mu
GROUP BY mu.convId
HAVING SUM(CASE WHEN mu.userId = 1 THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN mu.userId = 2 THEN 1 ELSE 0 END) > 0 AND
       SUM(CASE WHEN mu.userId NOT IN (1, 2) THEN 1 ELSE 0 END) = 0;

You can't filter before the GROUP BY because then you would miss counting user "3" if in the conversation. The third condition prevents "3" from participating.

In MySQL, this can be simplified to:

SELECT mu.convId
FROM messages_users mu
GROUP BY mu.convId
HAVING SUM( mu.userId = 1 ) > 0 AND
       SUM( mu.userId = 2 ) > 0 AND
       SUM( mu.userId NOT IN (1, 2) ) = 0;

We can try using a self-join operation with an EXISTS clause:

SELECT DISTINCT mu1.convId
FROM messages_users mu1
INNER JOIN messages_users mu2
    ON mu1.convId = mu2.convId
WHERE
    (mu1.userId = 1 AND mu2.userId = 2) AND
    NOT EXISTS (SELECT 1 FROM messages_users mu
                WHERE mu.convId = mu1.convId AND userID NOT IN (1, 2));

Here is a link to a demo showing that the above logic works:

Demo

For every " conversation with friend " there must be only 2 rows with the same convId :

SELECT convId
FROM messages_users 
GROUP BY convId
HAVING COUNT(userId) = 2;

If you want the " conversations with friend " for users 1 and 2:

SELECT DISTINCT convId FROM messages_users 
WHERE 
  (userId IN (1, 2)) 
  AND 
  convId IN 
    (SELECT convId
    FROM messages_users 
    GROUP BY convId
    HAVING COUNT(userId) = 2); 

See demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM