我有三个表格,其中包含以下关系,
------- 1 0..* ------------
|Product|-------------|Availability|
------- ------------
1 |
|
1 |
--------
|MetaData|
--------
我的原始sql看起来像这样
SELECT p.ID FROM product p
LEFT JOIN availability a ON a.productID=p.ID
AND a.start>=DATE_ADD(DATE(now()), INTERVAL 7 DAY)
LEFT JOIN meta_data m ON m.ID=p.meta_dataID
WHERE a.ID IS NULL
AND m.published_state=1;
也就是说,找到每个Product
MetaData.published_state
等于1
且没有Availability
,Availability.start
超过7天now()
}}。
我正在尝试使用ActiveRecord
方法完成相同的操作,使用类似下面的内容
$products = Product::find()
->joinWith('metaData')
->joinWith('availability')
->onCondition(['>=', 'availability.start', strtotime('+7 days')])
->where(['is', 'availability.ID', NULL])
->andWhere(['=', 'meta_data.published_state', 1])
->all();
但是,这没有结果。使用Connection::createCommand()
运行原始sql会返回我期望的行,因此数据没有问题。
我怀疑这个问题是由join
条件引起的,where
条件“互相流血”;加入和应用于加入或在哪里而不是分开。
如何输出正在运行的实际sql查询?这是从控制台控制器调用的动作。
如何更改代码以返回所需的Products
?
答案 0 :(得分:7)
我相信这是一个更好的解决方案。与其使用leftJoin
之类的Raw查询,不如使用joinWith
来补充andOnCondition
关系(这将需要的条件添加到join语句中)。
$products = Product::find()
->joinWith(['metaData' => function (ActiveQuery $query) {
return $query
->andWhere(['=', 'meta_data.published_state', 1]);
}])
->joinWith(['availability' => function (ActiveQuery $query) {
return $query
->andOnCondition(['>=', 'availability.start', strtotime('+7 days')])
->andWhere(['IS', 'availability.ID', NULL]);
}])
->all();
此外,当您在关系内编写where
子句时,它看起来更干净。它的工作原理与在外部编写相同(如果我没看错),但是在重构查询时,您可以轻松删除整个关系,而不会忘记外部的关系条件。
答案 1 :(得分:5)
只需使用以下条件即可。
$query = Product::find()
-> leftJoin('availability', 'availability.productID=product.ID AND a.start>=DATE_ADD(DATE(now()), INTERVAL 7 DAY)')
->leftJoin('meta_data', 'meta_data.ID=product.meta_dataID')
->where(['is', 'availability.ID', NULL])
->andWhere(['=', 'meta_data.published_state', 1])
->all();
答案 2 :(得分:0)
使用此:
$sql = 'SELECT p.ID FROM product p
LEFT JOIN availability a ON a.productID=p.ID
AND a.start>=DATE_ADD(DATE(now()), INTERVAL 7 DAY)
LEFT JOIN meta_data m ON m.ID=p.meta_dataID
WHERE a.ID IS NULL
AND m.published_state=1';
$products = Product::findBySql($sql);
Yii Active Record具有findBySql($sql)
方法,该方法允许您使用原始SQL查询运行并从数据库获取数据。当您对Yii的查询方法感到困惑时,或者当您想让查询与Yii一起运行变得更加复杂时,这很有用。
因此,基本上,在上面的代码块中,您只是将原始SQL查询放入了一个名为$sql
的变量中,并将其用作了findBySql()
方法的参数值。