PDO 参数化查询 - 重用命名占位符?

发布于 2024-08-25 01:50:30 字数 160 浏览 4 评论 0原文

本质上,我有一个必须在 SQL 查询中调用几次的值。因此,是否可以在语句中重用相同的命名占位符,例如 SELECT :Param FROM Table WHERE Column = :Param,然后简单地bindValue(":Param"),并让两个:Params 都有值?

In essence, I have a value that I have to call a couple times in my SQL query. Thus, is it possible to reuse the same named placeholder in the statement e.g.
SELECT :Param FROM Table WHERE Column = :Param, then simply bindValue(":Param"), and have the value be there for both :Params?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

荒岛晴空 2024-09-01 01:50:30

PDO::prepare 声明“您不能使用相同的命名参数标记在准备好的声明中命名两次”,所以我想那是不行的。

PDO::prepare states that "you cannot use a named parameter marker of the same name twice in a prepared statement", so I guess that's a no then.

五里雾 2024-09-01 01:50:30

如果您设置 PDO::ATTR_EMULATE_PREPARES = true,则可以。

例如$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

如果您使用 Laravel,您可以在 config/database.phpoptions 数组中进行设置。例如 PDO::ATTR_EMULATE_PREPARES =>正确

You can if you set PDO::ATTR_EMULATE_PREPARES = true.

E.g. $connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);.

If you're using Laravel you can set this in an options array in config/database.php. e.g. PDO::ATTR_EMULATE_PREPARES => true

掐死时间 2024-09-01 01:50:30

除了重用之外,这里的主要问题是您试图动态更改列名称。

此答案由匿名用户在 http://php.net/manual/en/pdo 上发布.prepare.php

对于那些想知道为什么在占位符周围添加引号是错误的人来说,
以及为什么不能对表名或列名使用占位符:

关于如何准备占位符存在一个常见的误解
语句有效:它们不是简单地替换为 as (转义)
字符串,以及执行的结果 SQL。相反,DBMS 要求
“准备”语句会提出一个完整的查询计划,说明它如何
将执行该查询,包括它将执行哪些表和索引
use,无论你如何填写,都是一样的
占位符。

“SELECT name FROM my_table WHERE id = :value”的计划将是
无论你替换“:value”,但看起来相似
“SELECT name FROM :table WHERE id = :value”无法计划,因为
DBMS 不知道您实际上要从哪个表中选择。

即使使用“模拟准备”,PDO 也不能让您使用
任何地方的占位符,因为它必须弄清楚你要做什么
意思是:“Select :foo From some_table”是否意味着“:foo”将成为
列引用,还是文字字符串?

当您的查询使用动态列引用时,您应该将已知存在于表中的列显式列入白名单,例如使用 switch 语句并在 default: 子句中抛出异常。

Apart from reuse, the main issue here is that you are trying to dynamically change col names.

This answer posted by an anonymous user on http://php.net/manual/en/pdo.prepare.php :

To those wondering why adding quotes to around a placeholder is wrong,
and why you can't use placeholders for table or column names:

There is a common misconception about how the placeholders in prepared
statements work: they are not simply substituted in as (escaped)
strings, and the resulting SQL executed. Instead, a DBMS asked to
"prepare" a statement comes up with a complete query plan for how it
would execute that query, including which tables and indexes it would
use, which will be the same regardless of how you fill in the
placeholders.

The plan for "SELECT name FROM my_table WHERE id = :value" will be the
same whatever you substitute for ":value", but the seemingly similar
"SELECT name FROM :table WHERE id = :value" cannot be planned, because
the DBMS has no idea what table you're actually going to select from.

Even when using "emulated prepares", PDO cannot let you use
placeholders anywhere, because it would have to work out what you
meant: does "Select :foo From some_table" mean ":foo" is going to be a
column reference, or a literal string?

When your query is using a dynamic column reference, you should be explicitly white-listing the columns you know to exist on the table, e.g. using a switch statement with an exception thrown in the default: clause.

