Reputation: 47
I'm currently having a problem with my query
TableA::find()
->select('*')
->joinWith(['TableB'])
->joinWith(['TableC'])
->joinWith(['TableD'])
->where([TableA.attribute1=1 or TableA.attribute2=1])
->andWhere([(further possible conditions on the other Tables)])
->all()
The usual execution order for SQL Queries is From (with joins)
and then where
.
Is there a way to execute the first where condition before the joins, to reduce the amount of joined lines? Something like
TableA::find()
->where([TableA.attribute1=1 or TableA.attribute2=1])
->select('*')
->joinWith(['TableB'])
->joinWith(['TableC'])
->joinWith(['TableD'])
->andWhere([(further possible conditions on the other Tables)])
->all()
Upvotes: 0
Views: 49
Reputation: 6144
You can modify the condition that is used for joining the tables.
In SQL it would look like this:
SELECT
*
FROM
`tableA`
JOIN `tableB` ON (
`tableA`.`FK` = `tableB`.`PK`
AND `tableA`.`attr1` = 'someValue'
)
JOIN tableC ON (`tableB`.`FK` = `tableC`.`PK`)
To do that in Yii you can use ActiveQuery::onCondition()
method. If you want to apply this condition only for this one query you can use callback in joinWith()
method to modify the query used for join.
$query = TableA::find()
->joinWith([
'tableB' => function(\yii\db\ActiveQuery $query) {
$query->onCondition(['tableA.attr1' => 'someValue']);
}
])
//... the rest of query
Other option would be using a subquery in FROM part of sql query like this:
SELECT
*
FROM
(
SELECT
*
FROM
`tableA`
WHERE
`attr1` = 'someValue'
) AS `tableA`
JOIN `tableB` ON (`tableA`.`FK` = `tableB`.`PK`)
In yii:
$subQuery = TableA::find()
->select('*')
->where(['attr1' => 'someValue']);
$query = TableA::find()
->select('*')
->from(['tableA' => $subQuery])
->joinWith('tableB')
// ... the rest of query
The main weakness of this approach is that temporary table from your subquery won't have any indexes so the join and other conditions will be slower. It might still be worth to use this approach if the tableA has a lot of rows and the condition you want to apply before join will reduce the number of rows significantly.
Upvotes: 1
Reputation: 577
Well, I think that's the best way at all. But if you don't print data from relation TableB
or TabelC
(you just get them only about where condition), you can set the relation like that:
TableA::find()
->joinWith('TableB', false) //dont load data from this relational table
->joinWith('TableC', false) //dont load data from this relational table
->joinWith(['TableD']) //load data from this relational table
->where([TableA.attribute1=1 or TableA.attribute2=1])
->andWhere([(further possible conditions on the other Tables)])
->all()
Upvotes: 0