I’m working on a Laravel project where I need to calculate an estimated_value
for each record in my SalesLead
model by multiplying the probability
and value
columns. I want to filter records based on this computed column.
I used a global scope to add the computed column like this:
class EstimatedValueScope implements Scope
{
public function apply(Builder $builder, Model $model): void
{
$builder->addSelect([
'*',
DB::raw('COALESCE(probability, 0) * COALESCE(value, 0) * 0.01 AS estimated_value'),
]);
}
}
And applied it to my model:
class SalesLead extends Model
{
protected static function booted()
{
static::addGlobalScope(new EstimatedValueScope);
}
}
I want to filter records using this computed column, for example:
$salesLeads = SalesLead::where('estimated_value', '>', 1000000)->get();
But I get an SQL error:
SQLSTATE[42703]: Undefined column: 7 ERROR: column "estimated_value" does not exist
LINE 1: ...t count(*) as aggregate from "sales_leads" where ("estimated...
^
Note: I need to use Eloquent’s where
method to filter by estimated_value
, just like with any other column, and avoid using whereRaw
or DB:Raw
.
Questions:
- How can I properly filter and query based on this computed
estimated_value
column? - Is using a global scope for this purpose the right approach? If not, what would be the best way to handle this?
- How can I ensure that the
estimated_value
column is included in the query and used correctly for filtering?
2
Answers
I believe that we have to use
having
instead ofwhere
for aggregated columns likeestimated_value
:Filtering and querying based on a computed column in Eloquent requires a bit of care because the computed column doesn’t exist in the database, so you can’t directly use Eloquent’s
where
method as you would with a regular column. Here’s how you can approach this:Hope it will be useful for you:
Using a Global Scope with a Subquery:
Querying with a Subquery for Filtering:
An Alternative: Use an Accessor:
You can then filter like this, although this will involve fetching all the records and filtering in memory:
Using
whereRaw
: