我有三张表,关系如下,
------- 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
?
我相信这个是更好的解决方案.而不是像leftJoin
你一样使用Raw查询应该补充你的joinWith
关系andOnCondition
(在条件加入你的连接语句时需要添加).
$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
在关系中写条款时它看起来更干净.它的工作方式与在外面编写相同(如果我没有错),但在重构查询时,您可以轻松删除整个关系而不会忘记外部的关系条件.
只需使用以下条件.
$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();