我有表users
和statuses
。我想选择所有用户,以及他们可能拥有的任何状态,但只选择每个用户的最新状态。
以下代码不起作用:
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
答案 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
)