如何将参数绑定到模型上使用的 Laravel 中的原始数据库查询?

Posted

技术标签:

【中文标题】如何将参数绑定到模型上使用的 Laravel 中的原始数据库查询?【英文标题】:How to bind parameters to a raw DB query in Laravel that's used on a model? 【发布时间】:2014-01-18 20:00:55 【问题描述】:

回复,

我有以下疑问:

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

它不起作用:Invalid parameter number: mixed named and positional parameters

有谁知道技巧或解决方法(我显然可以编写完整的查询,但更喜欢使用流利的构建器)。

【问题讨论】:

愚蠢的问题-但文档在其任何示例中都没有使用" "。你试过单身吗? @JamesBinford 是的,尝试了所有可能的组合,包括%s 您有 2 个:lat 在查询中,但只绑定了 1 个 @davidstrachan 似乎没有任何区别。 模型并不存在。您的意思是“在实例上使用”。模型只是一个空白模板。在 Laravel 世界中,每个人都使用了错误的术语,“模型”的意思是“实例”。 【参考方案1】:

好的,经过一些实验,这是我想出的解决方案:

$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 必须在查询中调用。希望这被记录在案!

【讨论】:

+1 正在寻找这个确切的答案...包括地图半径查询。谢谢! setBindings 似乎不支持 PDO 的命名参数:/ 如果您正在处理一个关系,例如,您应该使用addBinding 而不是setBindings 以避免覆盖关系绑定。 这是setBindings(array $bindings, $type = 'where')的签名。如果您在 WHERE 子句中有绑定,那么这些将被覆盖。您应该指定您的绑定用于查询的 SELECT 部分。 -&gt;setBindings([$lat, $lng, $lat, $radius], 'select') 对我也有用,虽然它不能很好地与 ->where() 一起使用,所以我也必须绑定它【参考方案2】:

老问题,但是如果我们必须重复一个变量,我们必须改变它在绑定数组中的键值。

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

够了。

【讨论】:

拉阿姆。谢谢你,先生。 在哪个版本中可以将绑定作为 DB::raw 的第二个参数? 我在 Laravel 4.2 中使用它 在 4.2 中,您可以使用绑定作为 whereRaw() 中的第二个参数,但不能在 DB::raw() 中使用。在上面的示例中,绑定被传递给 select(),而不是 DB::raw()。 我收到一个错误“strtolower() 期望参数 1 是字符串,给定数组”【参考方案3】:

为什么不呢?

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

【讨论】:

这是一个 2 年的问题。 selectRaw 当时不可用。 select() 接受绑定【参考方案4】:

我最近遇到了同样的问题,答案在错误消息mixed named and positional parameters 中。在您的情况下,:lat:lng 是命名参数,而 $radius 是位置参数。因此,解决您的问题的一种可能方法是使用 havingRaw() 并应用命名参数。

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

【讨论】:

【参考方案5】:
$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();

【讨论】:

【参考方案6】:

我将附近的搜索从 Doctrine v1 移植到 Laravel,check it out here.

只需将 Geographical 特征添加到模型中即可:

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

它通过使用 selectRaw 和这样的绑定来工作:

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

【讨论】:

以上是关于如何将参数绑定到模型上使用的 Laravel 中的原始数据库查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何更改绑定到 Razor 页面上模型的特定文本的字体颜色?

如何将参数传递到链式 Laravel Eloquent 关系中的位置

Laravel Livewire 绑定模型 Carbon 属性

如何在 laravel 5 中模拟模型上的 create 方法?

如何在模型绑定中使用带有 Laravel 的复选框组

Laravel:在自定义 Route::model 绑定中使用模拟实例