Reputation: 1
How can I translate this SQL to Eloquent?
SELECT *
FROM actions A1
WHERE A1.recurring_pattern IS NOT NULL AND
A1.parent_id IS NOT NULL AND
A1.due_date = (
SELECT MIN(due_date)
FROM actions A2
WHERE A2.parent_id = A1.parent_id AND
due_date > NOW()
)
Upvotes: 0
Views: 234
Reputation: 831
If I'm not mistaken, what you want to do is to get one action per sibling of actions, which satisfies the conditions:
If that's the case, your query can be simplified to:
SELECT * FROM actions
WHERE recurring_pattern IS NOT NULL
AND parent_id IS NOT NULL
AND due_date > NOW()
GROUP BY parent_id
HAVING MIN(due_date)
Basically you SELECT
actions that satisfy the outlined conditions above, then GROUP
them BY
their parents, and finally pick one action per group HAVING
the closest due date. This approach to querying eliminates the need to subquery.
Now, onto implementing the simplified query in Laravel Eloquent, we can define an Action
model as follows:
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
class Action extends Model
{
/**
* Scope to actions that have recurring pattern.
*/
function scopeHasRecurringPattern(Builder $query)
{
$query->where('recurring_pattern', '<>', null);
}
/**
* Scope to actions that have parents.
*/
function scopeHasParent(Builder $query)
{
$query->where('parent_id', '<>', null);
}
/**
* Scope to actions not due by the given date.
*/
function scopeIsNotDueBy(Builder $query, Carbon $now)
{
$query->where('due_date', '>', $now);
}
}
Then finally, we perform the query by doing:
Action::hasRecurringPattern() // 👈 filter actions having recurring patterns
->hasParent() // 👈 filter actions having parents
->isNotDueBy(now()) // 👈 filter actions not past due
->groupBy('parent_id') // 👈 group these filtered actions by identical parents
->havingRaw('MIN(due_date)') // 👈 finally pick the action per group having the closest due date
->get();
Upvotes: 1