17370845950

如何在 MySQL 中精确统计今日订单总金额(PHP Yii2 实战教程)

本文详解如何使用 yii2 query 构建精准的“今日销售额”查询,避免因时间戳精度、分组逻辑或字段误用导致的统计偏差,确保即使当日无订单也能返回 `0` 而非昨日数据。

要准确获取 MySQL 表中 orders 表今日(仅限当前日期,忽略具体时分秒)已完成订单的 price 字段总和,关键在于:不能依赖 G

ROUP BY + ORDER BY + LIMIT 1 的组合逻辑——该方式会返回「最近有数据的那一天」,而非「今天」;同时,直接用 FROM_UNIXTIME(updated_at, '%Y-%m-%d') 在 WHERE 条件中做匹配也不可行,因其属于表达式字段,无法高效利用索引且易引发类型隐式转换问题。

✅ 正确做法是:在 WHERE 子句中显式限定今日的时间范围,并使用 COALESCE(SUM(price), 0) 确保无记录时返回 0。

以下是推荐的 Yii2 实现(兼容 Unix 时间戳与 DATETIME 字段):

✅ 方案一:updated_at 为 Unix 时间戳(INT 类型)

public function getTotalEarningsToday()
{
    $todayStart = strtotime(date('Y-m-d 00:00:00')); // 今日 00:00:00 时间戳
    $todayEnd   = strtotime(date('Y-m-d 23:59:59')); // 今日 23:59:59 时间戳

    $records = (new Query())
        ->select(['COALESCE(SUM(price), 0) AS total', 'DATE(FROM_UNIXTIME(updated_at)) AS day'])
        ->from(Orders::tableName())
        ->where([
            'AND',
            ['status' => Orders::STATUS_COMPLETED],
            ['>=', 'updated_at', $todayStart],
            ['<=', 'updated_at', $todayEnd],
        ])
        ->groupBy('day') // 可选:确保单日聚合
        ->one(); // 使用 one() 而非 all(),因只查今日一行

    // 若无记录,$records 为 false → 手动补全
    if (!$records) {
        return ['total' => 0, 'day' => date('Y-m-d')];
    }

    return $records;
}

✅ 方案二:created_at / updated_at 为 DATETIME 类型(更推荐)

public function getTotalEarningsToday()
{
    $today = date('Y-m-d');
    $records = (new Query())
        ->select(['COALESCE(SUM(price), 0) AS total', new \yii\db\Expression("'$today' AS day")])
        ->from(Orders::tableName())
        ->where([
            'AND',
            ['status' => Orders::STATUS_COMPLETED],
            ['>=', 'created_at', $today . ' 00:00:00'],
            ['<=', 'created_at', $today . ' 23:59:59'],
        ])
        ->one();

    return $records ?: ['total' => 0, 'day' => $today];
}

⚠️ 注意事项:

  • 勿用 FROM_UNIXTIME(...) 在 WHERE 中做等值匹配:如 'updated_at' => strtotime('2025-02-21') 仅匹配 updated_at = 1645401600(即恰好整日零点),而实际订单时间戳多为 1645412345,必然漏查。
  • 优先使用 created_at 而非 updated_at:订单完成状态变更可能触发 updated_at 更新,但销售额应归属下单日(即 created_at)。
  • 必须用 COALESCE(SUM(...), 0):MySQL 中 SUM() 对空结果集返回 NULL,需转为 0 才符合业务预期。
  • 索引优化建议:为 (status, created_at) 建联合索引,大幅提升查询性能。

最终调用示例:

$result = $this->getTotalEarningsToday();
echo "今日销售额:¥{$result['total']}({$result['day']})"; 
// 输出:今日销售额:¥0(2025-06-15) 或 今日销售额:¥249.50(2025-06-15)

此方案逻辑清晰、可读性强、健壮可靠,彻底解决“查到昨日数据而非今日零值”的核心痛点。