Задать вопрос
Fragster
@Fragster
помогло? отметь решением!

Как перенести запрос с декартовым произведением в Eloquent relations?

В догонку к вопросу Как сделать динамический scope в relation?
Есть вот такая схема:
Vl4N9Mx.png
Нужно сделать relation типа HasMany, но который всегда содержал бы все AgreementType с отметкой, принята ли последняя редакция соглашения каждого типа.
Все данные по профилям получить можно таким вот запросом:
$profiles = Profile::limit(5)->get();
    $profileTable = with(new Profile)->getTable();
    $agreementTypeTable = with(new AgreementType)->getTable();
    $agreementProfileTable = with(new AgreementProfile())->getTable();
    $query = AgreementType::select("$agreementTypeTable.*", "$profileTable.id as profile_id")
      ->join($profileTable, DB::raw('1'), '=', DB::raw('1'))
      ->whereIn('profiles.id', $profiles->pluck('id'))
      ->addSelect(DB::raw("exists(select * from $agreementProfileTable where $agreementProfileTable.agreement_id = $agreementTypeTable.last_agreement_id and $agreementProfileTable.profile_id = $profileTable.id and $agreementProfileTable.agreement_id = $agreementTypeTable.last_agreement_id) as last_agreement_approved"));
    $query->get();


Но дальше нужно результат выводить результат $profiles и было бы очень удобно, если бы к соответствующему profile был бы уже приделан отфильтрованный результат.

Есть ли возможность запихать декартово произведение в relation?
  • Вопрос задан
  • 70 просмотров
Подписаться 1 Средний Комментировать
Решения вопроса 1
Fragster
@Fragster Автор вопроса
помогло? отметь решением!
В итоге сделал view в mysql, содержащий нужные данные (заодно переделал exists на join, потому что судя по explain так чуть лучше используются индексы, хотя, конечно, надо в боевых условиях сравнивать):
return new class extends Migration
{
  /**
   * Run the migrations.
   */
  public function up(): void
  {
    $prefix = DB::getTablePrefix();
    $agreementTypesTable = "agreement_types";
    $profilesTable = "profiles";
    $agreementProfileTable = "agreement_profile";
    $sqlQuery = DB::table($agreementTypesTable)
      ->select([
        "$agreementTypesTable.id as agreement_type_id",
        "$agreementTypesTable.last_agreement_id as last_agreement_id",
        "$profilesTable.id as profile_id",
        DB::raw("!ISNULL($agreementProfileTable.profile_id) as last_agreement_approved"),
      ])
      ->join($profilesTable, DB::raw('1'), '=', DB::raw('1'))
      ->leftJoin($agreementProfileTable, function (JoinClause $join) use ($agreementProfileTable, $agreementTypesTable, $profilesTable) {
        $join->on("$agreementProfileTable.agreement_id", "=", "$agreementTypesTable.last_agreement_id")
          ->on("$agreementProfileTable.profile_id", "=", "$profilesTable.id");
      })
      ->toSql();

    DB::statement("CREATE VIEW ${prefix}agreement_type_profile AS ($sqlQuery)");
  }

  /**
   * Reverse the migrations.
   */
  public function down(): void
  {
    $prefix = DB::getTablePrefix();
    DB::statement("DROP VIEW ${prefix}agreement_type_profile");
  }
};
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы