2011-04-13 87 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