【问题标题】:Laravel Eloquent Postgresql Select with Case and then filter by Case resultLaravel Eloquent Postgresql Select with Case,然后按 Case 结果过滤
【发布时间】: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 列过滤的方式是什么?

【问题讨论】:

    标签: laravel postgresql eloquent


    【解决方案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-&gt;active($dateFilter)$query-&gt;online($dateFilter)$query-&gt;offline($dateFilter)$query-&gt;inactive($dateFilter)$query-&gt;retired($dateFilter)

    所以如果你有$status = 'active',你可以打电话给$query-&gt;$status($dateFilter)

    【讨论】:

      猜你喜欢
      • 2013-06-10
      • 2020-11-03
      • 2015-10-22
      • 2014-01-29
      • 1970-01-01
      • 1970-01-01
      • 2022-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多