如何对 PDO 中的不同表使用相同的准备好的语句?
Posted
技术标签:
【中文标题】如何对 PDO 中的不同表使用相同的准备好的语句?【英文标题】:How can I use the same prepared statement for different tables in PDO? 【发布时间】:2011-11-11 22:41:09 【问题描述】:我经常需要提交一些非常相似的 SQL 查询,例如删除我知道 ID 的表中的一行。这是我的一段代码,prepared statement:
$stmt = $conn->prepare("DELETE FROM `".MY_FIRST_TABLE."` WHERE `id` = :id LIMIT 1");
$stmt->bindValue(':id', $id1, PDO::PARAM_INT);
$stmt->execute();
$stmt = $conn->prepare("DELETE FROM `".MY_SECOND_TABLE."` WHERE `id` = :id LIMIT 1");
$stmt->bindValue(':id', $id2, PDO::PARAM_INT);
$stmt->execute();
我想做这样的事情:
$stmt = $conn->prepare("DELETE FROM `:table` WHERE `id` = :id LIMIT 1");
$stmt->bindValue(':id', $id1, PDO::PARAM_INT);
$stmt->bindValue(':table', MY_FIRST_TABLE);
$stmt->execute();
$stmt->bindValue(':id', $id2, PDO::PARAM_INT);
$stmt->bindValue(':table', MY_SECOND_TABLE);
$stmt->execute();
如果我尝试这个,什么都不会发生。于是我用下面的sn-p来分析错误:
print_r($conn->errorInfo());
var_dump($stmt);
$stmt->debugDumpParams();
我明白了:
Array
(
[0] => 00000
[1] =>
[2] =>
)
object(PDOStatement)#4 (1)
["queryString"]=>
string(45) "DELETE FROM `:table` WHERE `id` = :id LIMIT 1"
SQL: [45] DELETE FROM `:table` WHERE `id` = :id LIMIT 1
Params: 2
Key: Name: [3] :id
paramno=-1
name=[3] ":id"
is_param=1
param_type=1
Key: Name: [6] :table
paramno=-1
name=[6] ":table"
is_param=1
param_type=2
这样的事情可能吗?
(我目前仅出于安全原因使用准备好的语句,而不是出于性能原因。)
准备好的陈述和 IN-Clause
我刚刚读到我不能对表名或列名使用准备好的语句 (source)。所以我想我必须寻找另一个解决方案。
【问题讨论】:
如果你尝试运行它会发生什么? 没什么。我添加了一些行来显示给你尽可能多的关于这个“bug”的信息。我认为故意不可能替换表名,因为准备好的语句似乎存储在数据库中以进行优化......据我所知。我想同时为每张桌子执行此操作可能很困难。所以我希望我能找到一个替代准备好的陈述,或者告诉我我对它们的假设是错误的。 【参考方案1】:我认为(我对此不是 100% 确定)您正在尝试查询一个名为
的表`'TableName'`
或者
`"TableName"`
取决于 PDO 如何尝试引用您的参数。我一直在研究如何不在 PDO 中引用字符串(我遇到了同样的问题),但我很久以前就放弃了并编写了自己的实现。
也许您可以预处理查询并用表名替换参数,但要小心替换表参数名时可能发生的陷阱 (That's what I'm talking about)。
【讨论】:
感谢您提供此信息。我查看了 mysql 服务器收到的查询:SELECT user_password FROM 'chess_users' WHERE 1 = '1'
。这似乎是我不能用准备好的语句来做的原因。另一个有趣的观察:这个查询是由SELECT user_password FROM :table WHERE :uid = :uid
创建的。为什么 :uid 被 1 替换一次,被 '1' 替换一次?
这个我不太清楚,你绑定uid参数的时候用的是什么类型的引号?
我不确定您所说的“报价类型”是什么意思。我使用过这个绑定语句(一次):$stmt->bindValue(':uid', USER_ID, PDO::PARAM_INT);
和 USER_ID 是 int
在 PDO 语句之前和之后。我已经通过var_dump
进行了检查。
我猜 PDO 只引用您想要的类型的参数的第一次出现,第二次使用默认引用(即PDO::PARAM_STR
)。我现在正在运行一些测试,看看我是否写了废话。【参考方案2】:
我可以建议一种不同的方法吗? :
# I'm hard-coding the values so just handle that first and set $id1 and $id2
$parameterArray = array('MY_FIRST_TABLE' => $id1, 'MY_SECOND_TABLE' => $id2);
$sql = '';
foreach($parameterArray as $tableNameKey => $idValue)
# build sql
$sql = "DELETE FROM `". $tableNameKey ."` WHERE `id`=". $idValue ." LIMIT 1";
# prepare and execute
$stmt = $conn->prepare($sql);
$stmt->execute();
# processing code after execution goes here
// ...
// ...
// ...
在这里,您只需使用要构建 DELETE
sql 语句的表和 ID 数组进行循环。您可以尝试一下吗?
【讨论】:
以上是关于如何对 PDO 中的不同表使用相同的准备好的语句?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用准备好的 PDO 语句设置 ORDER BY 参数?