如何获取最近创建的行,其中几列中的一列具有特定值?

时间:2015-05-26 04:19:22

标签: mysql sql

我有这个SQL表Messages,其中相关条目为senderrecipienttimestamptext。例如,一些例子是

sender     recipient    text             timestamp
user1      user2        hey              1
user2      user1        hello back       2
user1      user3        hey other dude   3

例如,为了填充iMessage中的视图;我需要一个SQL查询,以便给定用户在用户拥有的每个对话中获取最新消息。所以目前我所拥有的是

SELECT * 
FROM Messages m 
WHERE m.timestamp IN (SELECT MAX(m2.timestamp) 
               FROM Messages m2 
               WHERE m.sender = :user OR m.recipient = :user 
               GROUP BY sender, recipient)

但遗憾的是,此查询返回上述所有3条消息,因为嵌套选择将前两个分别分组,即使它们都在同一个对话中。有没有一种简单的方法来表达我在SQL中真正想要的东西,最好不要创建一个Conversations表并做一些有趣的业务?

3 个答案:

答案 0 :(得分:0)

在外部查询中,您尝试将“m.id”与内部查询进行比较,而不是使用“m.id”,您应该使用“m.timestamp

SELECT * 
FROM Messages m 
WHERE m.timestamp IN (SELECT max(m2.timestamp)
                     FROM Messages m2 
                     WHERE m.sender = :user 
                        OR m.recipient = :user) 

答案 1 :(得分:0)

你的方法基本上是行不通的。现在你正在检查显然不起作用的WHERE m.id IN (SELECT MAX(m2.timestamp)

假设这是一个拼写错误,并且您打算检查WHERE m.timestamp IN ...它仍然不可靠,因为来自不同会话的多条消息可能具有相同的时间戳。

相反,让我们放弃那种方法,因为它充满了困难,而只是执行anti-join

select m.*
  from messages m 
     left join messages m2 
       on ((m.sender = m2.sender and m.recipient = m2.recipient) 
           or (m.sender = m2.recipient and m.recipient = m2.sender)) 
         and m.timestamp < m2.timestamp 
  where m2.sender is null

demo here

通过加入两个条件,我们基本上加入'对话',无论发送者和接收者是否相同,或者一个的发送者是另一个的接收者。我们的最终谓词有一个时间范围 - 当不存在具有更高时间戳的消息时,外连接将返回空值,因此我们过滤where子句中的那些(这是反-join

答案 2 :(得分:-1)

如果您想查找用户的上一条消息,请尝试以下操作:

SELECT *
FROM `Messages` 
WHERE `recipient` = :user OR `sender` = :user
ORDER BY `timestamp` DESC
LIMIT 1

如果您想在两个用户之间找到最后一条消息,请尝试以下方法:

SELECT *
FROM `Messages` 
WHERE
    :user1 + :user2 = 
    CASE WHEN `recipient` = :user1 THEN `recipient`
         WHEN `sender` = :user1 THEN `sender`
         ELSE NULL
    END +
    CASE WHEN `recipient` = :user2 THEN `recipient`
         WHEN `sender` = :user2 THEN `sender`
         ELSE NULL
    END 
ORDER BY `timestamp` DESC
LIMIT 1