Как использовать JOIN в Laravel, когда два столбца одной таблицы ссылаются на один столбец другой таблицы? - PullRequest
0 голосов
/ 09 ноября 2018

у меня две таблицы: -

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 Eloquent?

Я пытался сделать что-то вроде этого: -

$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 голосов
/ 09 ноября 2018

При использовании Laravel это может быть выполнено как самоотносящаяся связь «многие ко многим» между users и users, используя friends в качестве сводной таблицы.

Если вы используете модели 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

0 голосов
/ 09 ноября 2018

Ну, я бы использовал ... 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')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...