#php #mysql #laravel #eloquent #left-join
Вопрос:
У меня в приложении есть список модулей, которые игроки могут выполнить, и когда они это сделают, они должны перестать появляться в списке «доступные модули». У меня есть таблица «игроки», «модули» и «module_player», чтобы сохранить отношение.
Итак, в списке «доступные модули» я хочу показывать только те модули, которые еще не были запущены (т. е. в таблице module_player нет записи) или были запущены, но еще не завершены (т. е. статус 1 в таблице module_player).
Допустим, у меня есть:
таблица игроков
ID | Имя |
---|---|
1 | Игрок_1 |
2 | Игрок_2 |
таблица модулей
ID | Имя |
---|---|
1 | Module_1 |
2 | Модуль_2 |
3 | Module_3 |
таблица module_player
module_id | идентификатор игрока | Статус |
---|---|---|
1 | 1 | 1 |
2 | 1 | 2 |
«Список доступных» должен возвращать только модуль 1 (запущен, но не завершен) и модуль 3 (не запущен).
Проблема в том, что я получаю только модуль 1 в «списке доступных», в этом запросе, который у меня есть, очевидно, что-то не так:
$modules = DB::table('modules')
->join('module_player', 'modules.id', '=', 'module_player.module_id', 'left')
->join('players', 'module_player.player_id', '=', 'players.id', 'left')
->where('module_player.status', '!=', 2)
->where('module_player.player_id, '=', 1)
->select('modules.id', 'modules.name', 'modules.image', 'modules.mandatory')->paginate(10);
Спасибо
Комментарии:
1. почему вы не используете отношения?
2. хм, потому что я хочу получить не только модули, которые имеют отношение к плееру, но и модули, которые еще не имеют отношения, и разбитые на страницы
3. таким образом, вам нужны модули, статус которых равен 1 в module_player и которые не существуют в этой таблице. как 1 и 3?
4. да, это именно то, что мне нужно
Ответ №1:
Как вы используете
`where('module_player.player_id, '=', 1)`
Вы получите только записи, в которых идентификатор игрока равен 1, поэтому попробуйте выполнить следующий запрос с whereNotIn
$modules = DB::table('modules')
->join('module_player', 'modules.id', '=', 'module_player.module_id', 'left')
->join('players', 'module_player.player_id', '=', 'players.id', 'left')
->whereNotIn('modules.id', function($query){
$query->select('module_id')
->from('module_player')
->where('status', 2);
})
->select('modules.id', 'modules.name', 'modules.image', 'modules.mandatory')->paginate(10);
если вы хотите, чтобы это было для какого-либо конкретного пользователя, вы можете передать идентификатор игрока в use()
->whereNotIn('modules.id', function($query) use($player_id){
$query->select('module_id')
->from('module_player')
->from('player_id', $player_id)
->where('status', 2);
})
Комментарии:
1. Спасибо, первый работает. Хотелось бы немного объяснить, почему, потому что я думал, что независимо от того, какой пользователь вошел в систему, результаты будут одинаковыми (вот почему я использовал строку, которую вы удалили). Но я попытался запустить/завершить разные модули с двумя разными пользователями, и результаты в порядке. Я не вижу в запросе , как он мог узнать, что, например, у игрока 1 завершен модуль 1 и запущено 2, а у игрока 2 запущен модуль 1 и больше ничего, если я нигде не использую идентификатор игрока, вошедшего в систему. Спасибо!
Ответ №2:
удалите ->where('module_player.player_id, '=', 1)
строку, так как она вернет записи с идентификатором игрока 1. и попробуйте выполнить следующий запрос
$modules = DB::table('modules')
->join('module_player', 'modules.id', '=', 'module_player.module_id', 'left')
->join('players', 'module_player.player_id', '=', 'players.id', 'left')
->where('module_player.status', '!=', 2)
->select('modules.id', 'modules.name', 'modules.image', 'modules.mandatory')->paginate(10);