Pull to refresh

SQL — единый синтаксис для UPDATE и INSERT

Не знаю как вас, но меня всегда раздражало в SQL синтаксическое различие UPDATE и INSERT запросов. Особенно в PHP, где запрос sql пишется почти всегда динамически. В вэб-программировании, довольно часто возникает ситуация, когда один и тот же скрипт должен вставить новую запись (если запись не существует) или обновить существующую. Самый очевидный пример — обработка форм. Например, есть форма из четырех полей, которые надо внести в БД. Причем либо вставка, либо обновление по первичному ключу. Код при этом может выглядеть примерно так:

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 для цикла, число итераций которого заранее известно :) Также, функция не учитывает ситуаций попадания символов разделения (: и |) в тексте значений. Если кому-то она реально будет нужна, поработаю над второй версией с экранированием этих символов
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.