如何将原始 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,并且在构建查询时,您应该在查询末尾使用 -&gt;createCommand()-&gt;rawSQL 替换为 -&gt;one()-&gt;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,如查找查询的主要内容,如果未能解决你的问题,请参考以下文章

在 Yii2 中执行原始 SQL 查询?

将原始 SQL 与 Doctrine 一起使用

sql语句中如何将字符类型转换成数字类型?

如何将 DAO 查询转换为 Yii2 ActiveRecord。如何从连接表中选择和使用特定列

Oracle中如何用SQL把字符串转换成整型

SQL查询,如何将查询结果的一列拼接接在结尾行上。如