使用Laravel查询生成器加入条件计数

时间:2016-02-11 02:57:29

标签: laravel-5.1 laravel-5.2 laravel-query-builder

我正在尝试使用Laravel Query构建器实现以下功能。

我有一张叫做特价的桌子。以下是基本架构

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上)加入到我现有的查询中,并且还可以获得每笔交易收到的upvotes和down票。

1 个答案:

答案 0 :(得分:1)

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