SQL запрос с Laravel Красноречивые и именованные привязки: смешанные именованные и позиционные параметры - PullRequest
0 голосов
/ 09 января 2020

Я пытаюсь выполнить следующий запрос. Примечание. В этом запросе я должен использовать именованные параметры . Я не понимаю проблему, потому что кажется, что я использую только именованные параметры. Как я могу заставить работать именованные параметры?

Примечание: запрос полностью функциональный, когда я выполняю его в БД или в laravel с помощью простой DB :: table (users) -> выберите ($ sql_with_values_inside)

Я новичок в Laravel, поэтому, возможно, я делаю это неправильно.

Запрос

$latitude = (float)$latitude;
$longitude = (float)$longitude;
$radius = (float)$radius;

$sql = '`firstname`,`lastname`,`email`,
     ST_X(`coordinates_public`) AS latitude,
     ST_Y(`coordinates_public`) AS longitude,
     (6371 * ACOS(COS(RADIANS(:latitude)) * COS(RADIANS(ST_Y(coordinates_private))) * COS(RADIANS(ST_X(coordinates_private)) - RADIANS(:longitude)) + SIN(RADIANS(:latitude)) * SIN(RADIANS(ST_Y(coordinates_private))))) AS distance';

$washers = DB::table('users')
    ->selectRaw($sql, ['latitude' => $latitude,'longitude'=> $longitude,'radius'=> $radius])
    ->whereRaw('MBRContains ( LineString (
        Point (
            :longitude + :radius / (111.320 * COS(RADIANS(:latitude))),
            :latitude + :radius / 111.133
        ),
        Point (
            :longitude - :radius / (111.320 * COS(RADIANS(:latitude))),
            :latitude - :radius / 111.133
        )), `coordinates_private`
    )', ['latitude' => $latitude,'longitude'=> $longitude,'radius'=> $radius])
    ->having('distance < :radius', ['radius'=> $radius])
    ->orderBy('distance')
    ->get();

Ошибка

Illuminate\Database\QueryException: SQLSTATE[HY093]:
Invalid parameter number: mixed named and positional parameters (SQL: select `firstname`,`lastname`,`email`,
    ST_X(`coordinates_public`) AS latitude,
    ST_Y(`coordinates_public`) AS longitude,
    (6371 * ACOS(COS(RADIANS(:latitude)) * COS(RADIANS(ST_Y(coordinates_private))) * COS(RADIANS(ST_X(coordinates_private)) - RADIANS(:longitude)) + SIN(RADIANS(:latitude)) * SIN(RADIANS(ST_Y(coordinates_private))))) AS distance from `users` where MBRContains (
    LineString
        (
        Point (
            :longitude + :radius / (111.320 * COS(RADIANS(:latitude))),
            :latitude + :radius / 111.133
        ),
        Point (
            :longitude - :radius / (111.320 * COS(RADIANS(:latitude))),
            :latitude - :radius / 111.133
        )
     ),
    `coordinates_private`) having `distance < :radius` = 4.8312518210935 order by `distance` asc)

Ответы [ 3 ]

1 голос
/ 10 января 2020

В избранном у вас нет :radius, но попробуйте связать его. должно быть

    ->selectRaw($sql, ['latitude' => $latitude,'longitude'=> $longitude])

1 голос
/ 10 января 2020

Из руководства PHP:

Вы должны включить уникальный маркер параметра для каждого значения, которое вы будете sh передавать в инструкцию при вызове PDOStatement :: execute (). Нельзя использовать именованный маркер параметра с одним и тем же именем более одного раза в подготовленном операторе, если только не включен режим эмуляции.

Таким образом, вы не можете использовать маркер именованного параметра с тем же именем.

Существует два решения:

  1. Используйте другой именованный ключ привязки для того же значения:
$sql = "(6371 * ACOS(COS(RADIANS(:lat)) * COS(RADIANS(ST_Y(coordinates_private))) * COS(RADIANS(ST_X(coordinates_private)) - RADIANS(:long)) + SIN(RADIANS(lat2)) * SIN(RADIANS(ST_Y(coordinates_private))))) AS distance";
...
->selectRaw($sql, ["lat" => $latitude, "long" => $longitude, "lat2" => $latitude])

Используйте ? вместо именованного связывания и связывание массива :
$sql = '(6371 * ACOS(COS(RADIANS(?)) * COS(RADIANS(ST_Y(coordinates_private))) * COS(RADIANS(ST_X(coordinates_private)) - RADIANS(?)) + SIN(RADIANS(?)) * SIN(RADIANS(ST_Y(coordinates_private))))) AS distance';
...
->selectRaw($sql, [$latitude, $longitude, $latitude])
1 голос
/ 09 января 2020

Я не уверен, что это проблема, но насколько я знаю, вы не можете использовать одно и то же имя параметра несколько раз, поэтому, например, для этой части запроса:

:longitude + :radius / (111.320 * COS(RADIANS(:latitude))),

вам следует используйте:

:longitude + :radius / (111.320 * COS(RADIANS(:latitude2))),

и затем передайте 3 параметра:

['latitude' => $latitude,'longitude'=> $longitude, 'latitude2' => $latitude]

Конечно, то же самое вы должны попробовать для других частей запроса. Имейте в виду, я не уверен на 100% в этом, потому что я редко использую именованные параметры.

...