Расширенные заполнители для SQL, например. WHERE id IN (??)

Обновление Bounty. Уже получил очень хороший ответ от Марка. Адаптировано: = в:, ниже. Тем не менее, я все еще ищу аналогичные схемы, кроме 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, очень похожая на ??, расширяется до ?,?,?. Подобные варианты использования и разумные для равномерности.

В любом случае, кто-нибудь еще реализовал такую ​​схему? Разные заполнители? Или что бы вы порекомендовали для простоты? Обновление: Я знаю, что интерфейс Oracle OCI для PHP также может связывать параметры массива, но не использует для этого специальные заполнители. И я ищу сопоставимые синтаксисы заполнителей.

Ответы

Ответ 1

Возможно, вы захотите избежать использования := в качестве заполнителя, поскольку он уже имеет использование в, например MySQL.

См. например этот ответ для использования в реальном мире.

Ответ 2

Мне нравится основная идея вашего предложения, но не нравится "именование" заполнителей. У меня в основном есть два возражения:

  • Ваши заполнители начинаются либо с :, либо с помощью ?. Вы должны выбрать одну форму, поэтому местозаполнитель может быть немедленно распознан. Я бы выбрал ?, потому что он имеет менее вероятные столкновения с SQL и более распространен для обозначения заполнителей.
  • Заполнители трудно понять и трудно запомнить. :& и :| кажутся мне правдоподобными, но отличать ??, :? и : довольно сложно.

Я изменил класс DB, чтобы поддерживать еще несколько заполнителей и быть более интеллектуальным: DB_intelligent.php (часть README о заполнителях не применяется к этому классу. Это только для нормального класса.)

Класс DB имеет два типа заполнителей: многофункциональный ? -заполнитель и ассоциативный заполнитель ?x (x может быть ,, & или |).

? placeholder. Этот заполнитель определяет тип вставки из типа аргумента:

null                => 'NULL'
'string'            => 'string'
array('foo', 'bar') => ('foo','bar')

?x placeholder: каждый элемент массива преобразуется в структуру `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, которая будет плохой.

Ответ 3

Очень аккуратно! Я думаю, что заполнители хороши, пока вы хорошо их документируете и предоставляете множество примеров, когда вы его распространяете. Это нормально, что вы изобрели свои собственные заполнители; кто-то должен был подумать об использовании ?, в конце концов.

Ответ 4

Если вы готовы потратить некоторое время на изучение doctrine, тогда вы сможете сделать потрясающие вещи, например:

$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 (?, 
?, 
?, 
?)

Этот пример был взят из: документации доктрины dql