Как я могу использовать один и тот же подготовленный оператор для разных таблиц в PDO?

#php #pdo #prepared-statement

#php #pdo #подготовленный оператор

Вопрос:

У меня довольно часто возникают очень похожие SQL-запросы, которые я должен отправлять, например, удаление одной строки в таблице, идентификатор которой мне известен. Вот мой фрагмент кода с подготовленным оператором:

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

Если я попробую это, ничего не произойдет. Итак, я использовал следующий фрагмент для анализа ошибки:

 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

Я только что прочитал, что я не могу использовать подготовленные операторы для имен таблиц или столбцов (исходный код). Так что, я думаю, мне нужно искать другое решение.

Комментарии:

1. Что произойдет, если вы попытаетесь запустить это?

2. Ничего. Я добавил несколько строк, чтобы показать, что они дают вам как можно больше информации, которая у меня есть об этой «ошибке». Я думаю, что намеренно невозможно заменить имена таблиц, поскольку подготовленные операторы, похоже, сохраняются в базе данных для оптимизации… насколько я понял. Я предполагаю, что может быть сложно сделать это для каждой таблицы одновременно. Итак, я надеюсь, что получу альтернативу для подготовленных операторов или мне скажут, что я ошибаюсь в своих предположениях о них.

Ответ №1:

Я думаю (я не уверен в этом на 100%), что вы пытаетесь запросить таблицу с именем

 `'TableName'`
  

Или

 `"TableName"`
  

в зависимости от того, как PDO пытается указать ваши параметры. Я искал, как не заключать строки в кавычки в PDO (у меня была ваша та же проблема), но я давно отказался от этого и написал свою собственную реализацию.

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

Комментарии:

1. Спасибо за эту информацию. Я взглянул на запрос, который был получен MySQL-сервером: SELECT user_password FROM 'chess_users' WHERE 1 = '1' . Похоже, это причина, по которой я не могу сделать это с помощью подготовленных операторов. Еще одно интересное наблюдение: этот запрос был создан SELECT user_password FROM :table WHERE :uid = :uid . Почему:uid заменяется один раз на 1 и один раз на ‘1’?

2. Я не уверен в этом, какой тип цитаты вы использовали, когда привязывали параметр uid?

3. Я не уверен, что вы имеете в виду под «типом цитаты». Я использовал этот оператор bind (один раз): $stmt->bindValue(':uid', USER_ID, PDO::PARAM_INT); а USER_ID находится int до и после операторов PDO. Я проверил это с помощью var_dump .

4. Я предполагаю, что 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.. Не могли бы вы попробовать это?