7

Here's the query in raw SQL:

SELECT * 
FROM (
    SELECT `characters`.`id`,`characters`.`refreshToken`,
           `characters`.`name`,max(`balances`.`created_at`) as `refreshDate`
        FROM `characters`
        INNER JOIN `balances` ON `characters`.`id` = `balances`.`character`
        WHERE `characters`.`refreshToken` IS NOT NULL
        GROUP BY `characters`.`id`
) AS `t1`
WHERE `refreshDate` < '2017-03-29';

I've tested this in phpMyAdmin and it returns the expected results. However I'm using the Eloquent and Laravel libraries in my PHP app and I'm not sure how to approach this. How exactly do subqueries work in this case?

3
  • 3
    Give it a try before asking how to do something, sorry Peter but SO isn't coding request website! You can find in Laravel's docs a lot of things about this. Commented Mar 30, 2017 at 14:19
  • 2
    I have and have drawn a blank. If you read the question I asked how subqueries work, I didn't ask for someone to give me the solution. Looking to learn here not just be given code. Commented Mar 30, 2017 at 14:58
  • 1
    Thanks for asking this question, i was looking solution of this issue in Lumen. Thanks again :) Commented Feb 7, 2019 at 13:38

2 Answers 2

10

You can do a subquery as a table but need to create the subquery first and then merge the bindings into the parent query:

$sub = Character::select('id', 'refreshToken', 'name')
    ->selectSub('MAX(`balances`.`created_at`)', 'refreshDate')
    ->join('balances', 'characters.id', '=', 'balances.character')
    ->whereNotNull('characters.refreshToken')
    ->groupBy('characters.id');

DB::table(DB::raw("($sub->toSql()) as t1"))
    ->mergeBindings($sub)
    ->where('refreshDate', '<', '2017-03-29')
    ->get();

If that is your entire query you can do it without the subquery and use having() instead like:

Character::select('id', 'refreshToken', 'name')
    ->selectSub('MAX(`balances`.`created_at`)', 'refreshDate')
    ->join('balances', 'characters.id', '=', 'balances.character')
    ->whereNotNull('characters.refreshToken')        
    ->groupBy('characters.id')
    ->having('refreshDate', '<', '2017-03-29');
Sign up to request clarification or add additional context in comments.

Comments

7

You can use subqueries in Eloquent by specifying them as a closure to the where method. For example:

$characters = Character::where(function ($query) {
    // subqueries goes here
    $query->where(...
          ...
          ->groupBy('id');
})
->where('refreshDate', '<', '2017-03-29')
->get();

You have to chain your methods to the $query variable that is passed to the closure in the above example.

If you want to pass any variable to the subquery you need the use keyword as:

$characterName = 'Gandalf';

$characters = Character::where(function ($query) use ($characterName) {
    // subqueries goes here
    $query->where('name', $characterName)
          ...
          ->groupBy('id');
})
->where('refreshDate', '<', '2017-03-29')
->get();

2 Comments

thanks for this - do subqueries have to go inside a where clause or can I also use them in a from clause?
I'm not completely sure about that. You could try and see if that works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.