Вопрос с горем пополам решил, может кому пригодиться ...
Для реализации запроса:
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();
Предполагаю, что существуют более изящные решения такого вопроса. Если они у вас есть - пожалуйста, поделитесь!