Mysql 在左联接中使用别名
我有一张桌子,存放友谊关系 它有id、userA和userB列(userA的id总是小于userB的id) 我尝试选择特定用户的所有友谊关系:Mysql 在左联接中使用别名,mysql,Mysql,我有一张桌子,存放友谊关系 它有id、userA和userB列(userA的id总是小于userB的id) 我尝试选择特定用户的所有友谊关系: SELECT CASE friendships.userA WHEN (?) THEN friendships.userB ELSE friendships.userA END AS friend_id, users.username FROM friendships LEFT JOIN users ON friend_id=users.id WHERE
SELECT CASE friendships.userA WHEN (?) THEN friendships.userB ELSE friendships.userA END AS friend_id, users.username FROM friendships
LEFT JOIN users ON friend_id=users.id WHERE userA = (?) OR userB = (?) ORDER BY timestamp DESC LIMIT ? OFFSET ?;
$stmt->bind_param("iiiii", $user_id, user_id, $user_id, $requestsPerLoad_db, $offset);
我收到以下错误消息:
“on子句”中的未知列“friend\u id”
这句话有什么不对?我可以获取$row['friend\u id']的值,但不能在左联接中使用它?这是您的查询:
SELECT (CASE f.userA WHEN (?) THEN f.userB ELSE f.userA END) AS friend_id,
u.username
FROM friendships f LEFT JOIN
users u
ON friend_id = u.id
WHERE f.userA = (?) OR f.userB = (?)
ORDER BY timestamp DESC
LIMIT ? OFFSET ?;
friend\u id
是在SELECT
中定义的,因此不能在同一查询中的其他位置使用它。您必须使用子查询。一个简单的解决方案是将逻辑移到ON
子句。这里有一种方法:
ON (u.id = f.userA and f.userB = ?) or
(u.id = f.userB and f.userA = ?)
另一种方法是完全跳过左连接
,并将逻辑移动到WHERE
子句:
SELECT u.id, u.username
FROM users u
WHERE EXISTS (SELECT 1
FROM friendships f
WHERE f.userB = ? AND f.userA = u.id
) OR
EXISTS (SELECT 1
FROM friendships f
WHERE f.userA = ? AND f.userB = u.id
)
ORDER BY timestamp DESC
LIMIT ? OFFSET ?;
这种方法的优点是查询可以利用适当的索引。这是因为它是一个派生列(或别名),而不是friendships
表的一部分。不能在一个列上联接两个表,而这两个列中都不存在
获取所有好友的另一种方法是使用如下所示的UNION
查询(我不确定为什么需要join
,因为该列仅出现在friendships
表中):
我在ON语句中添加了CASE语句,它可以工作:
SELECT CASE friendships.userA WHEN (?) THEN friendships.userB ELSE friendships.userA END AS friend_id, users.username FROM friendships
LEFT JOIN users ON CASE friendships.userA WHEN (?) THEN friendships.userB ELSE friendships.userA END =users.id WHERE userA = (?) OR userB = (?) ORDER BY timestamp DESC LIMIT ? OFFSET ?;
$stmt->bind_param("iiiiii", $user_id, $user_id, $user_id, $user_id, $requestsPerLoad_db, $offset);
friend_id是别名,您不能在加入条件下使用它。您必须使用完整表达式,或者您可以在子查询中计算表达式,然后使用它。完整表达式取决于大小写
。那么,我是否应该在新查询中使用$row['friend\u id'],然后从我的users表中选择以获取朋友的用户名?编辑:或者我应该在同一个查询中再次尝试使用CASE
。我不明白上一个解决方案为何不是很慢。就我所理解的查询而言,通过获取当前行的u.id并在WHERE EXISTS条件下使用该值,直到检查来自用户的所有行,用户数据库的每一行都会被检查。我有一种感觉,我误解了这个查询的流程,如果是,请您解释一下它是如何工作的,以及哪些索引是合适的。@JuliusS。无论哪种情况,都需要扫描用户
表。第二种方法的优点是,它可以使用(UserA,UserB)
和(UserB,UserA)
上的索引来解析查询。好的,我将使用一些解释
来比较这些语句并尝试理解它们。剩下一件事:您的查询尝试按时间戳排序,但我得到一个错误,告诉我时间戳不是users表的一列。没错,我实际上想按friendships表的timestamp列排序。有没有办法修改您的查询?@JuliusS。然后,orderby
。您的查询没有指定时间戳的来源。
SELECT CASE friendships.userA WHEN (?) THEN friendships.userB ELSE friendships.userA END AS friend_id, users.username FROM friendships
LEFT JOIN users ON CASE friendships.userA WHEN (?) THEN friendships.userB ELSE friendships.userA END =users.id WHERE userA = (?) OR userB = (?) ORDER BY timestamp DESC LIMIT ? OFFSET ?;
$stmt->bind_param("iiiiii", $user_id, $user_id, $user_id, $user_id, $requestsPerLoad_db, $offset);