开发者

Query for exact match of users in a conversation in SQL Server

开发者 https://www.devze.com 2023-03-11 14:54 出处:网络
I have a conversation table, and a user conversation table. CONVERSATION Id, Subject, Type USERCONVERSATION

I have a conversation table, and a user conversation table.

CONVERSATION
Id, Subject, Type

USERCONVERSATION
Id, UserId, ConversationId

I need to do a SQL Query based on a list of UserIds. So, if I have three UserIds for the same ConversationId, I need to perform a query where if I provide the same three userIds, it will ret开发者_JAVA技巧urn the ConversationId where they match exactly.


Assuming the same user can't be in a UserConversation twice:

SELECT ConversationID
FROM UserConversation
GROUP BY ConversationID
HAVING
   Count(UserID) = 3 -- this isn't necessary but might improve performance
   AND Sum(CASE WHEN UserID IN (1, 2, 3) THEN 1 ELSE 0 END) = 3

This also works:

SELECT ConversationID
FROM
   UserConversation UC
   LEFT JOIN (
      SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
   ) U (UserID) ON UC.UserID = U.UserID
GROUP BY ConversationID
HAVING
   Count(U.UserID) = 3
   AND Count(UC.UserID) = 3

If you find that performance is poor with either of these queries then a two-step method could help: First find all conversations containing at least the desired parties, then from that set exclude those that contain any others. Indexes of course will make a big difference.

Getting rid of the ID column from UserConversation will improve performance by getting more rows per page, thus more data per read (about 50% more!). If your Id column is not only the PK but also the clustered index, then immediately go change the clustered index to ConversationId, UserId (or vice versa, depending on the most common usage)!

If you need help with performance post a comment and I'll try to help you.

P.S. Here's another wild idea but it may not perform as well (though things can surprise you sometimes):

SELECT
   Coalesce(C.ConversationID, UC.ConversationID) ConversationID
   -- Or could be Min(C.ConversationID)
FROM
   Conversation C
   CROSS JOIN (
      SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
   ) U (UserID)
   FULL JOIN UserConversation UC
      ON C.ConversationID = UC.ConversationID
      AND U.UserID = UC.UserID
GROUP BY Coalesce(C.ConversationID, UC.ConversationID)
HAVING Count(*) = Count(U.UserID)


My solution was wrong, unfortunately... I strongly suggest to use one of Erik's solutions...

Regards

0

精彩评论

暂无评论...
验证码 换一张
取 消