2011-04-13 102 views
0

我想返回編寫一個查詢,只返回第一個結果whereid(第一個案例的結果)= X - 並忽略someid = X的後續結果。我將如何改變以下查詢來實現這一點?在CASE結果= X時返回第一個結果?

這裏就是我目前使用:

SELECT DISTINCT CASE WHEN $userid != senderid THEN senderid ELSE GROUP_CONCAT(receivers.id SEPARATOR ', ') END someid, 
      CASE WHEN $userid != senderid THEN senders.username ELSE GROUP_CONCAT(receivers.username SEPARATOR ', ') END somename, 
      messages.body, 
      messages.time 
    FROM messages 
    LEFT JOIN messages_recipients AS recipients ON messages.id = recipients.messageid 
    LEFT JOIN users AS senders ON messages.senderid = senders.id 
    LEFT JOIN users AS receivers ON recipients.userid = receivers.id 
    WHERE recipients.userid = $userid 
    OR messages.senderid = $userid 
    GROUP BY messages.id 
    ORDER BY messages.time DESC 
+0

'.... LIMIT 1'?只取第一行? – 2011-04-13 03:36:15

+0

基本上,上述查詢以用戶(我發送或接收)的形式提取了所涉及的所有消息。其中一些信息可能介於我和'約翰'之間,其他人可能介於我和'凱特'之間。我想在'John'和我之間返回最新消息,以及'Kate'和I之間的最新消息,以便在線索視圖中將它們用作「預覽」文本。 – Walker 2011-04-13 03:46:21

+0

因爲在用戶之間只能有一個線程,所以我只想返回第一條消息來說「好的,這裏有一個線程」。 – Walker 2011-04-13 03:47:44

回答

2

根據您評論的信息,我已經採取了另一個刺。

我非常實際操作,所以雖然我可以概念化將會發生什麼,但直到我開始修補時才肯定。

因此,讓我們從數據開始。根據我們所談到的,我創建了三個表:

用戶

id user_name 
1 Walker  
2 John  
3 Kate  

消息

id senderid body time 
1 1 ignored 1           2010-04-01 00:00:00.000 
2 1 ignored 2           2010-04-02 00:00:00.000 
3 3 ignored 3           2010-04-03 00:00:00.000 
4 1 msg A to john and kate        2010-04-10 00:00:00.000 
5 3 msg b from kate to walker and john     2010-04-11 00:00:00.000 

* messages_recipients *

id messageid userid 
1 1 2 
2 1 3 
3 2 2 
4 3 1 
5 4 2 
6 4 3 
7 5 1 
8 5 2 

數據是按照這樣一種方式定製的,即您(沃克)在四月份與John和Kate都收發了郵件。

您可以通過運行下面的SQL語句看到這些消息的列表:

SELECT 
    u2.user_name AS Sender, 
    u1.user_name AS Receiver, 
    m.body, 
    m.time 
FROM 
    messages m 
JOIN 
    messages_recipients mr ON m.id = mr.messageid 
JOIN 
    users u1 ON mr.userid = u1.id 
JOIN 
    users u2 ON m.senderid = u2.id 
ORDER BY 
    time DESC 

現在,我們有測試場景中,最棘手的部分:返回最近你們之間的溝通消息(沃克)和約翰和凱特。我有一個相當長的SQL語句,無可否認,我不是在創造這些最好的,但我認爲這仍然可以工作:

