Как сгруппировать по агрегации столбца во внешней таблице с отношением «многие ко многим» в Eloquent? - PullRequest
0 голосов
/ 25 июня 2019

У меня начинаются головные боли из-за этого, поэтому я решил просто опубликовать это здесьУ меня есть две таблицы, которые связаны через сводную таблицу (так как это отношение многие ко многим).Я использую Laravel и Eloquent (но общая помощь в том, как этого добиться с помощью обычных запросов SQL, также высоко ценится).
Я хочу заказать первую таблицу на основе столбца второй, но столбец должен быть «агрегирован»за это.

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

Car-Table: [id, color]  
Driver-Table: [id, name]  
Car.Driver-Table: [car_id, driver_id]

Мне нужен запрос, который получает все драйверы, которые только ездят на красных автомобилях итогда все, что не водит красные машины.
Мне нужно использовать запрос, потому что я, возможно, впоследствии сделаю другие вещи (например, фильтрацию) с этим запросом и в конце хочу разбить на страницы.
Я уже использую запросы, которые получают одну из двух групп.Они выглядят так: В модели драйвера:

public function redCars() {
    return $this->cars()->where('color', 'red');
}

public function otherColoredCars() {
    return $this->cars()->where('color', '<>', 'red');
}

А затем где-то в контроллере:

$driversWithOnlyRedCars = Driver::whereDoesntHave('otherColoredCars')->get();
$driversWithoutRedCars = Driver::whereDoesntHave('redCars')->get();

Есть ли способ объединить эти два?
Может быть, яЯ просто думаю, что здесь неправильно.

Обновление для уточнения:
В принципе мне нужно что-то подобное (или любым другим способом, который приведет к тому же результату)

$driversWithOnlyRedCars->addTemporaryColumn('order_column', 0); // Create temporary column with value 0
$driversWithoutRedCars->addTemporaryColumn('order_column', 1);
$combinedQuery = $driversWithOnlyRedCars->combineWith($driversWithoutRedCars); // Somehow combine both queries
$orderedQuery = $combinedQuery->orderBy('order_colum');
$results = $combinedQuery->get();

Обновление 2
Думаю, я узнал, как приблизиться к своей цели с помощью необработанных запросов.
Было бы что-то вроде этого:

$a = DB::table(DB::raw("(
  SELECT id, 0 as ordering
  FROM drivers
  WHERE EXISTS (
    SELECT * FROM cars
    LEFT JOIN driver_car ON car.id = driver_car.car_id
    WHERE driver.id = driver_car.driver_id
    AND cars.color = 'red'
  )
) as only_red_cars"));

$b = DB::table(DB::raw("(
  SELECT id, 1 as ordering
  FROM drivers
  WHERE EXISTS (
    SELECT * FROM cars
    LEFT JOIN driver_car ON car.id = driver_car.car_id
    WHERE driver.id = driver_car.driver_id
    AND cars.color <> 'red'
  )
) as no_red_cars"));

$orderedQuery = $a->union($b)->orderBy('ordering');

Теперь проблема в том, что мне нужномодели, заказанные таким образом, и в итоге разбиты на страницы, так что это не совсем ответ на мой вопрос.Я пытался преобразовать это обратно в модели, но мне пока не удалось.Что я пробовал:

$queriedIds = array_column($orderedQuery->get()->toArray(), 'id');
$orderedModels = Driver::orderByRaw('(FIND_IN_SET(drivers.id, "' .  implode(',', $queriedIds) . '"))');

Но похоже, что FIND_IN_SET допускает только столбец таблицы в качестве второго параметра.Есть ли другой способ получить модели в правильном порядке из запроса упорядоченного объединения?

Ответы [ 2 ]

0 голосов
/ 05 июля 2019

Вы можете использовать запрос UNION:

$driversWithOnlyRedCars = Driver::select('*', DB::raw('0 as ordering'))
    ->whereDoesntHave('otherColoredCars');

$driversWithoutRedCars = Driver::select('*', DB::raw('1 as ordering'))
    ->whereDoesntHave('redCars');

$drivers = $driversWithOnlyRedCars->union($driversWithoutRedCars)
    ->orderBy('ordering')
    ->orderBy('') // TODO
    ->paginate();

Как вы хотите заказать драйверы с одинаковым ordering?Вам следует добавить второе предложение ORDER BY, чтобы получать согласованный порядок каждый раз, когда вы выполняете запрос.

0 голосов
/ 25 июня 2019

Это лучшее, что я получил:

$driversWithOnlyRedCars = Driver::whereHas('cars',function($q){
  $q->where('color', 'red');
})->withCount('cars')->get()->where('cars_count',1);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...