Если один и тот же пользователь не может быть в UserConversation дважды:
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
Это также работает:
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
Если вы обнаружите, что производительность любого из этих запросов низкая, тогда может помочь двухэтапный метод: сначала найдите все разговоры, содержащие не менее желаемых сторон, затем из этого набора исключите те, которые содержат какие-либо другие. Индексы, конечно, будут иметь большое значение.
Избавление от столбца ID из UserConversation повысит производительность, получая больше строк на страницу, таким образом, больше данных за чтение (примерно на 50% больше!). Если в вашем столбце Id указан не только PK, но и кластеризованный индекс, немедленно измените кластеризованный индекс на ConversationId, UserId
(или наоборот, в зависимости от наиболее распространенного использования)!
Если вам нужна помощь с производительностью, оставьте комментарий, и я постараюсь вам помочь.
P.S. Вот еще одна дикая идея, но она может не сработать (хотя иногда это может вас удивить):
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)