【问题标题】:Laravel use multiple where and sum in single clauseLaravel 在单个子句中使用多个 where 和 sum
【发布时间】:2018-12-16 00:12:04
【问题描述】:

在我的数据库中我有instagram_actions_histories 表,其中我有action_type 列,在列中我有不同的数据,例如123

我正在尝试在关系中获取此表数据并将存储在列中的这些值相加,例如

$userAddedPagesList = auth()->user()->instagramPages()->with([
        'history' => function ($query)  {
            $query->select(['action_type as count'])->whereActionType(1)->sum('action_type');
        }
    ]
)->get();

顺便说一句,此代码不正确,因为我想在其中获取所有 history 和多个 sum

whereActionType(1)->sum('action_type')
whereActionType(2)->sum('action_type')
whereActionType(3)->sum('action_type')

例如(伪代码):

$userAddedPagesList = auth()->user()->instagramPages()->with([
        'history' => function ($query)  {
            $query->select(['action_type as like'])->whereActionType(1)->sum('action_type');
            $query->select(['action_type as follow'])->whereActionType(2)->sum('action_type');
            $query->select(['action_type as unfollow'])->whereActionType(3)->sum('action_type');
        }
    ]
)->get();

更新

$userAddedPagesList = auth()->user()->instagramPages()->with([
        'history' => function ($query) {
            $query->select('*')
                ->selectSub(function ($query) {
                    return $query->selectRaw('SUM(action_type)')
                        ->where('action_type', '=', '1');
                }, 'like')
                ->selectSub(function ($query) {
                    return $query->selectRaw('SUM(action_type)')
                        ->where('action_type', '=', '2');
                }, 'follow')
                ->selectSub(function ($query) {
                    return $query->selectRaw('SUM(action_type)')
                        ->where('action_type', '=', '3');
                }, 'followBack');
        }
    ]
)->get();

错误

Syntax error or access violation: 1140 Mixing of GROUP columns (MIN(),MAX(),COUNT(),...) with no GROUP columns is illegal if there is no GROUP BY clause (SQL: select *, (select SUM(action_type) where `action_type` = 1) as `like`, (select SUM(action_type) where `action_type` = 2) as `follow`, (select SUM(action_type) where `action_type` = 3) as `followBack` from `instagram_actions_histories` where `instagram_actions_histories`.`account_id` in (1, 2, 3))

我该如何实施这个解决方案?

更新:

InstagramAccount 类:

class InstagramAccount extends Model
{
    ...

    public function schedule()
    {
        return $this->hasOne(ScheduleInstagramAccounts::class, 'account_id');
    }

    public function history()
    {
        return $this->hasMany(InstagramActionsHistory::class, 'account_id');
    }
}

InstagramActionsHistory 类:

class InstagramActionsHistory extends Model
{
    protected $guarded=['id'];

    public function page(){
        return $this->belongsTo(InstagramAccount::class);
    }
}

用户类别:

class User extends Authenticatable
{
    use Notifiable;

    ...

    public function instagramPages()
    {
        return $this->hasMany(InstagramAccount::class);
    }
}

【问题讨论】:

  • 是您需要的原始查询,例如: select action_type, count(*) from your table group by action_type ?
  • @koalaok 我需要求和 action_type 时为 1,求和 action_type 时为 2,然后求和 action_type 时为 3
  • 也许我错过了一些额外的信息……但这对我来说越来越奇怪了。看起来你想对所有具有相同值的记录求和......通常它是一个计数......或者如果你真的需要 count()*value 的总和然后使用 SUM(): SELECT action_type, SUM( action_type) FROM instagram_actions_histories GROUP BY action_type
  • Laravel 是对的,您将聚合子查询 selectSub() 与普通缩放器结果 select('*') 混合在一起。您是否想要每个用户的结果以及各自的 SUM?
  • @Viney 如果我理解你的意思,对于每张有内部关系的桌子,每张action_type的总和更多@

