Запрос на точное совпадение пользователей в разговоре в SQL Server - PullRequest
4 голосов
/ 08 июня 2011

У меня есть таблица разговоров и таблица разговоров пользователей.

CONVERSATION
Id, Subject, Type

USERCONVERSATION
Id, UserId, ConversationId

Мне нужно выполнить SQL-запрос на основе списка идентификаторов пользователей.Итак, если у меня есть три UserId для одного и того же ConversationId, мне нужно выполнить запрос, где, если я предоставлю те же три userIds, он вернет ConversationId там, где они точно совпадают.

Ответы [ 2 ]

4 голосов
/ 08 июня 2011

Если один и тот же пользователь не может быть в 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)
0 голосов
/ 08 июня 2011

Мое решение было неверным, к сожалению ... Я настоятельно рекомендую использовать одно из решений Эрика ...

Привет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...