Расширенные заполнители для SQL, например, WHERE ID IN (??)
Bounty update: уже получил очень хороший ответ от Марка. Адаптировано:= в:, ниже. Тем не менее, я все еще ищу аналогичные схемы, кроме DBIx. Мне просто интересно быть совместимым с чем-либо.
Мне нужно посоветовать, какой синтаксис я выбрал для "расширенных" заполнителей в параметризованных операторах SQL. Поскольку создание некоторых конструкций (предложений IN) вызывало у меня проблемы, я решил использовать несколько синтаксических ярлыков, которые автоматически расширяются до обычных? заполнители.
Они мне нравятся. Но я хочу упаковать его для распространения и спрашиваю себя, легко ли это понять.
В основном мои новые заполнители ??
а также :?
(перечисленные параметры) и :&
а также :,
а также :|
а также ::
(для именованных заполнителей) со следующими вариантами использования:
-> db(" SELECT * FROM all WHERE id IN (??) ", [$a, $b, $c, $d, $e])
??
расширяется в ?,?,?,?,?,...
в зависимости от количества $args для моей функции db(). Это довольно ясно, и его синтаксис уже стандартизирован. Perls DBIx::Simple тоже его использует. Так что я уверен, что это приемлемая идея.
-> db(" SELECT :? FROM any WHERE id>0 ", ["title", "frog", "id"]);
// Note: not actually parameterized attr, needs cleanup regex
Признай это. Мне просто понравился смайлик. В основном это :?
заполнитель расширяет ассоциативный $args на простые имена столбцов. Фактически он отбрасывает любые значения $args. На самом деле это полезно для INSERT в сочетании с??, а иногда и для IN. Но здесь я уже задаюсь вопросом, является ли этот новый синтаксис разумным, или не просто неправильным, потому что он смешивает: а? персонажи. Но как-то кажется, что он хорошо соответствует синтаксической схеме.
-> db(" UPDATE some SET :, WHERE :& AND (:|) ", $row, $keys, $or);
Здесь мнемоника :,
расширяется в список name=:name
пары разделены ,
запятые. Тогда как :&
является столбцом =: список столбцов, к которому присоединяются AND
s. Для паритета я добавил :|
, У:& есть и другие варианты использования команд UPDATE.
Но мой вопрос не о полезности, а о том, что:, и:& кажутся запоминающимися?
-> db(" SELECT * FROM all WHERE name IN (::) ", $assoc);
После некоторого, хотя я также добавил ::
интерполировать :named,:value,:list
очень похоже ??
расширяется до ?,?,?
, Подобные варианты использования и целесообразно иметь для единообразия.
В любом случае, кто-нибудь еще реализовал такую схему? Разные заполнители? Или что бы вы порекомендовали для простоты? Обновление: я знаю, что интерфейс PHP Oracle OCI также может связывать параметры массива, но не использует для этого специальные заполнители. И я ищу сопоставимые синтаксисы заполнителей.
4 ответа
Вы можете избежать использования :=
в качестве заполнителя, потому что он уже используется, например, в MySQL.
Посмотрите, например, этот ответ для использования в реальном мире.
Мне нравится основная идея вашего предложения, но мне не нравится "именование" местозаполнителей. У меня есть два возражения:
- Ваши заполнители начинаются либо с
:
или с?
, Вы должны выбрать одну форму, чтобы заполнитель мог быть немедленно распознан. я бы выбрал?
потому что он имеет меньше возможных коллизий с SQL и чаще используется для обозначения заполнителей. - Заполнители трудно понять и трудно запомнить.
:&
а также:|
кажется правдоподобным для меня, но отличительные??
,:?
а также:
это довольно сложно.
Я изменил свой класс DB, чтобы поддерживать еще несколько заполнителей и быть более интеллектуальным: DB_intelligent.php (часть README о заполнителях не применяется к этому классу. Это только для нормального класса.)
Класс DB имеет два вида заполнителей: многофункциональный ?
заполнитель и заполнитель ассоциативного массива ?x
(x
может быть ,
, &
или же |
).
?
заполнитель: этот заполнитель определяет тип вставки из типа аргумента:
null => 'NULL'
'string' => 'string'
array('foo', 'bar') => ('foo','bar')
?x
заполнитель: каждый элемент в массиве преобразуется в `field`='value'
структура и взята с разделителем. Разделитель указывается x
составная часть: ,
разделять запятыми, &
от AND
а также |
от OR
,
Пример кода:
DB::x(
'UPDATE table SET ?, WHERE value IN ? AND ?&',
array('foo' => 'bar'),
array('foo', 'bar'),
array('hallo' => 'world', 'hi' => 'back')
);
// Results in this query:
// UPDATE table SET `foo`='bar' WHERE value IN ('foo','bar') AND `hallo`='world' AND `hi`='back'
Некоторые мысли, которые у меня возникли при разработке этой версии класса DB:
Очевидная мысль, которая может возникнуть: почему бы не использовать ?
для всех типов данных, даже ассоциативных массивов. Только добавить ?&
а также ?|
дополнительно. С помощью ?
на ассоциативном массиве будет так же, как с помощью ?,
в текущем дизайне. Причиной, по которой я этого не сделал, является безопасность. Вы часто хотите вставить данные из <select multiple>
в запрос (IN ?
). Но как HTML позволяет массива (form[array]
) форма также контролирует ассоциативный массив с тем же именем. Таким образом, мой Query Compositor распознал бы его как список значений field =>. Хотя это, вероятно, не повредит безопасности, это приведет к ошибке SQL, что плохо.
Очень аккуратный! Я думаю, что заполнители в порядке, если вы хорошо их документируете и приводите множество примеров при их распространении. Это нормально, что вы изобрели свои собственные заполнители; кто-то должен был подумать об использовании ?
, в конце концов.
Если вы хотите потратить некоторое время на изучение доктрины, вы можете сделать удивительные вещи, такие как:
$q = Doctrine_Query::create()
->select('u.id')
->from('User u')
->whereIn('u.id', array(1, 3, 4, 5));
echo $q->getSqlQuery();
что бы получить такой запрос:
SELECT
u.id AS u__id
FROM user u
WHERE u.id IN (?,
?,
?,
?)
Этот пример взят из документации: doctrine dql