Есть ли какой-нибудь "Laravel-ish" способ зафиксировать самые ранние и самые поздние даты из нескольких полей даты в нескольких таблицах laravel?
таблица для модели1:
fielda
| fieldb
| date1
таблица2 для модели2:
fieldc
| fieldd
| date1
| date2
Я не мог найти никакого элегантного способа сделать это. Мой текущий подход выглядит примерно так:
$model1_dates = Model1::select(\DB::raw('MIN(date1) as min_date'), \DB::raw('MAX(date1) as max_date'))->get();
$model2_dates = Model2::select(\DB::raw('MIN(date2) as min_date'), \DB::raw('MAX(date2) as max_date'))->get();
$model2_dates2 = Model2::select(\DB::raw('MIN(date2) as min_date'), \DB::raw('MAX(date1) as max_date'))->get();
после этого я сравню результаты и получу минимум и максимум из них...
Какие подходы были бы лучше?
Итак, для этого нет никакого подхода "Laravel"...
Моя первая попытка была примерно такой: `$earliest model 1 = Model 1::order By('idate1', 'asc')->pluck('date1')->first();`, но это будет означать еще одну шаг к сравнению
Да, есть такие функции, как max()
и min()
. Также вы можете объединить два запроса с помощью метода union()
Агрегированные методыСоюз
И вы также можете использовать orderBy
с laravel. Работает также на даты.
Сортировать по
Самый быстрый способ:
$minDateModel1 = Model1::min('date1');
$maxDateModel1 = Model1::max('date1');
Или:
$minDateModel1 = Model1::oldest('date1')->first()->pluck('date1');
$maxDateModel1 = Model1::latest('date1')->first()->pluck('date1');
Или:
$minDateModel1 = Model1::max('date1');
//should be the oldest first, newest at last
$minDateModel1 = Model1::orderBy('date1', 'asc')->first()->pluck('date1');
$maxDateModel1 = Model1::orderBy('date1', 'asc')->first()->pluck('date1');
Должен сделать трюк:
$minDateModel1 = Model1::max('date1');
$minDateModel21 = Model2::max('date1');
$minDateModel22 = Model2::max('date2');
$allMinDates = $allMinDates->merge($minDateModel1);
$allMinDates = $allMinDates->merge($minDateModel21);
$allMinDates = $allMinDates->merge($minDateModel22);
$min = $allMinDates->min();
Как я прокомментировал ветку комментариев к вопросам, OrderBy
был моим первым подходом.
Отредактировал ответ. Надеюсь, вам понравится, и вы оставите несколько голосов.
Я немного упростил код для ясности, на самом деле у меня есть как минимум 5 полей даты в 3 разных таблицах. @PaulSpiegel, не могли бы вы опубликовать ответ о том, как должен выглядеть SQL-запрос? Будет ли это хорошим случаем для использования оператора CASE
sql?
Прошил ларавельский способ, ни разу не было сказано, что это быстрее или лучше sql. Он также может запустить необработанный sql-запрос внутри laravel. Он также может определить функции, которые найдут для него минимум и максимум и просто вызовут их в запросе.
@AngelinCalu Но необработанный запрос не похож на Laravel.
@liqSTAR Я просто хочу убедиться, что для вас «laravel-ish» — это что-то вроде «аккуратный код любой ценой — производительность не имеет значения».
Теперь я понимаю, что подход «ларавела» не подходит для моего текущего случая. Думал, что это может быть какой-то вспомогательный метод, который мне может не хватать. Если необработанный запрос - это путь, я выберу этот маршрут :)
В laravel простой способ - это один запрос для каждого столбца, который я хочу найти, мин/макс. Затем мне нужно снова проверить результаты. В SQL вы должны присоединиться к таблице и выполнить НАИМЕНЬШЕЕ или БОЛЬШЕЕ минимальное/максимальное значение каждого столбца. Но вы также проверяете каждую колонку. Еще три запроса в одном запросе. Что касается целочисленных операций, которые необходимо выполнить, я бы сказал, что это тот же объем работы. Независимо от того, что мы предпочитаем... ответ на вопрос.
Любые рекомендуемые подходы к необработанному запросу?
Обычный выбор, присоединение к любой таблице с датами, затем указание имен столбцов каждой таблицы в функции НАИМЕНЬШИЙ. LEAST(min(t1.date1),min(t2.date2),min(t2.date2),...)
«Что касается целочисленных операций, которые необходимо выполнить, я бы сказал, что это тот же объем работы» - речь идет вовсе не о количестве «операций». Речь идет о задержке. Не стоит недооценивать коммуникационные издержки SQL-запроса даже в локальной базе данных. 6 запросов против 1 может быть не так уж и много. Но когда у вас есть 20 таблиц и около 50 полей с датами, мне будет не все равно.
Я использовал Laravel, но я не фанат - поэтому я действительно не знаю, что такое Laravel-ish или что это такое. Если вы имеете в виду "что-то, что выглядит просто", то это может быть
$minDate = collect([
Model1::min('date1'),
Model2::min('date1'),
Model2::min('date2'),
])->min();
$maxDate = collect([
Model1::max('date1'),
Model2::max('date1'),
Model2::max('date2'),
])->max();
Это аккуратно - но это 6 запросов к БД.
Один необработанный SQL будет
select min(min_date) as min_date, max(max_date) as max_date
from (
select min(date1) as min_date, max(date1) as max_date from table1
union all
select min(date1) as min_date, max(date1) as max_date from table2
union all
select min(date2) as min_date, max(date2) as max_date from table2
) x
или
select min(min_date) as min_date, max(max_date) as max_date
from (
select min(date1) as min_date, max(date1) as max_date
from table1
union all
select min(least(date1, date2)) as min_date,
max(greatest(date1, date2)) as max_date
from table2
) x
в зависимости от того, какие у вас индексы. Первый запрос работает лучше, когда у каждого столбца даты есть свой индекс.
Мне нравится твой ответ. Честно и довольно прямолинейно. Это то, что я мог придумать. Не могли бы вы помочь мне проверить производительность этого решения по сравнению с вашим? sqlfiddle.com/#!9/caa5e3/7
FROM table1, table2
это перекрестное соединение - хуже вряд ли получится :)
В случае производительности я бы предложил добиться этого на стороне MySQL. Выберите из своих таблиц, упорядочите по *, получите первый результат и последний результат.