Не знаю как вас, но меня всегда раздражало в SQL синтаксическое различие UPDATE и INSERT запросов. Особенно в PHP, где запрос sql пишется почти всегда динамически. В вэб-программировании, довольно часто возникает ситуация, когда один и тот же скрипт должен вставить новую запись (если запись не существует) или обновить существующую. Самый очевидный пример — обработка форм. Например, есть форма из четырех полей, которые надо внести в БД. Причем либо вставка, либо обновление по первичному ключу. Код при этом может выглядеть примерно так:
Даже набирая этот тестовый пример я не мог избавится от ощущения что я делаю два раза одно и тоже :) А в реальных задачах, количество полей может быть и пару десятков (а если работаешь над проектом индийских программистов, то речь уже о сотнях :)) И дело даже не в скоплении множества кавычек двух типов. Они тоже порядком надоедают — их нельзя спутать: для полей одни, для значений другие. Пропуск хоть одной — приведет к ошибке (а сообщения об ошибках в PHP мягко говоря, далеки от совершенства).
Но бог с ними с кавычками. Самое плохое, что для одинакового по сути запроса (существенная разница только в наличии WHERE во втором запросе) нужно писать два разных кода, а синтаксис отличается именно так, что даже копи/пэст не поможет :)
Столкнувшись в очередной раз с этим неудобством SQL, я решил убить двух зайцев: избавится от необходимости кучи кавычек и унифицировать запросы update и insert, чтобы не писать две версии кода. Соответствующая функция на PHP оказалась крайне простой, на ее написание ушло около 10 минут и примерно 15 минут тестирования и отладки. Опробовав ее использование в тот же день, я заметил что скорость написания скриптов обработки данных формы — увеличилась примерно в 2 раза. Сейчас жалею только о том, что не сделал ее еще пару лет назад. Надеюсь, она кому-то пригодится так же как и мне. А может кто-то укажет более лаконичный способ.
Функция крайне проста, она принимает текстовое выражение следующего формата:
Далее, парочка explode и циклов — разбирает строку на два массива: имена полей и значения. Еще передаются параметры определяющие выходной запрос (insert или update), имя таблицы и необязательный параметр $whr — для выражения WHERE (необязательный, в смысле для insert-запроса его не надо передавать, а для update — лучше не забывать никогда! :)) После чего, генерируется строка запроса, со вставкой кавычек. Правда, вставку кавычек для значений в функцию перенести не удалось — ведь они нужны не для всех типов данных. Собственно сама функция:
В ней есть некоторая избыточность: после окончания цикла, собирающего запрос — один раз выполняется копия из тела цикла. Это для исключения последней запятой, которая не нужна после последнего поля. Это можно было решить по-другому: использованием while-цикла. Но у меня врожденная привычка — всегда использовать for для цикла, число итераций которого заранее известно :) Также, функция не учитывает ситуаций попадания символов разделения (: и |) в тексте значений. Если кому-то она реально будет нужна, поработаю над второй версией с экранированием этих символов
INSERT INTO `mytab` (`f1`,`f2`,`f3`,`f4`) VALUES ('$v1','$v2','$v3','$v4')
UPDATE `mytab` SET `f1`='$v1',`f2`='$v2',`f3`='$v3',`f4`='$v4' WHERE `id`=$rID
Даже набирая этот тестовый пример я не мог избавится от ощущения что я делаю два раза одно и тоже :) А в реальных задачах, количество полей может быть и пару десятков (а если работаешь над проектом индийских программистов, то речь уже о сотнях :)) И дело даже не в скоплении множества кавычек двух типов. Они тоже порядком надоедают — их нельзя спутать: для полей одни, для значений другие. Пропуск хоть одной — приведет к ошибке (а сообщения об ошибках в PHP мягко говоря, далеки от совершенства).
Но бог с ними с кавычками. Самое плохое, что для одинакового по сути запроса (существенная разница только в наличии WHERE во втором запросе) нужно писать два разных кода, а синтаксис отличается именно так, что даже копи/пэст не поможет :)
Столкнувшись в очередной раз с этим неудобством SQL, я решил убить двух зайцев: избавится от необходимости кучи кавычек и унифицировать запросы update и insert, чтобы не писать две версии кода. Соответствующая функция на PHP оказалась крайне простой, на ее написание ушло около 10 минут и примерно 15 минут тестирования и отладки. Опробовав ее использование в тот же день, я заметил что скорость написания скриптов обработки данных формы — увеличилась примерно в 2 раза. Сейчас жалею только о том, что не сделал ее еще пару лет назад. Надеюсь, она кому-то пригодится так же как и мне. А может кто-то укажет более лаконичный способ.
Функция крайне проста, она принимает текстовое выражение следующего формата:
fieldname1:value1|fieldname2:value2| ...
и до бесконечности :)Далее, парочка explode и циклов — разбирает строку на два массива: имена полей и значения. Еще передаются параметры определяющие выходной запрос (insert или update), имя таблицы и необязательный параметр $whr — для выражения WHERE (необязательный, в смысле для insert-запроса его не надо передавать, а для update — лучше не забывать никогда! :)) После чего, генерируется строка запроса, со вставкой кавычек. Правда, вставку кавычек для значений в функцию перенести не удалось — ведь они нужны не для всех типов данных. Собственно сама функция:
function getsql($tq,$tab,$text,$whr="")
{
$mo=explode("|",$text); $sm=sizeof($mo);
for ($i=0; $i<$sm; $i++) {$mr=explode(":",$mo[$i]); $f[]=$mr[0]; $v[]=$mr[1];}
$sr=sizeof($f)-1;
for ($i=0; $i<$sr; $i++)
{
$fi.="`".$f[$i]."`,"; $vi.=$v[$i].",";
$up.="`".$f[$i]."`=".$v[$i].",";
}
$fi.="`".$f[$sr]."`"; $vi.=$v[$sr]; $up.="`".$f[$sr]."`=".$v[$sr];
if ($tq=="ins") $q="INSERT INTO `".$tab."` (".$fi.") VALUES (".$vi.")";
if ($tq=="upd") $q="UPDATE `".$tab."` SET ".$up." WHERE ".$whr;
return $q;
}
В ней есть некоторая избыточность: после окончания цикла, собирающего запрос — один раз выполняется копия из тела цикла. Это для исключения последней запятой, которая не нужна после последнего поля. Это можно было решить по-другому: использованием while-цикла. Но у меня врожденная привычка — всегда использовать for для цикла, число итераций которого заранее известно :) Также, функция не учитывает ситуаций попадания символов разделения (: и |) в тексте значений. Если кому-то она реально будет нужна, поработаю над второй версией с экранированием этих символов