BEGIN 
    DECLARE @UserId INT = 1 

    --A. Main Query 
    SELECT 
     CASE 
      WHEN mtemp.senderid = 1 [email protected] 
       THEN 
        CONCAT('Message To: ', receivers.user_name) 
       ELSE 
        CONCAT('Message From: ' , senders.user_name) 
       END AS MessageType, 
     mtemp.body, 
     mtemp.time 
    FROM 
     messages mtemp 
     INNER JOIN users senders ON 
      mtemp.senderid = senders.id 
     INNER JOIN 
      (
      --B. Inner Query determining most recent message (based on time) 
      -- between @UserID and the person @UserID 
      -- Communicated with (either as sender or receiver) 
      select userid,max(maxtime) as maxmaxtime from 
       (
        --C.1. First part of Union Query Aggregating sent/received messages on passed @UserId 
        SELECT 
         m2.body, 
         kk.* 
        FROM 
         `messages` m2 INNER JOIN 
          (
           SELECT DISTINCT 
            userid, 
            MAX(m.time) AS MaxTime 
           FROM 
            messages m INNER JOIN 
             messages_recipients mr ON m.id = mr.messageid AND 
             m.senderid = 1 [email protected] 
           GROUP BY 
            mr.userid 
          ) kk on m2.time = kk.MaxTime and m2.senderid = 1 [email protected] 

        UNION 
        --C.2. Second part of Union Query Aggregating sent/received messages on passed @UserId 
        SELECT 
         m1.body, 
         jj.* 
        FROM 
         `messages` m1 INNER JOIN 
         ----C.2a. Inner most query of users users who sent message to userid 
         (SELECT DISTINCT 
           senderid as userid, 
           MAX(m.time) AS MaxTime 
          FROM 
           messages m INNER JOIN 
            messages_recipients mr ON m.id = mr.messageid AND 
            mr.userid = 1 [email protected] 
          GROUP BY 
           m.senderid) jj on m1.time = jj.MaxTime and m1.senderid = jj.userid 
       )  MaximumUserTime 
      group by 
       MaximumUserTime.userid 
      ) AggregatedData on mtemp.time = AggregatedData.maxmaxtime 
        INNER JOIN users receivers on AggregatedData.userid = receivers.id 
      ORDER BY `time` DESC 
END 

要在phpMyAdmin測試,你就必須刪除評論以及開始/結束聲明語句。我只是想發佈這個,就好像它會在程序中看起來一樣。

該查詢假定您不會同時發送和接收來自同一用戶的不同消息;發生的機率似乎很小,所以我希望這可能會起作用。

當我運行此查詢我得到如下結果:

MessageType body time 
Message From: Kate   msg b from kate to walker and john     2010-04-11 00:00:00.000 
Message To: John  msg A to john and kate        2010-04-10 00:00:00.000 

這是最近關於所有那些誰沃克傳達用戶之間沃克通信。

希望有所幫助。

1

一個子查詢可以在這種情況下工作(雖然它的性能可能不會使它成爲一個很好的選擇):

SELECT DISTINCT CASE WHEN $userid != senderid THEN senderid ELSE GROUP_CONCAT(receivers.id SEPARATOR ', ') END someid, 
      CASE WHEN $userid != senderid THEN senders.username ELSE GROUP_CONCAT(receivers.username SEPARATOR ', ') END somename, 
      messages.body, 
      messages.time 
    FROM messages 
    INNER JOIN 
     (
     SELECT m.senderId, m.receiverId, MAX(m.time) AS MyMaxTime FROM messages GROUP BY m.senderId, m.receiverId 
     ) myLittleQuery 
      ON messages.senderid = myLittleQuery.senderid AND messages.senderid = myLittleQuery.receiverId AND messages.time = myLittleQuery.MyMaxTime 
    LEFT JOIN messages_recipients AS recipients ON messages.id = recipients.messageid 
    LEFT JOIN users AS senders ON messages.senderid = senders.id 
    LEFT JOIN users AS receivers ON recipients.userid = receivers.id 
    WHERE recipients.userid = $userid 
    OR messages.senderid = $userid 
    GROUP BY messages.id 
    ORDER BY messages.time DESC 

過去一段時間以來,我一直在MySQL領域,所以我的語法很可能是關閉的。然而,它的要點就在那裏。

此外,根據您想要檢索的內容,您可能還會丟棄DISTINCT和CASE語句。

+0

嗨雷,我只是想創建一個所有對話的列表用戶($ userid)已經有了。兩個用戶之間只能進行一次對話,而且不必相互交換(如果我發送了一條消息並且沒有得到答覆,那仍然是一個對話,並且如果有消息發送給我,而我沒有回覆,這仍然是一個談話)。有任何想法嗎? – Walker 2011-04-13 05:51:40