How to transform raw SQL into Yii2 like find query

此生再无相见时 提交于 2020-03-05 05:20:04

问题


I can't convert raw SQL query in to Yii2 like method. I'd like to implement grid view from my RAW sql with filtering and sorting. I'm using ActiveDataProvider with method in the ModelSearch as Yii default way.

I did try to use Model::findBySql but it is not letting me filter or sort my results in the grid view. I don't want to useSQLDataProvider because I have relations in my queries.

I see that changing Model::FindBySql($sql) to Model::find is letting me sort and filter but the results are not as expected. I have to transform this SQL to use Model::Find() method

My sql I struggle to change is

$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';

my Controller:

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,
                ]);

My Model

$query = Address::findBySql($sql);
    $query->joinWith(['contest']);

    $dataProvider = new ActiveDataProvider([
        'query' => $query,
    ]); 

and view:

echo GridView::widget([
                    'dataProvider' => $dataProvider,
                    'filterModel' => $searchModel,
                    'layout'=> '{items}',

回答1:


Assuming that your raw SQL query is working correctly you can use ActiveRecord or Query Builder to create your query.

For using MYSQL functions inside the query you must use \yii\db\Expresion, and while building the query you should use ->createCommand()->rawSQL at the end of the query replacing with ->one() or ->all(), and echo the query to see what the RAW SQL query is built and compare it with the original query.

You can use the following query:

$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,
]); 


来源:https://stackoverflow.com/questions/55443342/how-to-transform-raw-sql-into-yii2-like-find-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!