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

StackOverflow https://stackoverflow.com/questions/1622521

  •  06-07-2019
  •  | 
  •  

Вопрос

Я играю с подготовленными утверждениями в PHP / PDO. Базовые запросы работают нормально, передавая значение в предложение WHERE:

$stmt = $db->prepare( 'SELECT title FROM episode WHERE id=:id' );
$stmt->bindParam( ':id', $id, PDO::PARAM_INT );
$id = 5;
$stmt->execute();

Однако у меня есть ситуация, когда мне нужно передать переменные для имен полей. Этот запрос (с соответствующей привязкой) работает нормально:

SELECT :field FROM episode WHERE id=:id

Этот выдает ошибку:

SELECT title FROM :field WHERE id=:id

Этот не выдает ошибку, но не возвращает строк:

SELECT title FROM episode WHERE :field=:id

Итак, что должно работать в подготовленных утверждениях? Могу ли я «параметризировать» имена полей, имен таблиц и т. Д.?

Это было полезно?

Решение

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

См. этот вопрос и впоследствии этот комментарий в руководстве по PHP .

Другие советы

@ Джош Лейцель

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

Рассмотрим следующий пример:

Мой проект имеет логическую структуру:

Иерархия компании выражается в единицах сущностей. Каждый объект может рассматриваться в общем случае как член иерархии или как член определенного уровня иерархии. Сама иерархия определяется в таблице как одна ветвь дерева следующим образом:

entity_structure (
   id
   name
   parent_entity_structure_id
);

и сами сущности выражаются как:

entities (
   id
   name
   entity_structure_id
   parent_id
);

Для простоты использования я построил алгоритм, который создает плоский вид дерева. Следующий конкретный пример иллюстрирует, что я имею в виду:

SELECT * FROM entity_structure;

id      | name               | entity_structure_parent_id
-----------------------------------------------------------
1       | Company            | null    (special one that always exists)
2       | Division           | 1
3       | Area               | 2
4       | Store              | 3

Это приведет к созданию следующего плоского представления:

entity_tree (
   entity_id
   division_id
   area_id
   store_id
)

Объекты, находящиеся на уровне деления, будут иметь Division_id, area_id и store_id как NULL, Area_ID Area и Store_id как NULL и т. д.

Приятно то, что это позволяет вам запрашивать все дочерние элементы подразделения, используя оператор, подобный следующему:

SELECT * FROM entity_tree WHERE division_id = :division_id;

Однако это предполагает, что я знаю уровень структуры объекта, который запрашиваю. Было бы неплохо сделать:

SELECT * FROM entity_tree WHERE :structure = :entity_id;

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

$children = array();
$stmt = $pdo->prepare('SELECT entity_id FROM entity_tree WHERE :structure = :entityId');
foreach ($entities AS $entity) {
   $stmt->execute(array(
      ':structure' = $entity->getEntityStructureId(),
      ':entityId'  = $entity->getId()
   ));

   $children[$entity->getId()] = $stmt->fetchAll(PDO::FETCH_COLUMN);
}

в результате получается более чистый код и только одно подготовленное утверждение.

Весь пример не использует никакого пользовательского ввода.

Просто кое-что рассмотреть.

В параметре IN также нельзя ничего параметризировать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top