Расширенные заполнители для 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 пары разделены , запятые. Тогда как :& является столбцом =: список столбцов, к которому присоединяются ANDs. Для паритета я добавил :|, У:& есть и другие варианты использования команд 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

Другие вопросы по тегам