insert into MyTable(Fields1, Field2, Field3)
values ('Sweets', 934, to_date('21/05/2001', 'dd/mm/yyyy'))
неправда ли она более проста в использовании ?
Здесь представлены функции SqlInsert и SqlUpdate. Вы наверное заметили, что я передаю TDateTime приведённый как Variant. Причина кроется в том, что VType в array of const не имеете TDateTime типа и даты просто представлены как vtExtended.
Функция SqlInsert имеет 2 переопределённых вызова, которые позволяют Вам включить или выполнить массив имён колонок.
Посмотрим, как выглядят эти функции:
interfaceconst// Возврат и перевод каретки
CrLf = #13#10;
// Прототипы функцийfunction SqlInsert(Values : arrayofconst;
TableName : string; ColNames : arrayofstring) : string; overload;
function SqlInsert(Values : arrayofconst;
TableName : string) : string; overload;
function SqlUpdate(Values : arrayofconst; TableName : string;
ColNames : arrayofstring; WhereClause : string) : string;
implementation// Помещаем TDateTime в Values (array of const)// Представлен как Variantfunction SqlInsert(Values : arrayofconst;
TableName : string; ColNames : arrayofstring) : string;
var
RetVar : string;
i : integer;
begin
RetVar := 'insert into ' + TableName + CrLf + '(' + ColNames[0];
for i := 1 to High(ColNames) do
RetVar := RetVar + ',' + ColNames[i];
RetVar := RetVar + ')' + CrLf;
RetVar := RetVar + 'values (';
for i := 0 to High(Values) dobegincase Values[i].VType of
vtInteger, vtInt64 :
RetVar := RetVar + IntToStr(Values[i].VInteger);
vtChar :
RetVar := RetVar + QuotedStr(Values[i].VChar);
vtString :
RetVar := RetVar + QuotedStr(Values[i].VString^);
vtPChar :
RetVar := RetVar + QuotedStr(Values[i].VPChar);
vtExtended :
RetVar := RetVar + FloatToStr(Values[i].VExtended^);
vtAnsiString :
RetVar := RetVar + QuotedStr(string(Values[i].VAnsiString));
// TDateTime - иначе получаем как vtExtended
vtVariant :
RetVar := RetVar + 'to_date(' + QuotedStr(FormatdateTime('dd/mm/yyyy',
TDateTime(Values[i].VVariant^))) + ',' + QuotedStr('dd/mm/yyyy') + ')';
else
RetVar := RetVar + '??????';
end;
RetVar := RetVar + ',';
end;
Delete(RetVar,length(RetVar),1);
RetVar := RetVar + ')';
if High(Values) < High(ColNames) then
ShowMessage('SQL Insert - Not enough values.');
if High(Values) > High(ColNames) then
ShowMessage('SQL Insert - Too many values.');
Result := RetVar;
end;
function SqlInsert(Values : arrayofconst;
TableName : string) : string; overload;
var
RetVar : string;
i : integer;
begin
RetVar := 'insert into ' + TableName + CrLf;
RetVar := RetVar + 'values (';
for i := 0 to High(Values) dobegincase Values[i].VType of
vtInteger, vtInt64 :
RetVar := RetVar + IntToStr(Values[i].VInteger);
vtChar :
RetVar := RetVar + QuotedStr(Values[i].VChar);
vtString :
RetVar := RetVar + QuotedStr(Values[i].VString^);
vtPChar :
RetVar := RetVar + QuotedStr(Values[i].VPChar);
vtExtended :
RetVar := RetVar + FloatToStr(Values[i].VExtended^);
vtAnsiString :
RetVar := RetVar + QuotedStr(string(Values[i].VAnsiString));
// TDateTime - иначе получаем как vtExtended
vtVariant :
RetVar := RetVar + 'to_date(' + QuotedStr(FormatdateTime('dd/mm/yyyy',
TDateTime(Values[i].VVariant^))) + ',' + QuotedStr('dd/mm/yyyy') + ')';
else
RetVar := RetVar + '??????';
end;
RetVar := RetVar + ',';
end;
Delete(RetVar,length(RetVar),1);
RetVar := RetVar + ')';
Result := RetVar;
end;
function SqlUpdate(Values : arrayofconst; TableName : string;
ColNames : arrayofstring; WhereClause : string) : string;
var
RetVar, Parm : string;
i : integer;
begin
RetVar := 'update ' + TableName + ' set' + CrLf;
for i := 0 to Min(High(Values),High(ColNames)) dobegincase Values[i].VType of
vtInteger, vtInt64 :
Parm := IntToStr(Values[i].VInteger);
vtChar :
Parm := QuotedStr(Values[i].VChar);
vtString :
Parm := QuotedStr(Values[i].VString^);
vtPChar :
Parm := QuotedStr(Values[i].VPChar);
vtExtended :
Parm := FloatToStr(Values[i].VExtended^);
vtAnsiString :
Parm := QuotedStr(string(Values[i].VAnsiString));
// TDateTime - иначе получаем как vtExtended
vtVariant : Parm := 'to_date(' + QuotedStr(FormatdateTime('dd/mm/yyyy',
TDateTime(Values[i].VVariant^))) + ',' + QuotedStr('dd/mm/yyyy') + ')';
else
Parm := '??????';
end;
RetVar := RetVar + ColNames[i] + '=' + Parm + ',';
end;
Delete(RetVar,length(RetVar),1);
RetVar := RetVar + CrLf + 'where ' + WhereClause;
if High(Values) < High(ColNames) then
ShowMessage('SQL Update - Not enough values.');
if High(Values) > High(ColNames) then
ShowMessage('SQL Update - Too many values.');
Result := RetVar;
end;
Перевод на русский язык:
Это пример программирования Delphi, демонстрирующий, как генерировать динамические запросы SQL для вставки и обновления данных с помощью функций SqlInsert и SqlUpdate.
Основная идея этих функций - упростить процесс создания динамических запросов SQL. Функции принимают массив значений, имя таблицы и необязательные имена столбцов для запроса обновления в параметрах.
Функция SqlInsert генерирует запрос INSERT INTO, перебирая массив значений, форматируя каждое значение по его типу (целочисленное, строка, дата/время) и конкатенируя их в единый SQL-строковый запрос. Если количество значений не соответствует количеству имен столбцов, предоставленных пользователем, функция отображает сообщение об ошибке.
Функция SqlUpdate генерирует запрос UPDATE, перебирая массив значений и массив имен столбцов, форматируя каждое значение по его типу и конкатенируя их в единый SQL-строковый запрос. В запросе также включается клаузула WHERE. Если количество значений не соответствует количеству имен столбцов, предоставленных пользователем, функция отображает сообщение об ошибке.
Вот некоторые улучшения, которые можно сделать:
Обработка ошибок: текущая реализация только проверяет соответствие количества значений количеству имен столбцов. Лучше было бы проверять другие потенциальные ошибки, такие как неправильные имена таблицы или столбца, неправильные типы данных и т.д.
Организация кода: код довольно длинный и может быть разделен на более маленькие процедуры или функции для улучшения читаемости и поддерживаемости.
Безопасность типов: код использует типы Variant (например, TDateTime, Variant), которые могут привести к ошибкам выполнения времени, если не будут правильно обработаны. Лучше было бы использовать сильные типы переменных и данных structures, где это возможно.
Защита от SQL-инъекций: генерируемые SQL-запросы уязвимы для атак SQL-инъекциями. Лучше было бы использовать готовые заявки или параметризованные запросы вместо конкатенации пользовательского ввода в строке запроса.
Вот пример рефакторирования функции SqlInsert с использованием более современного и безопасного подхода:
functionSqlInsert(Values:TArray<TValue>;TableName:string;ColNames:TArray<string>):string;varRetVar:TStringBuilder;beginRetVar:=TStringBuilder.Create;tryRetVar.Append('insert into ').Append(TableName).AppendLine;RetVar.Append('(');forvari:=0toHigh(ColNames)dobeginRetVar.Append(ColNames[i]);ifi<High(ColNames)thenRetVar.Append(', ');end;RetVar.AppendLine(')');RetVar.AppendLine('values (');forvari:=0toHigh(Values)dobegincaseValues[i].VTypeofvtInteger,vtInt64:RetVar.Append(IntToStr(TValue(Values[i]).AsInteger));vtChar:RetVar.Append(QuotedStr(TValue(Values[i]).AsString));vtString:RetVar.Append(QuotedStr(TValue(Values[i]).AsString));vtPChar:RetVar.Append(QuotedStr(TValue(Values[i]).AsString));vtExtended:RetVar.Append(FloatToStr(TValue(Values[i]).AsExtended));vtAnsiString:RetVar.Append(QuotedStr(string(TValue(Values[i]).AsAnsiString)));vtVariant:ifTValue(Values[i]).VType=tvariantdatetimethenRetVar.Append('to_date(').Append(FormatDateTime('dd/mm/yyyy',TValue(Values[i]).AsDateTime)).Append(',').Append(QuotedStr('dd/mm/yyyy')).Append(')')elseRetVar.Append(QuotedStr(TValue(Values[i]).AsString));elseRetVar.Append('??????');end;ifi<High(Values)thenRetVar.AppendLine(', ');end;RetVar.AppendLine(')');Result:=RetVar.ToString;finallyRetVar.Free;end;end;
В этом рефакторированном функции используется TStringBuilder для создания SQL-запроса, что обеспечивает лучшую производительность и управление памятью по сравнению с конкатенацией строк с помощью оператора +. Функция также использует сильные типы переменных (например, TValue, TString) где это возможно, что может помочь предотвратить ошибки типа при выполнении.
Генератор SQL-запросов Insert, Update позволяет упростить процесс создания динамических запросов к базе данных.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.