Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SELECT sub-query with WHERE condition in Yii2 find() / QueryBuilder

I was able to find simple examples of sub-query building, but am unable to figure out nor find the solution when I need to include a WHERE condition. I am trying to simulate the following statement...

SELECT ParentTable.*, (SELECT MAX(ChildTable.NumberField) 
                       FROM ChildTable
                       WHERE ChildTable.FK_Id = ParentTable.Id)
FROM ParentTable

Guess I'd need something like...

$query = ParentClass::find()
        ->addSelect(
            ChildClass::find()
            ->where('childTable.fk_id=parentTable.id')
            ->max('childTable.field1')
        );

But it gives me an error: Column not found: 1054 Unknown column 'parentTable.id' in 'where clause'

EDIT: Including actual class/table names...

$endQuery = UnitSchedule::find()
            ->where('cm_courseschedule.id=cm_unitschedule.csch_id')
            ->max('cm_unitschedule.slot');
$query = CourseSchedule::find();
$query->addSelect($endQuery);
like image 554
Shahid Thaika Avatar asked Oct 18 '15 18:10

Shahid Thaika


3 Answers

Thanks Used_By_Already and Mike Ross, your replies helped me arrive at the final complete Yii2/MySQL solution below.

$query = ParentClass::find();
$subQuery = ChildClass::find()->select('fk_id, max(column1) as column1')->groupBy('fk_id');
$query->leftJoin(['T' => $subQuery], 'T.fk_id = parentTable.id');
like image 34
Shahid Thaika Avatar answered Nov 15 '22 05:11

Shahid Thaika


The example query, from a SQL perspective is using a "correlated subquery" inside the select clause and often this is a very inefficient way of forming a query.

SELECT ParentTable.*, (SELECT MAX(ChildTable.NumberField) 
                       FROM ChildTable
                       WHERE ChildTable.FK_Id = ParentTable.Id)
FROM ParentTable

Although it may appear at first glance to be more complex and hence less efficient, it is generally better for performance to avoid "correlated subqueries" in a select clause and substitute using a "derived table" instead, like this:

SELECT ParentTable.*,c.MxNum
FROM ParentTable
LEFT JOIN (
           SELECT ChildTable.FK_Id, MAX(ChildTable.NumberField) as MxNum FROM ChildTable
           GROUP BY ChildTable.FK_Id
           ) AS c ON c.FK_Id = ParentTable.Id

Note, a correlated subquery with a select clause might return NULL, and due to this, if replacing them with a derived table the equivalent join type is a LEFT OUTER JOIN (or simply LEFT JOIN) as this also permits a NULL result. However if you don't need NULLs for the column, then use the more efficient INNER JOIN instead.

Apologies in advance for not knowing Yii2 syntax, but it seems relevant to know an effective alternative approach which may assist in solving the issue.

like image 136
Paul Maxwell Avatar answered Nov 15 '22 04:11

Paul Maxwell


Try this because it works fine for me, i had similar situation where my table names are event and area_interest

 $query = new Query();
 $subquery = new Query();
 $subquery ->select(['area_intrest.interest'])
            ->from('area_intrest' )
            ->where('area_intrest.id = event.interest_id');

 $query ->select(['event.title',$query3])
            ->from('event');
 $command = $query->createCommand();
 $data = $command->queryAll();

In your condition you can even use max in the subquery in quotes and it will work fine.

like image 45
Mike Ross Avatar answered Nov 15 '22 04:11

Mike Ross