Laravel 抱怨具有重复命名参数的查询
Laravel complains about query with duplicate named parameters
当我这样做时(laravel):
<?php
\DB::select('SELECT * FROM my_table WHERE id = :id || id = :id', [
'id' => 1,
]);
它说:
SQLSTATE[HY093]: Invalid parameter number (SQL: SELECT * FROM my_table WHERE id = :id || id = :id)
但是当我这样做时(纯 php):
<?php
$dbh = new PDO('mysql:dbname=...', '...', '...');
$stmt = $dbh->prepare('SELECT * FROM my_table WHERE id = :id || id = :id');
$r = $stmt->execute([
'id' => 1,
]);
while ($row = $stmt->fetch()) {
var_dump($row['id']);
}
成功了。我做错了什么?
P.S。显然,我运行遇到问题时的查询更有意义。
UPD 大致真实查询:
SELECT id
FROM objects
WHERE ACOS(
SIN(RADIANS(lat)) * SIN(RADIANS(:lat))
+ COS(RADIANS(lat)) * COS(RADIANS(:lat)) * COS(RADIANS(:lng - lng))
) * 6371 < 10
据我所知,这一切都归结为 mysql
无法处理命名参数。
This parameter can include one or more parameter markers in the SQL statement by embedding question mark (?) characters at the appropriate positions.
You must include a unique parameter marker for each value you wish to pass in to the statement when you call PDOStatement::execute(). You cannot use a named parameter marker of the same name more than once in a prepared statement, unless emulation mode is on.
Laravel 具有仿真模式 disabled by default。可以通过在连接设置中添加 'options' => [PDO::ATTR_EMULATE_PREPARES => TRUE]
来在 config/database.php
中启用它。这样您将获得与纯 php 相同的结果。不过不确定这是个好主意。
我通常使用带有 "constant" 派生的 table 的 CROSS JOIN 来解决这个问题(FROM 子句中的子查询)。然后我可以根据需要多次重复使用这些参数。
SELECT id
FROM objects o
CROSS JOIN (SELECT :lat as lat, :lng as lng) params
WHERE ACOS(
SIN(RADIANS(o.lat)) * SIN(RADIANS(params.lat))
+ COS(RADIANS(o.lat)) * COS(RADIANS(params.lat)) * COS(RADIANS(params.lng - o.lng))
) * 6371 < 10
当我这样做时(laravel):
<?php
\DB::select('SELECT * FROM my_table WHERE id = :id || id = :id', [
'id' => 1,
]);
它说:
SQLSTATE[HY093]: Invalid parameter number (SQL: SELECT * FROM my_table WHERE id = :id || id = :id)
但是当我这样做时(纯 php):
<?php
$dbh = new PDO('mysql:dbname=...', '...', '...');
$stmt = $dbh->prepare('SELECT * FROM my_table WHERE id = :id || id = :id');
$r = $stmt->execute([
'id' => 1,
]);
while ($row = $stmt->fetch()) {
var_dump($row['id']);
}
成功了。我做错了什么?
P.S。显然,我运行遇到问题时的查询更有意义。
UPD 大致真实查询:
SELECT id
FROM objects
WHERE ACOS(
SIN(RADIANS(lat)) * SIN(RADIANS(:lat))
+ COS(RADIANS(lat)) * COS(RADIANS(:lat)) * COS(RADIANS(:lng - lng))
) * 6371 < 10
据我所知,这一切都归结为 mysql
无法处理命名参数。
This parameter can include one or more parameter markers in the SQL statement by embedding question mark (?) characters at the appropriate positions.
You must include a unique parameter marker for each value you wish to pass in to the statement when you call PDOStatement::execute(). You cannot use a named parameter marker of the same name more than once in a prepared statement, unless emulation mode is on.
Laravel 具有仿真模式 disabled by default。可以通过在连接设置中添加 'options' => [PDO::ATTR_EMULATE_PREPARES => TRUE]
来在 config/database.php
中启用它。这样您将获得与纯 php 相同的结果。不过不确定这是个好主意。
我通常使用带有 "constant" 派生的 table 的 CROSS JOIN 来解决这个问题(FROM 子句中的子查询)。然后我可以根据需要多次重复使用这些参数。
SELECT id
FROM objects o
CROSS JOIN (SELECT :lat as lat, :lng as lng) params
WHERE ACOS(
SIN(RADIANS(o.lat)) * SIN(RADIANS(params.lat))
+ COS(RADIANS(o.lat)) * COS(RADIANS(params.lat)) * COS(RADIANS(params.lng - o.lng))
) * 6371 < 10