当一个表的两列引用另一表的一列时,如何在Laravel中使用JOIN?

时间:2018-11-09 09:12:04

标签: laravel join laravel-5.6

我有两个表:-

A. users table

    |--------------------------------------------------------|
    |  id  |    fname    |     lname     |      deleted      |
    |--------------------------------------------------------|
    |  1   |     Jax     |     Briggs    |         n         |
    |--------------------------------------------------------|
    |  2   |    Juli     |     Briggs    |         y         |
    |--------------------------------------------------------|
    |  1   |     Nacy    |     Blew      |         n         |
    |--------------------------------------------------------|

B. friend table

    |-------------------------------------------------------------|
    |  id  |    user_id    |     receiver_id     |    status      |
    |-------------------------------------------------------------|
    |  1   |       2       |          3          |       0        |
    |-------------------------------------------------------------|
    |  2   |       1       |          3          |       1        |
    |-------------------------------------------------------------|
    |  1   |       2       |          1          |       1        |
    |-------------------------------------------------------------|

我正在尝试使用以下查询来检索用户的朋友:-

"SELECT users.id, users.fname, users.lname FROM users,friend 
 WHERE 
      IF(friend.user_id != $id, friend.user_id = users.id, friend.receiver_id = users.id)
      AND (friend.user_id = $id OR friend.receiver_id = $id)
      AND (friend.status = 1)
      AND (user.deleted = 'n')"

如果friend.status = 1,则表示接收者已经接受了好友请求。 如果user.deleted = n,则表示该用户帐户尚未删除

如何将上述查询转换为Laravel口才?

我试图做这样的事情:-

$friendshipQuery    = Friend::select('users.id', 'users.fname', 'users.lname', 'users.email')
                              ->whereRaw('IF(friend.user_id != ' .$id. ', friend.user_id = users.id, friend.receiver_id = users.id)')
                              ->where(array('friend.status' =>  Globals::FR_ACCEPTED)) // status which are accepted
                              ->where(function($query) use ($id){
                                $query->where(array(
                                               'friend.user_id'       => $id        // check whether user id matches sender id 
                                        ))
                                        ->orWhere(array(
                                                'friend.receiver_id'   => $id        // check whether user id matches receiver id 
                                        ));
                                 })
                                ->where('users.deleted', 'n');

不知何故,我无法将两个表连接在一起,因为friend.user_id和friend.receiver_id都引用了users.id。

我该如何实现?

还有其他有效方法吗?

2 个答案:

答案 0 :(得分:1)

使用Laravel时,可以使用users作为数据透视表,作为usersfriends之间的自引用多对多关系来实现。

如果您使用Laravel模型,请定义一个User模型和一个public function friends()关系,具体程度如下:

class User extends Model {
  ...
  public function friends(){
    return $this->belongsToMany(User::class, "friends", "user_id", "receiver_id");
  }
}

然后,您将可以简单地进行以下操作:

$user = User::with(["friends"])->first();
$friends = $user->friends;
dd($user, $friends);

如果您需要过滤该查询以仅显示接受的朋友,则只需执行以下操作:

$user = User::with(["friends" => function($query){
  $query->where("status", "=", Globals::FR_ACCEPTED);
}])->first();
$friends = $user->friends;
dd($user, $friends);

您甚至可以将status检查添加到关系的末尾,以便仅返回接受的朋友。但是,无论哪种方式,Laravel都提供了一些强大的工具来有效地处理此问题,因此请考虑使用它们。

https://laravel.com/docs/5.7/eloquent-relationships#many-to-many

答案 1 :(得分:0)

好吧,我将使用... join()并为表名加上别名以避免混淆(用户u,朋友f,用户朋友uf) )

$friendshipQuery = Friend::table('users as u')
                   ->join('friend as f', 'f.user_id', '=', 'u.id')
                   ->join('users as uf', 'f.receiver_id', '=', 'uf.id')
                   ->select('uf.*')
                   ->where('f.status', '1')
                   ->where('uf.deleted', 'n')
                   ->where('u.deleted', 'n')
                   ->where(function($query) use ($id)
                   {
                       $query->where(array('friend.user_id'       => $id))
                             ->orWhere(array('friend.receiver_id' => $id));
                   });

顺便说一句,笛卡尔联接是可怕且不赞成的

我会用这种方式重写SQL查询

SELECT uf.id, uf.fname, uf.lname
FROM users u
LEFT JOIN friend f ON u.id = f.user_id
LEFT JOIN users uf ON uf.id = f.receiver_id
WHERE (f.user_id = $id OR f.receiver_id = $id)
  AND (f.status = 1)
  AND (uf.deleted = 'n')
  AND (u.deleted = 'n')