标签: php laravel laravel-5.6


【解决方案1】:

另一种为不同类型的操作获取条件总和的方法,您可以在 InstagramAccount 模型中定义 hasOne() 关系,例如

public function history_sum()
{
    return $this->hasOne(InstagramActionsHistory::class, 'account_id')
        ->select('account_id',
            DB::raw('sum(case when action_type = 1 then 0 END) as `like`'),
            DB::raw('sum(case when action_type = 2 then 0 END) as `follow`'),
            DB::raw('sum(case when action_type = 3 then 0 END) as `followBack`')
        )->groupBy('account_id');
}

然后您可以将相关数据预加载为

$userAddedPagesList = auth()->user()->instagramPages()->with('history_sum')->get();

使用这种方法将只执行一个额外的查询,以根据您的条件获得 3 个不同的总和结果

select `account_id`,
sum(case when action_type = 1 then action_type else 0 END) as `like`, 
sum(case when action_type = 2 then action_type else 0 END) as `follow`, 
sum(case when action_type = 3 then action_type else 0 END) as `followBack` 
from `instagram_actions_histories` 
where `instagram_actions_histories`.`account_id` in (?, ?, ?) 
group by `account_id`

虽然与使用 withCount 的其他方法(这也是一个有效的答案)相比,将为每种操作类型添加 3 个相关的相关子查询,这可能会导致性能开销,但生成的查询将如下所示

select `instagram_account`.*, 
(select sum(action_type) from `instagram_actions_histories` where `instagram_account`.`id` = `instagram_actions_histories`.`account_id` and `action_type` = ?) as `like`, 
(select sum(action_type) from `instagram_actions_histories` where `instagram_account`.`id` = `instagram_actions_histories`.`account_id` and `action_type` = ?) as `follow`,
(select sum(action_type) from `instagram_actions_histories` where `instagram_account`.`id` = `instagram_actions_histories`.`account_id` and `action_type` = ?) as `followBack`
from `instagram_account` 
where `instagram_account`.`user_id` = ? 
and `instagram_account`.`user_id` is not null

要检查生成的查询,请参阅Laravel 5.3 - How to log all queries on a page?

【讨论】:

  • @M Khalid Junaid 你的帖子是我学习新方法的原因,谢谢
【解决方案2】:

selectSub() 创建您在其中使用聚合 (SUM) 的子查询,但 select() 是一个缩放器,返回一个缩放器结果;除非您使用分组,否则不允许在同一级别混合聚合和缩放查询。如果您想返回每个用户的结果,请尝试添加groupBy,这里我假设iduserstable 上的主键

$userAddedPagesList = auth()->user()->instagramPages()->with([
        'history' => function ($query) {
            $query->select('*')
                ->selectSub(function ($query) {
                    return $query->selectRaw('SUM(action_type)')
                        ->where('action_type', '=', '1');
                }, 'like')
                ->selectSub(function ($query) {
                    return $query->selectRaw('SUM(action_type)')
                        ->where('action_type', '=', '2');
                }, 'follow')
                ->selectSub(function ($query) {
                    return $query->selectRaw('SUM(action_type)')
                        ->where('action_type', '=', '3');
                }, 'followBack');

            $query->groupBy('users.id');   //<-- add this
        }
    ]
)->get();

【讨论】:

  • 关系表是instagram_actions_histories 而不是user,实际上我正在尝试在instagram_actions_histories 中求和action_type,当我将您的组更改为$query-&gt;groupBy('instagram_actions_histories.id') 时出现此错误:SQLSTATE[42000]: Syntax error or access violation: 1055 'instacheeta.instagram_actions_histories.account_id' isn't in GROUP BY
  • ohh.. 我建议发布所有涉及的表结构。
猜你喜欢
  • 2020-09-28
  • 2018-09-05
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 2020-07-26
  • 2017-05-20
  • 2013-10-29
  • 2015-06-03
相关资源
最近更新 更多