Laravel Eloquent Postgresql Select with Case,然后按 Case 结果过滤
Posted
技术标签:
【中文标题】Laravel Eloquent Postgresql Select with Case,然后按 Case 结果过滤【英文标题】:Laravel Eloquent Postgresql Select with Case and then filter by Case result 【发布时间】:2021-04-02 15:52:11 【问题描述】:我有一个 CASE 原始语句,它为每一行生成一个状态。如果用户不想查看所有项目但特定集合,我想按此状态进行过滤。
$query = Device::leftJoin('devices_meters', 'devices_meters.device_id', '=', 'devices.id')
->leftJoin('device_measurements', 'device_measurements.device_id', '=', 'devices.id')
->select(
'devices.*',
DB::raw("
CASE
WHEN
devices.retired = false
AND devices.last_reported_utc_at > :dateFilter
AND SUM(device_measurements.flow) > 0
THEN 'active'
WHEN
devices.retired = false
AND devices.last_reported_utc_at > :dateFilter
AND SUM(device_measurements.flow) = 0
THEN 'online'
WHEN
devices.retired = false
AND devices.last_reported_utc_at <= :dateFilter
THEN 'offline'
WHEN
devices.retired = false
AND devices.serial_number IS NULL
THEN 'inactive'
WHEN
devices.retired = true
THEN 'retired'
END AS status,
MAX(devices_meters.activated_at) AS activated_at,
MAX(devices_meters.created_at) AS latest
"),
)
->setBindings(['dateFilter' => $dateFilter]);
->groupBy('devices.id', 'devices_meters.activated_at')
->orderBy('devices.installed_at', 'DESC')
->paginate($user->settings_pagination);
我试过了:
$query->where('status', '=', $status);
$query->having('status', '=', $status);
但是这些不起作用。我可以通过status
列过滤的方式是什么?
【问题讨论】:
【参考方案1】:由于status
并不是真正的列,所以只需要使用整个case 语句进行过滤即可。
如果$status
是“活动的”,那么您需要添加
WHERE (
devices.retired = false
AND devices.last_reported_utc_at > :dateFilter
AND SUM(device_measurements.flow) > 0
)
每个状态的 SQL 查询等等。
但是,使用 Eloquent,您可以 define local query scopes in your Device
model
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class Device extends Model
public function scopeActive(Builder $query, $dateFilter)
$hasNecessaryJoins = collect($query->getQuery()->joins)
->contains('table', 'device_measurements');
return $query
->unless($hasNecessaryJoins, function ($subquery)
// do the left Join if it's not done already
$subquery->leftJoin('device_measurements', 'device_measurements.device_id', '=', 'devices.id'));
)
->where(function($subquery) use ($dateFilter)
$subquery->where('retired', false)
->where('last_reported_utc_at', '>', $dateFilter)
->whereRaw('SUM(device_measurements.flow) > 0');
);
public function scopeOnline(Builder $query, $dateFilter)
// online seems to be the same as active?
return $query
->active($dateFilter);
public function scopeOffline(Builder $query, $dateFilter)
return $query
->where(function($subquery) use ($dateFilter)
$subquery->where('retired', false)
->where('last_reported_utc_at', '<=', $dateFilter);
);
public function scopeInactive(Builder $query, $dateFilter)
return $query
->where(function($subquery)
$subquery->where('retired', false)
->whereNull('serial_number');
);
public function scopeRetired(Builder $query, $dateFilter)
return $query
->where('retired', true);
有了这些范围,您可以致电$query->active($dateFilter)
、$query->online($dateFilter)
、$query->offline($dateFilter)
、$query->inactive($dateFilter)
、$query->retired($dateFilter)
。
所以如果你有$status = 'active'
,你可以打电话给$query->$status($dateFilter)
;
【讨论】:
以上是关于Laravel Eloquent Postgresql Select with Case,然后按 Case 结果过滤的主要内容,如果未能解决你的问题,请参考以下文章
在 Laravel 中使用诸如 JSON 函数之类的 Postgres 功能
php Laravel 5 Eloquent CheatSheet #laravel #eloquent