0

Laravel Query builder で次のことを達成しようとしています。

deal というテーブルがあります。以下は基本的なスキーマです

id
deal_id
merchant_id
status
deal_text
timestamps

スキーマが次のマーチャントという別のテーブルもあります

id
merchant_id
merchant_name
about
timestamps

現在、次のクエリを使用して取引を取得しています

$deals = DB::table('deals')
        -> join ('merchants', 'deals.merchant_id', '=', 'merchants.merchant_id')
        -> where ('merchant_url_text', $merchant_url_text)
        -> get();

取引に関連付けられているマーチャントは 1 つだけなので、クエリで取引と関連するマーチャント情報を取得しています。

これで、tbl_deal_votes という 3 番目のテーブルができました。そのスキーマは次のようになります

id
deal_id
vote (1 if voted up, 0 if voted down)
timestamps

私がやりたいことは、この 3 番目のテーブル (deal_id で) を既存のクエリに結合し、各取引が受け取った賛成票と反対票も取得できるようにすることです。

4

1 に答える 1

1

単一のクエリでこれを行うには、おそらく SQL サブクエリを使用する必要がありますが、これは Laravel 4/5 で適切な流暢なクエリをサポートしていないようです。Eloquent オブジェクトを使用していないため、生の SQL がおそらく最も読みやすいでしょう。deals.deal_id(以下の例では、 and列を無視することに注意してくださいmerchants.merchant_id。これは、削除される可能性があります。代わりに、規則により、 deals.idandフィールドのみを使用します。)merchants.id

$deals = DB::select(
    DB::raw('
        SELECT
            deals.id AS deal_id,
            deals.status,
            deals.deal_text,
            merchants.id AS merchant_id,
            merchants.merchant_name,
            merchants.about,
            COALESCE(tbl_upvotes.upvotes_count, 0) AS upvotes_count,
            COALESCE(tbl_downvotes.downvotes_count, 0) AS downvotes_count
        FROM
            deals
        JOIN merchants ON (merchants.id = deals.merchant_id)
        LEFT JOIN (
            SELECT deal_id, count(*) AS upvotes_count
            FROM tbl_deal_votes
            WHERE vote = 1 && deal_id
            GROUP BY deal_id
        ) tbl_upvotes ON (tbl_upvotes.deal_id = deals.id)
        LEFT JOIN (
            SELECT deal_id, count(*) AS downvotes_count
            FROM tbl_deal_votes
            WHERE vote = 0
            GROUP BY deal_id
        ) tbl_downvotes ON (tbl_downvotes.deal_id = deals.id)
    ')
);

流暢を使用したい場合は、これでうまくいくはずです:

$upvotes_subquery = '
    SELECT deal_id, count(*) AS upvotes_count
    FROM tbl_deal_votes
    WHERE vote = 1
    GROUP BY deal_id';

$downvotes_subquery = '
    SELECT deal_id, count(*) AS downvotes_count
    FROM tbl_deal_votes
    WHERE vote = 0
    GROUP BY deal_id';

$deals = DB::table('deals')
    ->select([
        DB::raw('deals.id AS deal_id'),
        'deals.status',
        'deals.deal_text',
        DB::raw('merchants.id AS merchant_id'),
        'merchants.merchant_name',
        'merchants.about',
        DB::raw('COALESCE(tbl_upvotes.upvotes_count, 0) AS upvotes_count'),
        DB::raw('COALESCE(tbl_downvotes.downvotes_count, 0) AS downvotes_count')
    ])
    ->join('merchants', 'merchants.id', '=', 'deals.merchant_id')
    ->leftJoin(DB::raw('(' . $upvotes_subquery . ') tbl_upvotes'), function($join) {
        $join->on('tbl_upvotes.deal_id', '=', 'deals.id');
    })
    ->leftJoin(DB::raw('(' . $downvotes_subquery . ') tbl_downvotes'), function($join) {
        $join->on('tbl_downvotes.deal_id', '=', 'deals.id');
    })
    ->get();

流暢なクエリに関するいくつかの注意事項:

  1. DB::raw() メソッドを使用して、選択したいくつかの列の名前を変更しました。deals.id そうしないと、 と の間で結果に矛盾が生じていたでしょうmerchants.id
  2. COALESCE を使用して、null投票をデフォルトで 0 にしました。
  3. 読みやすくするために、サブクエリを個別の PHP 文字列に分割します。
  4. サブクエリに左結合を使用したため、賛成票/反対票のない取引がまだ表示されます。
于 2016-02-11T05:39:02.960 に答える