В продолжение к вопросу <a href="https://qna.habr.com/q/1393140" rel="nofollow">Как сделать динамический scope в relation?</a>, хочу уточнить: у меня есть следующая схема: <br/>
Чтобы преобразовать запрос с использованием декартова произведения в отношения Eloquent, вам нужно использовать методы, предоставляемые Eloquent для работы с отношениями между моделями. Декартово произведение предполагает, что все возможные комбинации записей из двух таблиц должны быть представлены. В Eloquent это можно сделать с помощью метода `join`, или используя `hasMany`, `belongsTo`, `belongsToMany` и другие методы для работы с отношениями. Пример схемы баз данных и соответствующих моделей: - У вас есть таблица `users` и таблица `posts`, и вы хотите получить все комбинации пользователей и их постов (декартово произведение). ### Пример: ```php // Модель User class User extends Model { public function posts() { return $this->hasMany(Post::class); } } // Модель Post class Post extends Model { public function user() { return $this->belongsTo(User::class); } } // Получение всех комбинаций пользователей и постов $users = User::all(); $posts = Post::all(); $combinations = []; foreach ($users as $user) { foreach ($posts as $post) { $combinations[] = [ 'user_id' => $user->id, 'user_name' => $user->name, 'post_id' => $post->id, 'post_title' => $post->title, ]; } } // $combinations теперь содержит декартово произведение пользователей и постов ``` ### Использование запроса с `join` Если нужно выполнить запрос к базе данных напрямую с использованием `join`, вы можете сделать это следующим образом: ```php $combinations = DB::table('users') ->crossJoin('posts') ->select('users.id as user_id', 'users.name as user_name', 'posts.id as post_id', 'posts.title as post_title') ->get(); ``` ### Примечания: - Декартово произведение может привести к большому количеству строк, особенно если у вас много записей в обеих таблицах. Поэтому используйте его с осторожностью. - Если это просто для отображения данных, разумнее использовать отношения Eloquent и загружать связанные данные при помощи методов типа `with`, чтобы избежать избыточных соединений. - Если вам нужно фильтровать результаты, добавьте соответствующие условия в запросы или используйте локальные скоупы предварительно. Если у вас есть дополнительные вопросы или требуется более конкретный пример, пожалуйста, уточните!
В итоге сделал 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"); } };