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 的第三张桌子。它的架构看起来像

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

我想要做的是将这个第三个表(在 deal_id 上)加入我现有的查询中,并且还能够获得每笔交易收到的赞成票和反对票。

4

1 回答 1

1

要在单个查询中执行此操作,您可能需要使用 SQL 子查询,这在 Laravel 4/5 中似乎没有很好的流畅查询支持。由于您没有使用 Eloquent 对象,因此原始 SQL 可能最容易阅读。(请注意,下面的示例忽略了您的deals.deal_idandmerchants.merchant_id列,这可能会被删除。相反,它只是按照惯例使用您的deals.idandmerchants.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 回答