Laravel построитель запросов две таблицы в левом соединении - PullRequest
1 голос
/ 07 июня 2019

У меня есть следующий запрос, который я пытаюсь преобразовать в конструктор запросов Laravel, чтобы я мог воспользоваться автоматическим экранированием и т. Д.

SELECT subjects.name, report_comments.comment
FROM subjects
LEFT JOIN (report_comments, library_comments) ON subjects.id = library_comments.subject_id
AND report_comments.library_comment_id = library_comments.id
AND report_comments.report_id = 1

По сути, запрос говорит: «получить имена всех субъектов, и если у них есть соответствующий отчет_комментарий (через промежуточную таблицу library_comments), вернуть это вместе с субъектом» (у субъекта либо один, либо ноль отчет_комментариев по заданным критериям). Запрос работает, если я запускаю его непосредственно в MySQL, и возвращает ожидаемые результаты. report_comment.report_id = 1 на данный момент жестко запрограммирован, но в конечном итоге будет заполнителем, так что любой report_id может быть передан.

Пока мне удалось получить:

DB::table('subjects')->select(['subjects.name', 'report_comments.comment'])->leftJoin('report_comments', function ($join) {
$join->on('subjects.id', '=', 'library_comments.subject_id')
->on('report_comments.library_comment_id', '=', 'library_comments.id')
->on('report_comments.report_id', '=', '1');
})

Если я добавлю toSql, результат будет:

select `subjects`.`name`, `report_comments`.`comment` from `subjects` left join `report_comments` on `subjects`.`id` = `library_comments`.`subject_id` and `report_comments`.`library_comment_id` = `library_comments`.`id` and `report_comments`.`report_id` = `1`

Это почти то, что я хочу, за исключением того, что он не работает, потому что таблица library_comments вообще не упоминается:

Illuminate/Database/QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'library_comments.subject_id' in 'on clause' (SQL: select `subjects`.`name`, `report_comments`.`comment` from `subjects` left join `report_comments` on `subjects`.`id` = `library_comments`.`subject_id` and `report_comments`.`library_comment_id` = `library_comments`.`id` and `report_comments`.`report_id` = `1`)'

Что мне нужно сделать, так это сообщить функции leftJoin о report_comments и library_comments, но, похоже, нет никакого способа сделать это. Я попробовал:

leftJoin(['report_comments', 'library_comments'], function($join)

по предположению, что Laravel может преобразовать массив имен таблиц в (report_comments, library_comments), но это не сработало и дало мне следующее предупреждение:

PHP Notice:  Array to string conversion in /home/paul/sites/report-assistant/vendor/laravel/framework/src/Illuminate/Database/Grammar.php on line 39

Есть ли способ передать несколько таблиц в leftJoin, или мне нужно полностью переписать запрос для работы с компоновщиком запросов Laravel?

Я использую laravel/framework версию 5.8.21, и все мои зависимости обновлены (composer update && npm update).

Ответы [ 3 ]

1 голос
/ 07 июня 2019

Использование BD::raw

напишите запрос вот так и он будет работать

 DB::table('subjects')->select(['subjects.name, report_comments.comment'])->leftJoin(DB::raw('(report_comments, library_comments)'), function ($join) {
$join->on('subjects.id', '=', 'library_comments.subject_id')
->on('report_comments.library_comment_id', '=', 'library_comments.id')
->on('report_comments.report_id', '=', '1');
})
0 голосов
/ 07 июня 2019

После небольшой переделки мне удалось найти ответ в двух частях:

Сначала я должен был настроить эту часть соединения:

on('report_comments.report_id', '=', '1')

и замените его на:

where('report_comments.report_id', '=', '1')

Если бы я не сделал этого, Laravel заключил бы в кавычки 1 с обратными галочками, в результате чего MySQL интерпретировал бы его как имя столбца.

Другим изменением было использование DB::raw, которого я пытался избежать, но я не думаю, что это слишком плохо в этой ситуации, потому что я передаю жестко запрограммированную строку, а не пользовательский ввод (или что-то под влиянием пользовательского ввода ). leftJoin теперь выглядит так:

leftJoin(DB::raw('(report_comments, library_comments)')
0 голосов
/ 07 июня 2019

Не уверен, что это сработает, но я предполагаю, что это будет что-то в этом роде, надеюсь, вы что-то из этого получите.

В основном добавил проверку, чтобы увидеть, существует ли связь, если она существует, затем присоединитесь к ней.

Subject::select('subjects.name, report_comments.comment')
    ->leftJoin('library_comments', 'subjects.id, '=', library_comments.subject_id')
    ->leftJoin('report_comments', function($join){

          if(report->library->relationship){
              $join->on('report_comments.library_comment_id', '=', 'library_comments.id')
              ->where('report_comments.report_id', '=', '1');
          }

})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...