You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Yii2单查询实现:按created筛选用户并独立统计fail_date范围内cons_debit

在Yii2中单个查询实现多条件统计(不受主筛选条件约束)

你当前的问题核心是主查询通过created条件过滤了数据集,导致cons_debit的统计只能基于过滤后的行,无法覆盖该user_id所有行中fail_date符合条件的数据。要在单个查询中实现需求,需要调整查询逻辑,确保user_id的筛选基于created条件,但统计cons_debit时使用该user_id的全量数据。

方案一:子查询筛选目标user_id,关联全量数据统计

先通过子查询获取所有created在时间范围内的user_id,再基于这些user_id统计两个指标:

// 子查询:获取符合created时间条件的user_id(去重)
$userSubQuery = self::find()
    ->select('mrd.user_id')
    ->where(['>=', 'mrd.created', $start_date])
    ->andWhere(['<=', 'mrd.created', $end_date . ' 23:59:59'])
    ->groupBy('mrd.user_id');

// 主查询:统计指定user_id的两个指标
$result = self::find()
    ->select([
        'mrd.user_id',
        // 统计created在范围内的actual_revenue总和
        'total_revenue' => new \yii\db\Expression(
            'SUM(CASE WHEN mrd.created BETWEEN :start_date AND :end_date_full THEN mrd.actual_revenue ELSE 0 END)',
            [
                ':start_date' => $start_date,
                ':end_date_full' => $end_date . ' 23:59:59',
            ]
        ),
        // 统计fail_date在范围内的cons_debit总和(不受created约束)
        'cons_debit_total' => new \yii\db\Expression(
            'SUM(CASE WHEN mrd.fail_date BETWEEN :start_date AND :end_date_full THEN mrd.cons_debit ELSE 0 END)',
            [
                ':start_date' => $start_date,
                ':end_date_full' => $end_date . ' 23:59:59',
            ]
        )
    ])
    ->where(['in', 'mrd.user_id', $userSubQuery])
    ->groupBy('mrd.user_id')
    ->offset(max($params['page'] - 1, 0) * $params['limit'])
    ->orderBy(['total_revenue' => SORT_DESC])
    ->limit($params['limit'])
    ->asArray()
    ->all();

方案二:使用HAVING过滤user_id,无需子查询

通过条件聚合统计total_revenue,同时用HAVING子句确保user_id至少有一行created在时间范围内,这样cons_debit的统计可以覆盖该user_id的全量数据:

$result = self::find()
    ->select([
        'mrd.user_id',
        'total_revenue' => new \yii\db\Expression(
            'SUM(CASE WHEN mrd.created BETWEEN :start_date AND :end_date_full THEN mrd.actual_revenue ELSE 0 END)',
            [':start_date' => $start_date, ':end_date_full' => $end_date . ' 23:59:59']
        ),
        'cons_debit_total' => new \yii\db\Expression(
            'SUM(CASE WHEN mrd.fail_date BETWEEN :start_date AND :end_date_full THEN mrd.cons_debit ELSE 0 END)',
            [':start_date' => $start_date, ':end_date_full' => $end_date . ' 23:59:59']
        )
    ])
    ->groupBy('mrd.user_id')
    // 过滤出至少有一行created在时间范围内的user_id
    ->having(['>', 'SUM(CASE WHEN mrd.created BETWEEN :start_date AND :end_date_full THEN 1 ELSE 0 END)', 0])
    ->addParams([
        ':start_date' => $start_date,
        ':end_date_full' => $end_date . ' 23:59:59'
    ])
    ->offset(max($params['page'] - 1, 0) * $params['limit'])
    ->orderBy(['total_revenue' => SORT_DESC])
    ->limit($params['limit'])
    ->asArray()
    ->all();

关键说明

  • 两种方案都避免了在主查询WHERE中直接过滤created条件,确保cons_debit统计可以访问该user_id的所有行数据。
  • 方案一适合数据量较大的场景,子查询可以快速筛选出目标user_id,减少主查询处理的数据量;方案二更简洁,无需额外子查询。

内容的提问来源于stack exchange,提问作者Stern

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 06:14:56