Какие токены можно параметризировать в подготовленных инструкциях PDO? - PullRequest
8 голосов
/ 26 октября 2009

Я играю с подготовленными утверждениями в 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

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

Ответы [ 3 ]

10 голосов
/ 26 октября 2009

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

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

1 голос
/ 27 октября 2009

Вы не можете параметризовать что-либо и в предложении IN.

1 голос
/ 27 октября 2009

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

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

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

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

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

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);
}

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

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

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

...