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

Yii2中按广告商ID与服务商ID分组筛选最大日期对应记录的实现问题

解决Yii2中GROUP BY后获取每组最大日期对应完整记录的问题

你的问题核心在于:当你在SELECT中包含非聚合且未出现在GROUP BY中的字段(比如id、companyID)时,MySQL在非严格模式下会随机返回这些字段的值,而非对应MAX(date)的那条记录的值,这就是你得到错误id和companyID的原因。

下面提供两种可靠的解决方案,你可以根据MySQL版本和需求选择:

方法一:子查询关联(兼容所有MySQL版本)

先通过子查询获取每个(advertiserID, providerID)组的最大日期,再关联原表筛选出对应完整记录:

// 第一步:构建子查询,得到每组的最大日期
$subQuery = CompaniesAdvertisersProvidersAssoc::find()
    ->select(['advertiserID', 'providerID', 'MAX(date) as max_date'])
    ->groupBy(['advertiserID', 'providerID']);

// 第二步:主查询关联子查询,匹配出对应最大日期的完整记录
$currentAssoc = CompaniesAdvertisersProvidersAssoc::find()
    ->select([
        'companiesAdvertisersProviders.id as bmAssocID',
        'companiesAdvertisersProviders.date',
        'advertiserID',
        'providerID',
        'companyID',
        'advertisers.name as advertiser',
        'providers.name as provider',
        'companies.id as companyID',
        'companies.name as company',
        'advertisers.image as advertiserImage',
        'providers.image as providerImage',
        'companies.companyLogo as bmImage'
    ])
    ->joinWith(['advertiser', 'provider', 'company'], false)
    ->innerJoin(
        ['sub' => $subQuery],
        'companiesAdvertisersProviders.advertiserID = sub.advertiserID 
         AND companiesAdvertisersProviders.providerID = sub.providerID 
         AND companiesAdvertisersProviders.date = sub.max_date'
    )
    ->orderBy([
        'company' => SORT_ASC,
        'advertiser' => SORT_ASC
    ])
    ->asArray()
    ->all();

这个方法逻辑清晰:先锁定每组的最大日期,再通过关联条件精准定位到对应的完整记录,彻底避免了随机取值的问题。

方法二:窗口函数(MySQL 8.0+ 推荐)

如果你的MySQL版本是8.0及以上,用ROW_NUMBER()窗口函数可以更简洁地实现需求:

$currentAssoc = CompaniesAdvertisersProvidersAssoc::find()
    ->select([
        'bmAssocID' => 't.id',
        't.date',
        't.advertiserID',
        't.providerID',
        't.companyID',
        'advertisers.name as advertiser',
        'providers.name as provider',
        'companies.id as companyID',
        'companies.name as company',
        'advertisers.image as advertiserImage',
        'providers.image as providerImage',
        'companies.companyLogo as bmImage',
        // 给每个(advertiserID, providerID)组按日期降序编号
        'ROW_NUMBER() OVER (PARTITION BY t.advertiserID, t.providerID ORDER BY t.date DESC) as rn'
    ])
    ->from(['t' => CompaniesAdvertisersProvidersAssoc::tableName()])
    ->joinWith(['advertiser', 'provider', 'company'], false)
    // 只保留每组的第一条(即日期最大的记录)
    ->having('rn = 1')
    ->orderBy([
        'company' => SORT_ASC,
        'advertiser' => SORT_ASC
    ])
    ->asArray()
    ->all();

窗口函数会给每个分组内的记录按日期降序分配序号,rn=1就代表该组日期最大的那条记录,代码更简洁高效。

额外说明

如果某个(advertiserID, providerID)组内存在多条日期相同且都是最大的记录,上述两种方法会返回所有符合条件的记录。如果需要只保留其中一条(比如按id最大的),可以在子查询或窗口函数的排序条件里加上id DESC即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 18:58:14