При использовании groupby, как использовать столбец другой таблицы в качестве ключа группы?

#mysql #laravel #eloquent

Вопрос:

У меня есть столик tariff_groups :

ID Имя
1 Зеленые тарифы
2 Синие тарифы
3 Красные тарифы

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

ID thing_id тарифная группа Описание дельта
1 1 1 Хороший тариф Зеленой группы. 0
2 1 1 Еще более приятный тариф Зеленой группы. 1
3 1 1 Лучший зеленый тариф. 2
4 1 2 Классный синий тариф. 3
5 1 3 Удивительный красный тариф. 4

С помощью этого кода я получаю все тарифы thing , которые с id 1:

 $tariffs = DB::table('things_usage_tariffs')
    ->where(
        [
            'thing_id' => $id,
        ]
    )
    ->orderBy('delta', 'asc')
    ->get()
    ->groupBy('tariff_group')
    ;
 

Который возвращает:

 IlluminateSupportCollection {#1257 ▼
    1 => IlluminateSupportCollection {#1247 ▼
      #items: array:4 [▶]
    }
    2 => IlluminateSupportCollection {#1253 ▼
      #items: array:1 [▶]
    }
    3 => IlluminateSupportCollection {#1246 ▼
      #items: array:1 [▶]
    }
}
 

Это круто, но я хотел бы знать, как изменить запрос, который я получаю напрямую:

 IlluminateSupportCollection {#1257 ▼
    'Green tariffs' => array(4)
    'Blue tariffs' => array(1)
    'Red tariffs' => array(1)
}
 

Я знаю, что мог бы повторить результат и заменить цифровые клавиши их соответствующим названием тарифной группы, но для этого мне нужно было бы сделать другое заявление, в котором будут указаны имена, и я чувствую, что это можно сделать с помощью соединения. Есть какие-нибудь идеи?

Комментарии:

1. Один из простых способов-использовать красноречие в правильных отношениях.

Ответ №1:

С красноречивыми и правильными отношениями:

Две модели:

 class TariffGroup extends Model{
   public function thingsUsageTariffs(){
     return $this->hasMany(ThingsUsageTariff::class, 'tariff_group', 'id');
   }
}
class ThingsUsageTariff extends Model{
   public function tariffGroup(){
     return $this->belongsTo(TariffGroup::class, 'id', 'tariff_group');
   }
}
 

Теперь в вашем контроллере:

 $tariffs = TariffGroup::with(['thingsUsageTariffs' => function($query){
  return $query->orderBy('delta', 'asc');
}])->get();
 

должно получиться что-то похожее на то, чего вы хотите достичь.


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

 $tariffs = DB::table('things_usage_tariffs')
   ->join('tariff_groups', 'tariff_groups.id', '=', 'things_usage_tariffs.tariff_group')
   ->orderBy('things_usage_tariffs.delta', 'asc')
   ->get()
   ->groupBy('tariff_group')
   ->map(function ($group) { 
        return $group->keyBy('name'); 
   });
 

Этот результат должен быть ближе к желаемому результату.

Примечание: Имя должно быть уникальным, так как мы назначаем его в качестве ключей. Кроме того, этот код не тестируется, но я надеюсь, что это укажет вам правильное направление.

Комментарии:

1. Так что это не очень просто без использования моделей? Только с помощью конструктора запросов?

2. кроме того, это приводит к ошибке «mb_strpos() ожидает, что параметр 1 будет строковым, заданным объектом».

3. @Alex исправлено с помощью метода, чтобы исправить эту ошибку.

4. @Alex также добавил альтернативный метод, который не использует модели.

5. спасибо за ваши усилия. в итоге я создал модель тарифов и, используя сводные данные, я вроде как близок к тому, что мне нужно.