web-dev-qa-db-fra.com

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

Ré,

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();

Cela ne fonctionne 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 générateur couramment).

42
MarkL

OK, après quelques expériences, voici la solution que je propose:

$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();

setBindings doit être appelé sur la requête. Je souhaite que cela a été documenté!

83
MarkL

Ancienne question, mais si nous devons répéter une variable, nous devons modifier sa valeur de clé dans le tableau de liaisons.

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

C'est assez.

22
bluesky777

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
Stefan Z

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, le :lat et le :lng sont des paramètres nommés alors que vous avez $radius comme positionnel. Donc, une solution possible à votre problème consiste à utiliser havingRaw() et à appliquer les paramètres nommés. 

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

2
jovani

J'ai porté la recherche à proximité de Doctrine v1 à Laravel, jetez-y un œil ici.

Ajoutez simplement le trait Geographical au modèle pour pouvoir ensuite:

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

Cela fonctionne en utilisant selectRaw avec des liaisons 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
malhal
$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
Danilo Lima