Comment lier des paramètres à une requête de base de données brute dans Laravel qui est utilisé sur un modèle?

Re,

j'ai la requête suivante:

$property = 
    Property::select(
        DB::raw("title, lat, lng, ( 
            3959 * acos( 
                cos( radians(:lat) ) * 
                cos( radians( lat ) ) * 
                cos( radians( lng ) - radians(:lng) ) + 
                sin( radians(:lat) ) * 
                sin( radians( lat ) ) 
            ) 
        ) AS distance", ["lat" => $lat, "lng" => $lng, "lat" => $lat])
    )
    ->having("distance", "<", $radius)
    ->orderBy("distance")
    ->take(20)
    ->get();

ça ne marche pas: Invalid parameter number: mixed named and positional parameters .

est-ce que quelqu'un connaît une astuce ou une solution de contournement (je peux évidemment écrire la requête complète mais préfère utiliser le constructeur fluent).

40
demandé sur Jonathan 2014-01-01 05:43:55

6 réponses

OK, après quelques expériences, voici la solution que j'ai trouvé:

$property = 
    Property::select(
        DB::raw("title, lat, lng, ( 
            3959 * acos( 
                cos( radians(  ?  ) ) *
                cos( radians( lat ) ) * 
                cos( radians( lng ) - radians(?) ) + 
                sin( radians(  ?  ) ) *
                sin( radians( lat ) ) 
            )
       ) AS distance")
    )
    ->having("distance", "<", "?")
    ->orderBy("distance")
    ->take(20)
    ->setBindings([$lat, $lng, $lat,  $radius])
    ->get();

fondamentalement, setBindings doit être appelé sur la requête. Ce voeu a été documenté!

80
répondu MarkL 2016-04-23 17:55:45

Vieille question, mais si nous devons répéter une variable, nous devons changer sa valeur de clé dans les liaisons tableau.

    $property = Property::select(
        DB::raw("title, lat, lng, ( 3959 * acos( cos( radians(:lat) ) * 
        cos( radians( lat ) ) * cos( radians( lng ) - radians(:lng) ) + 
        sin(radians(:lat_i) ) * sin( radians( lat ) ) ) ) AS distance"),
        ["lat" => $lat, "lng" => $lng, "lat_i" => $lat]);

ça suffit.

18
répondu bluesky777 2017-10-10 07:44:03

pourquoi pas?

    $latitude = $request->input('latitude', '44.4562319000');
    $longitude = $request->input('longitude', '26.1003480000');
    $radius = 1000000;

    $locations = Locations::selectRaw("id, name, address, latitude, longitude, image_path, rating, city_id, created_at, active,
                         ( 6371 * acos( cos( radians(?) ) *
                           cos( radians( latitude ) )
                           * cos( radians( longitude ) - radians(?)
                           ) + sin( radians(?) ) *
                           sin( radians( latitude ) ) )
                         ) AS distance", [$latitude, $longitude, $latitude])
        ->where('active', '1')
        ->having("distance", "<", $radius)
        ->orderBy("distance")
        ->get();
10
répondu Stefan Z 2016-02-25 15:06:57

j'ai rencontré le même problème tout récemment et la réponse se trouve dans le message d'erreur mixed named and positional parameters . Dans votre cas, les paramètres :lat et :lng sont nommés alors que vous avez $radius comme position. Ainsi, une solution possible à votre problème est de faire usage de havingRaw() et d'appliquer les paramètres nommés.

--havingRaw('distance < :radius', ['radius' => $radius])

2
répondu jovani 2016-08-15 01:59:47
$select = <<<SQL
    title,
    lat,
    lng,
    (3959*acos(cos(radians( ? ))*cos(radians(lat))*cos(radians(lng)-radians( ? ))+sin(radians( ? ))*sin(radians(lat)))) AS distance
SQL;

$property = Property::selectRaw($select, [$lat, $lng, $lat])
    ->having('distance', '<', $radius)
    ->orderBy('distance')
    ->take(20)->get();
0
répondu Danilo Lima 2015-12-30 14:38:49

j'ai porté la recherche à proximité de Doctrine v1 à Laravel, regardez ici.

il suffit d'ajouter le trait Geographical au modèle alors vous pouvez faire:

$model->newDistanceQuery($request->query('lat'), $request->query('lon'))->orderBy('miles', 'asc')->get();

il fonctionne en utilisant selectRaw avec des fixations comme ceci:

$sql = "((ACOS(SIN(? * PI() / 180) * SIN(" . $latName . " * PI() / 180) + COS(? * PI() / 180) * COS(" . $latName . " * PI() / 180) * COS((? - " . $lonName . ") * PI() / 180)) * 180 / PI()) * 60 * ?) as " . $unit;
if($kilometers){
    $query->selectRaw($sql, [$lat, $lat, $lon, 1.1515 * 1.609344]);
}
else{
    // miles
    $query->selectRaw($sql, [$lat, $lat, $lon, 1.1515]);
}
0
répondu malhal 2016-10-01 21:54:40