在CASE结果= X的情况下返回第一个结果?

时间:2011-04-13 03:31:41

标签: mysql database greatest-n-per-group

我正在尝试返回编写一个只返回第一个结果的查询,其中someid(第一个案例的结果)= X - 并忽略其中someid = 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

2 个答案:

答案 0 :(得分: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

数据的定制方式使得(Walker)在4月份与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 

现在,我们有了测试场景,这个棘手的部分:返回你(Walker)和John和Kate之间最近的沟通信息。我有一个相当长的SQL语句,不可否认,我不是最好的创建这些,但我认为这仍然有效:

BEGIN
    DECLARE @UserId INT = 1

    --A.  Main Query
    SELECT
        CASE 
            WHEN mtemp.senderid = 1 --@UserId 
                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 --@UserId
                                GROUP BY
                                    mr.userid
                            ) kk on m2.time = kk.MaxTime and m2.senderid = 1 --@UserId

                    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 --@UserId
                            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

这是与Walker沟通的所有用户中有关Walker的最新通讯。

希望有所帮助。

答案 1 :(得分: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语句。