Laravel 在单个子句中使用多个 where 和 sum
Laravel use multiple where and sum in single clause
在我的数据库中我有 instagram_actions_histories
table 其中我有 action_type
列,在列中我有不同的数据,例如 1
或 2
或 3
我正在尝试获取此 table 关系数据并对存储在列中的此值求和,例如
$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))
我如何实施此解决方案?
更新:
Instagram 账号class:
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:
class InstagramActionsHistory extends Model
{
protected $guarded=['id'];
public function page(){
return $this->belongsTo(InstagramAccount::class);
}
}
用户class:
class User extends Authenticatable
{
use Notifiable;
...
public function instagramPages()
{
return $this->hasMany(InstagramAccount::class);
}
}
selectSub()
创建您在其中使用聚合 (SUM
) 的子查询,但 select()
是一个缩放器 returns 一个缩放器结果;除非你使用 grouping.If 你想 return 每个用户的结果,否则不允许在同一级别混合聚合与缩放器查询,尝试添加 groupBy
,这里我假设 id
是users
table
上的主键
$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();
另一种获取不同类型操作的条件总和的方法,您可以在 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
要检查生成的查询,请参阅
在我的数据库中我有 instagram_actions_histories
table 其中我有 action_type
列,在列中我有不同的数据,例如 1
或 2
或 3
我正在尝试获取此 table 关系数据并对存储在列中的此值求和,例如
$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))
我如何实施此解决方案?
更新:
Instagram 账号class:
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:
class InstagramActionsHistory extends Model
{
protected $guarded=['id'];
public function page(){
return $this->belongsTo(InstagramAccount::class);
}
}
用户class:
class User extends Authenticatable
{
use Notifiable;
...
public function instagramPages()
{
return $this->hasMany(InstagramAccount::class);
}
}
selectSub()
创建您在其中使用聚合 (SUM
) 的子查询,但 select()
是一个缩放器 returns 一个缩放器结果;除非你使用 grouping.If 你想 return 每个用户的结果,否则不允许在同一级别混合聚合与缩放器查询,尝试添加 groupBy
,这里我假设 id
是users
table
$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();
另一种获取不同类型操作的条件总和的方法,您可以在 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
要检查生成的查询,请参阅