不念旧人 2024-09-01 01:50:30

许多像您这样的查询可以重写为仅使用一个占位符。

SELECT :Param FROM Table WHERE Column = :Param

会是一样的

SELECT Column FROM Table WHERE Column = :Param

但有时没那么简单。例如:

SELECT *
FROM my_table
WHERE first_name LIKE :Param
   OR last_name  LIKE :Param
   OR biography  LIKE :Param

在这种情况下,您可以重用将其存储在交叉连接派生表中的参数值(FROM 子句中的子查询):

SELECT t.*
FROM my_table t
CROSS JOIN (SELECT :Param as Param) AS x
WHERE first_name LIKE x.Param
   OR last_name  LIKE x.Param
   OR biography  LIKE x.Param

Many queries like yours can be rewritten to use only one placeholder.

SELECT :Param FROM Table WHERE Column = :Param

would be the same as

SELECT Column FROM Table WHERE Column = :Param

But sometimes it's not that simple. For example:

SELECT *
FROM my_table
WHERE first_name LIKE :Param
   OR last_name  LIKE :Param
   OR biography  LIKE :Param

In such case you could reuse the parameter value storing it in a cross joined derived table (subquery in FROM clause):

SELECT t.*
FROM my_table t
CROSS JOIN (SELECT :Param as Param) AS x
WHERE first_name LIKE x.Param
   OR last_name  LIKE x.Param
   OR biography  LIKE x.Param
錯遇了你 2024-09-01 01:50:30

正如其他人指出的那样,有很多解决方法:

  1. 使用不同的占位符,同时为它们提供相同的值。
  2. 重写您的查询,以便仅需要唯一的占位符。
  3. ATTR_EMULATE_PREPARES 设置为 true

如果上述方法不可能也不可取,还有另一种优雅的方法可以解决此问题,即在 SQL 中使用变量:

DECLARE @MyVariable AS INT = :value;
SELECT column_x FROM table WHERE column_y = @MyVariable OR column_z = @MyVariable;

然后通过分配 <代码>值。

As others pointed out, there are quite some workarounds:

  1. Use different placeholders whilst providing them the same value.
  2. Rewrite your query so that only unique placeholders are required.
  3. Set ATTR_EMULATE_PREPARES to true

If the above is not possible nor desirable, there is another elegant way to solve this, by using variables in SQL:

DECLARE @MyVariable AS INT = :value;
SELECT column_x FROM table WHERE column_y = @MyVariable OR column_z = @MyVariable;

Then prepare this statement by just assigning value.

感情洁癖 2024-09-01 01:50:30

有一个解决方法:

  function search($criteria) {

     $sql = "SELECT * FROM my_table
        WHERE column_1 like CONCAT('%', :criteria1, '%') 
           OR column_2 like CONCAT('%', :criteria2, '%') 
           OR column_3 like CONCAT('%', :criteria3, '%')  
     ";

     $stmt =  $this->db->prepare($sql);
     $stmt->bindParam(':criteria1', $criteria);
     $stmt->bindParam(':criteria2', $criteria);
     $stmt->bindParam(':criteria3', $criteria);
     $stmt->execute();
     return($stmt->fetchAll(PDO::FETCH_ASSOC));
  }

总之,使用具有相同条件的不同占位符。

There's a workaround:

  function search($criteria) {

     $sql = "SELECT * FROM my_table
        WHERE column_1 like CONCAT('%', :criteria1, '%') 
           OR column_2 like CONCAT('%', :criteria2, '%') 
           OR column_3 like CONCAT('%', :criteria3, '%')  
     ";

     $stmt =  $this->db->prepare($sql);
     $stmt->bindParam(':criteria1', $criteria);
     $stmt->bindParam(':criteria2', $criteria);
     $stmt->bindParam(':criteria3', $criteria);
     $stmt->execute();
     return($stmt->fetchAll(PDO::FETCH_ASSOC));
  }

In summary, use different placeholders with the same criteria.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文