Какие токены можно параметризировать в подготовленных инструкциях PDO?
-
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
также нельзя ничего параметризировать.