左连接以获取最新条目

时间:2017-06-10 19:30:07

标签: mysql left-join

我有表usersstatuses。我想选择所有用户,以及他们可能拥有的任何状态,但只选择每个用户的最新状态。

以下代码不起作用:

SELECT users.id, alias, gender, login, logout, users.create_date, statustext as statustxt, TIMESTAMPDIFF(YEAR,birthdate,CURDATE()) AS age
                FROM users
                LEFT JOIN statuses s ON users.id = s.user_id
                WHERE s.ID = (                              
                        SELECT MAX(s2.ID)                    
                        FROM statuses s2
                        WHERE s2.user_id = s.user_id         
                        )

这会使用户获得最新状态,但不会使用users表中的用户。也许它可以通过一些小调整来解决?

我通过搜索获得了子查询,但我不明白该代码是如何工作的。它似乎比较了同一个表的两个版本(例如:WHERE s2.user_id = s.user_id)。我在哪里可以阅读这种技术? 在这种情况下是否需要子查询?

如果你能找到一个解决方案会很棒,并且对其工作方式的一些基本解释将受到高度赞赏。

---------- EDIT ---------------

我接受了其中一个回复(由maresa)并结合我的初始代码的子查询,这有效(!)它有3个选择,看起来有点过于复杂?:

 SELECT users.id, alias, gender, login, logout, users.create_date, statustext as statustxt, TIMESTAMPDIFF(YEAR,birthdate,CURDATE()) AS age
FROM users
    LEFT JOIN (
        SELECT user_id, statustext FROM statuses s
         WHERE s.ID = (                             
           SELECT MAX(s2.ID)                
           FROM statuses s2
           WHERE s2.user_id = s.user_id
     )
  ) as s ON users.id = s.user_id

3 个答案:

答案 0 :(得分:1)

我遇到过类似的问题。这篇文章是相关的:http://www.microshell.com/database/sql/optimizing-sql-that-selects-the-maxminetc-from-a-group/

关于您的特定查询,由于您只关心最新状态,因此您希望首先获得每个用户的最新状态。假设最新状态具有最新的id(基于您的样本),SQL将在下面:

SELECT
    MAX(ID), statustext, user_id
FROM
    statuses
GROUP BY
    user_id

上述查询的作用是获取每个user_id的最新状态。一旦你得到它,你可以把它想象成一张桌子。然后只需加入这个"表" (查询)而不是真实的(状态表)。因此,您的查询如下所示:

SELECT
    users.id, alias, gender, login, logout, users.create_date, statustext as statustxt, TIMESTAMPDIFF(YEAR,birthdate,CURDATE()) AS age
FROM
    users
    LEFT JOIN (
        SELECT
            MAX(ID), user_id
        FROM
            statuses
        GROUP BY
            user_id
    ) as s ON users.id = s.user_id
    LEFT JOIN statuses ON statuses.ID = s.ID -- EDIT: Added this line.

答案 1 :(得分:0)

您可以使用子选择作为连接,并限制为仅显示1行:

SELECT 
    users.id, 
    alias, 
    gender, 
    login, 
    logout, 
    users.create_date, 
    statustext as statustxt, 
    TIMESTAMPDIFF(YEAR,birthdate,CURDATE()) AS age
FROM users
LEFT JOIN (
    SELECT user_id,statustext 
    FROM statuses s1
    WHERE s1.user_id = users.id
    ORDER BY status_date DESC
    LIMIT 1
) s ON users.id = s.user_id

答案 2 :(得分:0)

您可以使用带有元组的in子句

SELECT 
      users.id
    , alias
    , gender
    , login
    , logout
    , users.create_date
    , statustext as statustxt
    , TIMESTAMPDIFF(YEAR,birthdate,CURDATE()) AS age
  FROM users
  LEFT JOIN statuses s ON users.id = s.user_id
  WHERE (s.user_id, s.ID)  in  (                              
          SELECT user_id, MAX(s2.ID)                    
          FROM statuses s2
          group by user_id       
  )