Reputation: 435
my knowledge on mysql is very basic and now im facing a "complex" (for me) query in which im stuck so thank you in advance if someone could give me some light on this.
I have three tables:
Orders
id | name | comments | ...
OrderLines
id | name | sDate | eDate | comments | ...
OrderLinesStats
id | lineID | date | status | ...
Every day OrderLinesStats is updated via a cron job and gets a new record with actual date, status and other fields so the highest id is the actual data.
Im trying to get that last stats row with a relation in yii2 as follows:
in OrdersLines model:
public function getLastOrdersLinesStats()
{
return $this->hasMany(OrdersLinesStats::className(), ['lineID' => 'id'])
->orderBy(['id'=>SORT_DESC])
->groupBy('lineID');
}
OrdersModel:
public function getOrdersLines()
{
return $this
->hasMany(OrdersLines::className(), ['orderID' => 'id'])
->orderBy(['typeID' => SORT_ASC, 'name' => SORT_ASC])
->with(['lastOrdersLinesStats']);
}
But when I debug the query looks like this:
SELECT * FROM `ordersLinesStats` WHERE `lineID` IN (1873, 1872, 1884, 1883, 1870, 1874, 1876, 1880, 1871, 1877, 1881, 1882, 1885, 1886, 1869, 1875, 1878) GROUP BY `lineID` ORDER BY `id` DESC
and doesnt give me the last stats record for each line... in fact, it gives me the oldest one. Seems that im missing something but i cant find it.
Thanks again
Upvotes: 4
Views: 5619
Reputation: 3777
I am just answering this to be thorough and hopefully help other's who stumble upon this page.
I recommend always including both, hasOne
and hasMany
. This way, you can pop the top record, or retrieve all of them.
/**
* @return \yii\db\ActiveQuery
*/
public function getUserPlan()
{
return $this->hasOne(UserPlan::className(), ['user_id' => 'id'])
->orderBy(['id' => SORT_DESC])
->one();
}
/**
* @return \yii\db\ActiveQuery
*/
public function getUserPlans()
{
return $this->hasMany(UserPlan::className(), ['user_id' => 'id'])
->orderBy(['id' => SORT_DESC])
->all();
}
hasMany
will return an array of ActiveQuery Objects, where hasOne
will return just an ActiveQuery Object by itself.
You use them like so (example in UserController on User model):
$model = $this->findOne($id);
or
$model = User::findOne($id);
or
$model = User::find()->where(['id' => $id])->one();
Then grab the relations like so:
$plan = $model->userPlan
or
$plans = $model->userPlans
For userPlan:
$planId = $plan->id;
Handling userPlans:
foreach($plans as $plan) {
$plan->id;
}
Upvotes: 1
Reputation: 2499
All you need to do is change the getLastOrdersLinesStats()
to be as follows:
public function getLastOrdersLinesStats()
{
return $this->hasMany(OrdersLinesStats::className(), ['lineID' => 'id'])
->orderBy(['id'=>SORT_DESC])
->one();
}
This basically returns the last OrderLinesStats row that you want for each Order
You can access this as follows:
if you have an object called myOrder
for example
then you can access the row you want as myOrder->lastOrderLinesStats
Upvotes: 6
Reputation: 3008
In OrdersModel add getLastOrderLineStat() method that uses via() junction:
public function getLastOrderLineStat()
{
return $this->hasOne(OrdersLinesStats::className(), ['lineID' => 'id'])
->orderBy(['id'=>SORT_DESC])
->groupBy('lineID')
->via('ordersLines');
}
If $model is an OrdersModel instance, you obtain the last stat row using:
$model->lastOrderLineStat
Upvotes: 4