web-dev-qa-db-ja.com

Laravel Query Builderを使用してサブクエリから選択する方法は?

Eloquent ORMを使用して、次のSQLで値を取得したいと思います。

-SQL

 SELECT COUNT(*) FROM 
 (SELECT * FROM abc GROUP BY col1) AS a;

それから私は次のことを考えました。

-コード

 $sql = Abc::from('abc AS a')->groupBy('col1')->toSql();
 $num = Abc::from(\DB::raw($sql))->count();
 print $num;

より良い解決策を探しています。

最も簡単な解決策を教えてください。

76
quenty658

@delmadordの回答とコメントに加えて:

現在、FROM句にサブクエリを作成する方法がないため、生のステートメントを手動で使用する必要があり、必要に応じて、すべてのバインディングをマージします。

$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance

$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
    ->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
    ->count();

バインディングを正しい順序でマージする必要があることに注意してください。他のバインド句がある場合は、mergeBindingsの後に配置する必要があります。

$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )

    // ->where(..) wrong

    ->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder

    // ->where(..) correct

    ->count();
110
Jarek Tkaczyk

Laravel v5.6.12(2018-03-14)クエリビルダーにfromSub()およびfromRaw()メソッドを追加 (#23476) .

受け入れられた答えは正しいですが、次のように簡略化できます。

DB::query()->fromSub(function ($query) {
    $query->from('abc')->groupBy('col1');
}, 'a')->count();

上記のスニペットは、次のSQLを生成します。

select count(*) as aggregate from (select * from `abc` group by `col1`) as `a`
42
mpskovvang

@JarekTkaczykのソリューションは、まさに私が探していたものです。 DB::table()クエリを使用しているときに、それを行う方法だけが見逃します。この場合、これは私がそれを行う方法です:

$other = DB::table( DB::raw("({$sub->toSql()}) as sub") )->select(
    'something', 
    DB::raw('sum( qty ) as qty'), 
    'foo', 
    'bar'
);
$other->mergeBindings( $sub );
$other->groupBy('something');
$other->groupBy('foo');
$other->groupBy('bar');
print $other->toSql();
$other->get();

getQuery()メソッドを使用せずにmergeBindingsを作成する方法に特に注意してください

11
Thiago Mata

laravel 5.5から、サブクエリ専用のメソッドがあり、次のように使用できます。

Abc::selectSub(function($q) { $q->select('*')->groupBy('col1'); }, 'a')->count('a.*');

または

Abc::selectSub(Abc::select('*')->groupBy('col1'), 'a')->count('a.*');

3
Sasa Blagojevic

目的のクエリを実行するコードを作成できませんでした。ASは、派生テーブルではなく、テーブルabcのみのエイリアスです。 Laravel Query Builderは、派生テーブルエイリアスを暗黙的にサポートしていません。これにはDB :: rawが必要になる可能性が高いです。

私が思いついた最も簡単な解決策はあなたのものとほとんど同じですが、あなたが求めたようにクエリを生成します:

$sql = Abc::groupBy('col1')->toSql();
$count = DB::table(DB::raw("($sql) AS a"))->count();

生成されたクエリは

select count(*) as aggregate from (select * from `abc` group by `col1`) AS a;
1
delmadord

私はこのようなことをするのが好きです:

Message::select('*')
->from(DB::raw("( SELECT * FROM `messages`
                  WHERE `to_id` = ".Auth::id()." AND `isseen` = 0
                  GROUP BY `from_id` asc) as `sub`"))
->count();

あまりエレガントではありませんが、シンプルです。

1
Guy Mazuz