Mysql 在左联接中使用别名

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

我有一张桌子,存放友谊关系

它有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 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);