如何将原始 SQL 转换为 Yii2,如查找查询
Posted
技术标签:
【中文标题】如何将原始 SQL 转换为 Yii2,如查找查询【英文标题】:How to transform raw SQL into Yii2 like find query 【发布时间】:2019-03-31 17:07:52 【问题描述】:我无法将原始 SQL 查询转换为类似 Yii2 的方法。我想通过过滤和排序从我的 RAW sql 实现网格视图。我使用 ActiveDataProvider 和 ModelSearch 中的方法作为 Yii 默认方式。
我确实尝试使用 Model::findBySql,但它不允许我在网格视图中过滤或排序我的结果。我不想使用 SQLDataProvider,因为我的查询中有关系。
我看到将 Model::FindBySql($sql) 更改为 Model::find 可以让我进行排序和过滤,但结果与预期不符。我必须将此 SQL 转换为使用 Model::Find() 方法
我很难改变的 sql 是
$sql = 'SELECT A.*, (6371 * acos(cos(radians("'.$mapSearch->gps_lat.'")) * cos(radians(gps_lat))*cos(radians(gps_long)-radians("'.$mapSearch->gps_long.'"))+sin(radians("'.$mapSearch->gps_lat.'"))*sin(radians(gps_lat)))) AS distance FROM address A JOIN contest_has_address CA On A.id = CA.address_id JOIN contest C On C.id = CA.contest_id JOIN contest_has_date CD On C.id = CD.contest_id JOIN date D On D.id = CD.date_id WHERE main = 1 AND C.status = 1 AND D.start_time > "'.$today.'" HAVING distance < "'.$mapSearch->distance.'" ORDER BY distance ASC';
我的控制器:
if($mapSearch->save(false))
$lat = $mapSearch->gps_lat;
$long = $mapSearch->gps_long;
$sql = 'SELECT A.*, (6371 * acos(cos(radians("'.$mapSearch->gps_lat.'")) * cos(radians(gps_lat))*cos(radians(gps_long)- radians("'.$mapSearch->gps_long.'"))+sin(radians("'.$mapSearch->gps_lat.'") )*sin(radians(gps_lat)))) AS distance FROM address A JOIN contest_has_address CA On A.id = CA.address_id JOIN contest C On C.id = CA.contest_id JOIN contest_has_date CD On C.id = CD.contest_id JOIN date D On D.id = CD.date_id WHERE main = 1 AND C.status = 1 AND D.start_time > "'.$today.'" HAVING distance < "'.$mapSearch->distance.'" ORDER BY distance ASC';
$models = Address::findBySql($sql)->all();
$count = Yii::$app->db->createCommand($sql)->queryScalar();
$dataProvider = $searchModel->searchMapAddress(Yii::$app->request->queryParams, $sql);
return $this->render('map', [
'sql'=>$sql,
'searchModel'=>$searchModel,
'models'=>$models,
'dataProvider'=>$dataProvider,
'mapSearch'=>$mapSearch,
'lat'=>$mapSearch->gps_lat,
'long'=>$mapSearch->gps_long,
]);
我的模特
$query = Address::findBySql($sql);
$query->joinWith(['contest']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
并查看:
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'layout'=> 'items',
【问题讨论】:
【参考方案1】:假设您的原始 SQL 查询工作正常,您可以使用 ActiveRecord 或 Query Builder 来创建您的查询。
要在查询中使用 mysql 函数,您必须使用 \yii\db\Expresion
,并且在构建查询时,您应该在查询末尾使用 ->createCommand()->rawSQL
替换为 ->one()
或 ->all()
,并回显查询以查看RAW SQL 查询的构建内容并将其与原始查询进行比较。
您可以使用以下查询:
$query=Address::find()->alias('A')
->select([new Expression('A.*, (6371 * acos(cos(radians("' . $mapSearch->gps_lat . '")) * cos(radians(gps_lat))*cos(radians(gps_long) -radians("' . $mapSearch->gps_long . '")) + sin(radians("' . $mapSearch->gps_lat . '"))*sin(radians(gps_lat)))) AS distance')])
->join('left join', 'content_has_address CA', 'A.id = CA.address_id')
->join('left join', 'contest C', 'C.id = CA.contest_id')
->join('left join', 'contest_has_date CD', 'C.id = CD.contest_id')
->join('left join', 'date D', 'D.id = CD.date_id')
->where(
['AND',
['=', 'main', 1],
['=', 'C.status', 1],
['>', 'D.start_time', $today]
]
)
->having(['<', 'distance', $mapSearch->distance])
->orderBy('distance asc');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
【讨论】:
acos(cos(radians(....
不要将 sql server 用作计算器。在您的 php 代码中计算并仅将结果传递给查询
@MarcinOrlowski 谢谢你的提示会这样做,还没有考虑性能
@MarcinOrlowski 问题是关于转换查询而不是优化它,我没有添加任何内容
@MuhammadOmerAslam:我以为我在 OP 的帖子下发布了该说明,而不是您的答案。显然不是 - 我的错,对不起。
@MarcinOrlowski 它的好兄弟,它发生了 :)以上是关于如何将原始 SQL 转换为 Yii2,如查找查询的主要内容,如果未能解决你的问题,请参考以下文章