2011-06-08 96 views
4

我有一個對話表和一個用戶對話表。查詢SQL Server中對話中用戶的完全匹配

CONVERSATION 
Id, Subject, Type 

USERCONVERSATION 
Id, UserId, ConversationId 

我需要做一個基於UserIds列表的SQL查詢。所以,如果我有三個UserIds用於相同的ConversationId,那麼我需要執行一個查詢,如果我提供了相同的三個userIds,它將返回它們完全匹配的ConversationId。

+0

你想涉及_only_三個用戶的對話,或所涉及的三個用戶_and任意數量的額外users_的? – 2011-06-08 07:00:37

+0

只有這三個用戶。把它想象成一個電話信息。如果我與3個人開始對話,那麼這3個(或n個)人會使用相同的conversationId進入UserConversation表。如果我然後開始一個全新的對話,恰好有相同的3(或n)個人,而不是創建3個新的條目,它將返回conversationId,然後新的消息可以添加到現有的對話中。 – mickyjtwin 2011-06-08 07:08:47

+0

如果你正在設計數據庫,我會批評你使用'Id'作爲列名的事實,而不是包含'Conversation.ConversationID'這樣的表名,因爲不同表中的列意味着相同的東西有不同的名字。另外,USERCONVERSATION表可能不需要Id列。這是一個多對多的連接表,這些幾乎都不需要自己的ID。 – ErikE 2011-06-08 08:04:57

回答

4

假設同一個用戶不能在一個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 

如果您發現任何一個查詢的性能都很差,那麼採用兩步法可能會有所幫助:首先查找包含至少至少所需參與方的所有會話,然後從該集合中排除包含任何其他參與方的那些會話。當然索引會有很大的不同。

擺脫UserConversation中的ID列可以通過每頁獲取更多行來提高性能,從而每次讀取的數據量更多(大約多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

我會對你對提高性能的想法感興趣 – mickyjtwin 2011-06-08 08:33:56

+0

@micky我發佈了一些東西,你怎麼看待它們?你可以從'UserConversation'中刪除'Id'嗎? 「UserConversation」表上的聚簇索引和非聚簇索引是什麼?你知道'ConversationID'還是'UserID'會更頻繁地查詢UserConversation嗎?對我給你的問題進行測試,看看最好的方法。如果你發佈了我所說的所有結果,我會在稍後幫助你...我現在必須走了! – ErikE 2011-06-08 08:37:37

0

我的解決辦法是錯誤的,可惜... 我強烈建議使用的Erik's solutions一個...

問候

+0

@mickyjtwin此答案不符合您的要求。它將返回涉及三個用戶*和任何其他數量的用戶*的對話。 – ErikE 2011-06-08 08:00:43

+0

@Erik - 這是怎麼回事?如果您將用戶數放在'@ numberOfUsersIds'中,那麼它只會查找指定用戶參與的用戶數量。 – 2011-06-08 08:06:26

+1

由於您的WHERE子句排除了其他用戶,因此Count將最大限度地列於列表中的用戶,而不計算其他用戶被排除在外。嘗試這個查詢,並且在它不應該返回時返回一個行,因爲UserID 4是對話的一部分:'SELECT ConversationID FROM(SELECT 1,1 UNION ALL SELECT 1,2,UNION ALL SELECT 1,3,UNION ALL SELECT 1,4 )UserConversation(ConversationID,UserID)WHERE UserID IN(1,2,3)GROUP BY ConversationID HAVING Count(UserID)= 3' – ErikE 2011-06-08 08:10:39