Сборный SELECT средствами Query Builder от Laravel 10

Рейтинг: 0Ответов: 1Опубликовано: 17.08.2023

Как выразить вот такой запрос средствами Query Builder от Laravel 10:

SELECT 
 3 AS month_num
UNION
SELECT 
 1
UNION
SELECT 
 2
ORDER BY month_num ASC

Пример конечно синтетический. Мне потом нужно к нему с помощью JOIN прицепить реальную таблицу. Но начать не могу, не получается и с этим.

Пробовал вот так, но вылетает ошибка и без сортировки:

$query = $this->select(DB::raw('3 AS month_num'))
              ->union(DB::raw('1'))
              ->union(DB::raw('2'));

Ответы

▲ 0Принят

Вопрос с горем пополам решил, может кому пригодиться ...

Для реализации запроса:

SELECT 
 3 AS month_num
UNION
SELECT 
 1
UNION
SELECT 
 2
ORDER BY month_num ASC

использую следующую конструкцию Query Builder:

$result = DB::query()->select(DB::raw('3 AS month_num'))
            ->union(DB::query()->select(DB::raw('1')))
            ->union(DB::query()->select(DB::raw('2')))
            ->orderBy('month_num', 'asc')
            ->get();

Результат состоит из трёх строк. Создаётся "на-лету" без каких-то временных или постоянных таблиц.

Пример практического применения

Пусть есть таблица бронирований bookings, и в ней значимые для последующей задачи поля:

  • created_at - дата создания записи
  • paid- флажок о поступившей оплате (0-нет, 1-да)
  • amount сумма оплаты за это бронирование

Задача: получить за 2023 год по каждому месяцу сумму оплат.

"Сырой" SQL-запрос это решает так:

SELECT
  month_table.month_num,
  IFNULL(SUM(bookings.amount), 0)
FROM
  bookings
RIGHT JOIN (
  SELECT 1 AS month_num
  UNION
  SELECT 2
  UNION
  SELECT 3
  UNION
  SELECT 4
  UNION
  SELECT 5
  UNION
  SELECT 6
  UNION
  SELECT 7
  UNION
  SELECT 8
  UNION
  SELECT 9
  UNION
  SELECT 10
  UNION
  SELECT 11
  UNION
  SELECT 12
) AS month_table
  ON
    month_table.month_num = MONTH(bookings.created_at) AND
    YEAR(bookings.created_at) = 2023 AND
    bookings.paid = 1
GROUP BY
  month_table.month_num
ORDER BY
  month_table.month_num ASC

А с помощью Laravel Query Builder это же самое у меня получилось сделать вот так:

  $result = DB::table('bookings')
            ->select('month_table.month_num', DB::raw('IFNULL(SUM(bookings.amount), 0) AS amount'))
            ->rightJoinSub(function ($subquery) {
                $subquery->select(DB::raw('1 AS month_num'))
                    ->union(DB::query()->select(DB::raw('2')))
                    ->union(DB::query()->select(DB::raw('3')))
                    ->union(DB::query()->select(DB::raw('4')))
                    ->union(DB::query()->select(DB::raw('5')))
                    ->union(DB::query()->select(DB::raw('6')))
                    ->union(DB::query()->select(DB::raw('7')))
                    ->union(DB::query()->select(DB::raw('8')))
                    ->union(DB::query()->select(DB::raw('9')))
                    ->union(DB::query()->select(DB::raw('10')))
                    ->union(DB::query()->select(DB::raw('11')))
                    ->union(DB::query()->select(DB::raw('12')));
            }, 'month_table', function ($join) {
              $join->on('month_table.month_num', '=', DB::raw('MONTH(bookings.created_at)'))
                ->where(DB::raw('YEAR(bookings.created_at)'), '=', 2023)
                ->where('bookings.paid', '=', 1);
            })->groupBy('month_table.month_num')
              ->orderBy('month_table.month_num', 'asc')
              ->get();

Предполагаю, что существуют более изящные решения такого вопроса. Если они у вас есть - пожалуйста, поделитесь!