Форум: "Прочее";
Текущий архив: 2007.02.11;
Скачать: [xml.tar.bz2];
ВнизРазмышления о построении SQL-запроса. Найти похожие ветки
← →
Kostafey © (2007-01-16 23:46) [0]Всем доброго времени суток.
В последнее время пишу в основном какой-то странный код, нелепая смесь паскаля и SQL.
Казалось бы что может быть проще - забросил запрос в строку, в нужный момент отправил в датасет,
вызвал и получил результат. Но вот с чем приходится сталкиваться. Мноие фрагменты этого SQL-кода часто повторяются,
но повторяются не 1:1, а с небольшими изменениями.
Ну самый простой пример, удаление таблиц:
вместо
ADOQuery1.SQL.Text :=
"delete from ZVK1 "#13#10 +
"delete from ZVK2 "#13#10 +
...
пишу
ADOQuery1.SQL.Text := "";
for i := 1 to ZVKTableCount do
ADOQuery1.SQL.Text := ADOQuery1.SQL.Text +
"delete from " + ZVKTableNames[i] + " "#13#10;
Но это было только началом. Потом мне просто ень стало вбивать большие запросы и я стал писать процедуры, которые их
формировали, писать их сложнее, чем просто вбивать текст, зато они защищают от банальных опечаток.
вот один оиз таких "перлов":
//********************************SQL_a5****************************************
procedure TQParam.SQL_a5;
//..............................................................................
function SelectGenerator: widestring;
var i: byte;
ind, srv: string;
begin
for i := 1 to 8 do
begin
ind := cppq(i < 5, inttostr(i), inttostr(i - 4));
srv := cppq(i < 5, "", "_s");
Result := Result +
"case "#13#10 +
" when (z" + ind + srv + ".zcnt is null) and (o" + ind + srv + ".zcnt is null) then 0 "#13#10 +
" when (z" + ind + srv + ".zcnt is null) then o" + ind + srv + ".zcnt "#13#10 +
" when (o" + ind + srv + ".zcnt is null) then z" + ind + srv + ".zcnt "#13#10 +
" else z" + ind + srv + ".zcnt+o" + ind + srv + ".zcnt "#13#10 +
"end as Rank" + ind + srv + ", "#13#10;
end;
end;
//..............................................................................
function JoinGenerator(srv: string): widestring;
var i: byte;
ind, arx, kin: string;
begin
for i := 1 to 8 do
begin
ind := cppq(i < 5, inttostr(i), inttostr(i - 4));
arx := cppq(i < 5, "", "ARX");
kin := cppq(i < 5, "z", "o");
Result := Result +
"LEFT JOIN ( "#13#10 +
" select z.PCH_COD, count(z.PCH_COD) zcnt "#13#10 +
" from ZVK1" + arx + " z "#13#10 +
" where "#13#10 +
" (z.DATE_ZVK between @DateFrom" + srv + " and @DateTo" + srv + ") "#13#10 +
" and (z.RANK=" + ind + ") "#13#10 +
" group by "#13#10 +
" z.PCH_COD "#13#10 +
" "#13#10 +
" ) " + kin + ind + srv + " ON " + kin + ind + srv + ".PCH_COD= p.PCH_COD "#13#10;
end;
end;
//..............................................................................
function SumsGenerator(ind, srv: string): widestring;
begin
Result :=
" (select count(z.PCH_COD)+ "#1310 +
" (select count(o.PCH_COD) "#1310 +
" from ZVK1ARX o "#1310 +
" where (o.DATE_ZVK between @DateFrom" + srv + " and @DateTo" + srv + ") "#1310 +
" and (o.RANK=" + ind + ")) zcnt "#1310 +
" from ZVK1 z "#1310 +
" where (z.DATE_ZVK between @DateFrom" + srv + " and @DateTo" + srv + ") "#1310 +
" and (z.RANK=" + ind + ")) "#1310;
end;
//..............................................................................
begin
SQL_result :=
"select "#13#10 +
" p.PCH_NAME, "#13#10 +
SelectGenerator +
"1 as Dummy "#13#10 +
" "#13#10 +
"from "#13#10 +
" PCH p "#13#10 +
" "#13#10 +
//Анализируемый промеуток времени
JoinGenerator("") +
//Сравнительный промеуток времени
JoinGenerator("_s") +
"union "#13#10 +
"Select ""Итого :"", "#13#10 +
SumsGenerator("1", "") + ", "#13#10 +
SumsGenerator("2", "") + ", "#13#10 +
SumsGenerator("3", "") + ", "#13#10 +
SumsGenerator("4", "") + ", "#13#10 +
SumsGenerator("1", "_s") + ", "#13#10 +
SumsGenerator("2", "_s") + ", "#13#10 +
SumsGenerator("3", "_s") + ", "#13#10 +
SumsGenerator("4", "_s") + ", "#13#10 +
"2 as Dummy "#13#10 +
"order by Dummy, p.PCH_NAME "#13#10;
end;
//______________________________________________________________________________
Остается сохранить SQL_result в файл и протестировать результат.
Возможно кто-то назовет это бредом, я сам последнее время скаптически отношусь к этой смеси языков,
но и писать все влоб не очень хочется - возрастает вероятность опечаток отловить которые на основе получаемых
результатов почти невозможно, да и не совсем красиво переписывать повторяющийся код, даже если этот код "просто текст"
Хотелось бы услышать Ваше мнение и то как лучше выходить из такой ситуации.
P.S. Я не исползую хранимые процедуры сознательно, т.к. в рамках решаемой мною задачи вносить изменения в БД нежелательно.
← →
Sergey Masloff (2007-01-16 23:50) [1]idiot
← →
unknown © (2007-01-16 23:53) [2]
> Kostafey © (16.01.07 23:46)
Такой ужас в коде не есть гуд.
Логичнее было бы хранить тексты запросов в отдельных файлах. Или в ресурсах.
Или в designtime явно прописывать в компонентах.
← →
Sergey Masloff (2007-01-16 23:57) [3]unknown © (16.01.07 23:53) [2]
>Логичнее было бы хранить тексты запросов в отдельных файлах. Или в >ресурсах.
возможно
просто я за одним красавцем сопровождал код такой. Это трындец полный. Причем потом общался с людьми которые с ним впоследствии работали... Он как комета оставил за собой след... Эх, Даля бы он свой словарь бы пополнил эпитетами которые челу складывали...
← →
Eraser © (2007-01-17 00:01) [4]Кстати по теме. Вот пришлось столкнуться с построением запросов, правда на в php коде.
Так вот, есть ли какой-то стандарт написания SQL запросов? в php можно писать практически, как в текстовом файле.. насчет этого проще, чем в Делфи.
← →
Sergey Masloff (2007-01-17 00:04) [5]Eraser © (17.01.07 00:01) [4]
На фиг их строить? Ну мучаете же сервак у него в результате весь процедурный кеш забит а потом удивляются что-то и нагрузка не очень а сервер тормозит... А после перезагрузки какое-то время летает... с чего бы... Не про вас конкретно но столько я таких ситуаций видел... не сосчитать ;-)
← →
Kostafey © (2007-01-17 00:04) [6]> idiot
ну это-то я и сам понял :)
> Логичнее было бы хранить тексты запросов в отдельных файлах.
> Или в ресурсах.
> Или в designtime явно прописывать в компонентах.
Ну а собственно какая разница. Пусть даже в текстовых переменных.
Итог-то один: текст запроса будет уже готовым.
← →
Sergey Masloff (2007-01-17 00:04) [7]p/s а стандарта нет серверу по фиг хоть в одну строку запиши.
← →
vlad-mal © (2007-01-17 00:05) [8]
> Sergey Masloff (16.01.07 23:57) [3]
> я за одним красавцем сопровождал код такой. Это трындец
> полный. Причем потом общался с людьми которые с ним впоследствии
> работали... Он как комета оставил за собой след... Эх, Даля
> бы он свой словарь бы пополнил эпитетами которые челу складывали.
> ..
Вот поэтому таких спецов нужно хранить и лелеять. :0)
Иначе действительно трындец.
← →
Sergey Masloff (2007-01-17 00:06) [9]Kostafey © (17.01.07 00:04) [6]
>ну это-то я и сам понял :)
Заметь что я латиницей. Это не так грубо у буржуев как у нас, так что не обижайся.
А готовый текст это кошерно - всегда легко читать, легко модифицировать, легко трассировать и др.
← →
Джо © (2007-01-17 00:07) [10]> [7] Sergey Masloff (17.01.07 00:04)
> p/s а стандарта нет серверу по фиг хоть в одну строку запиши.
Дык, ведь компилятору тоже пофиг, как исходный код отформатирован, однако же стандарты есть :)
← →
Eraser © (2007-01-17 00:09) [11]> [5] Sergey Masloff (17.01.07 00:04)
> На фиг их строить?
А что с ними тогда делать? )
← →
Eraser © (2007-01-17 00:10) [12]> [7] Sergey Masloff (17.01.07 00:04)
серверу то пофиг, а вот девелоперу нет )
← →
Sergey Masloff (2007-01-17 00:13) [13]Джо © (17.01.07 00:07) [10]
>однако же стандарты есть :)
у каждого свои?
сейчас рефакторю за одним человеком такое впечетление у него правило такое: ни одна соседняя строка не должна начинаться с одной позиции при этом при отступах обязательно чередовать табуляции и пробелы. Выглядит это так (клянусь не утрирую!)
procedure Foo()
Begin
DoSomething();
if b
then
begin
DoSomethingElse();
try
.....
exception
.....
End //try
end //if
End //Foo()
← →
Kostafey © (2007-01-17 00:14) [14]> Заметь что я латиницей. Это не так грубо у буржуев как у
> нас, так что не обижайся.
Как я и говорил - и сам уже понял печенкой что-то не то делаю. Не обижаюсь.
> А готовый текст это кошерно - всегда легко читать, легко
> модифицировать, легко трассировать и др.
А вот на счет такой конструкции:
вместо
ADOQuery1.SQL.Text :=
"delete from ZVK1 "#13#10 +
"delete from ZVK2 "#13#10 +
...
пишу
ADOQuery1.SQL.Text := "";
for i := 1 to ZVKTableCount do
ADOQuery1.SQL.Text := ADOQuery1.SQL.Text +
"delete from " + ZVKTableNames[i] + " "#13#10;
Она еще более менее удобочитаема или и ее лучше в развернутом виде писать ?
← →
Sergey Masloff (2007-01-17 00:16) [15]Kostafey © (17.01.07 00:14) [14]
Все же подумай насчет хранимой процедуры... серьезно
← →
Anatoly Podgoretsky © (2007-01-17 00:18) [16]> Sergey Masloff (17.01.2007 00:13:13) [13]
Он наверно балдет от этого, представляя как другие матерятся.
← →
vlad-mal © (2007-01-17 00:20) [17]
> Sergey Masloff (17.01.07 00:13) [13]
> сейчас рефакторю за одним человеком такое
> впечетление у него правило такое: ни одна соседняя строка
> не должна начинаться с одной позиции при этом при отступах
> обязательно чередовать табуляции и пробелы. Выглядит это
> так (клянусь не утрирую!)
Хе-хе, кажется, я знаю что это такое.
У меня тоже попадалось.
1:1
Чел писал, используя MultyEdit. Вместо штатного редактора Delphi (MultyEdit легко интегрируется). В нем все выглядит OK, пока не откроешь в Delphi.
Возьми DelphiFormatter, отсюда:
http://www.dow.wau.nl/aew/delforexp.html
одно нажатие - и весь проект(или только текущий файл) переформатирован в соответствии с установленными стандартами.
Я давно пользуюсь.
← →
Kostafey © (2007-01-17 00:29) [18]> Sergey Masloff
А вообще кое с чем мжно поспорить.
1. Например формитирование собственно Delphi-кода я делаю со всей тщательность (на сколько это позволяет моя квалификация)
2. В сам SQL-запрос полезет кто-то вряд ли. В случе ошибки задачу вернут мне на доработку.
3. И наконец (об этом я, правда не сказал) программа имеет возможность вывода полученно запроса на экран (перед его выполнением) -
глупость, но если уж кто-то хчет его (запрос) увидеть, то писаь ему не придется ни строчки
← →
vlad-mal © (2007-01-17 00:38) [19]Kostafey © (16.01.07 23:46)
> Всем доброго времени суток. В последнее время пишу в основном
> какой-то странный код, нелепая смесь паскаля и SQL.
Можно состряпать какой-нибудь компонент - наследник TCollection, например, по образцу редактора столбцов в гриде или редакторе полей в наборе данных. Главным свойством элемента коллекции будет текст запроса, который редактировать в TRichEdit (или TSynEdit).
И в этой коллекции сосредоточить все тексты твоих запросов.
Или просто в чем-нибудь внешнем хранить. Хоть в TXT - файлах.
← →
Kostafey © (2007-01-17 00:55) [20]> Можно состряпать какой-нибудь компонент - наследник TCollection,
> например, по образцу редактора столбцов в гриде или редакторе
> полей в наборе данных. Главным свойством элемента коллекции
> будет текст запроса, который редактировать в TRichEdit
> (или TSynEdit).
К сожалению до темы разработки компоненьов у меня руки до сих пор не дошли...
> Или просто в чем-нибудь внешнем хранить. Хоть в TXT - файлах.
Хм. пользователь может слазить в такоой вот файлиик и случайно его повредить. Хотя я и такой вариант обдумывал.
Но тогда уж ini, т.к. встречаются доволно часто и не болльшие запросы, надо все структурировать.
Вот, тоже, пожалуй удачный пример такой смеси:
вместо
ADOQuery1.SQL.Text :=
"IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N""[dbo].[ZVK1ARX]"") AND type in (N""U"")) "#13#10 +
"DROP TABLE [dbo].[ZVK1ARX] "#13#10 +
" "#13#10 +
"IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N""[dbo].[ZVK3ARX]"") AND type in (N""U"")) "#13#10 +
"DROP TABLE [dbo].[ZVK3ARX] "#13#10 +
" "#13#10 +
"IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N""[dbo].[ZVK41ARX]"") AND type in (N""U"")) "#13#10 +
"DROP TABLE [dbo].[ZVK41ARX] "#13#10 +
" "#13#10 +
"IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N""[dbo].[ZVK4ARX]"") AND type in (N""U"")) "#13#10 +
"DROP TABLE [dbo].[ZVK4ARX] "#13#10 +
" "#13#10 +
"IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N""[dbo].[ZVK_TEXARX]"") AND type in (N""U"")) "#13#10 +
"DROP TABLE [dbo].[ZVK_TEXARX] "#13#10 +
" "#13#10 +
"IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N""[dbo].[zvkrtpARX]"") AND type in (N""U"")) "#13#10 +
"DROP TABLE [dbo].[zvkrtpARX] "#13#10;
написать
for i := 1 to FRCTableCount do
ADOQuery1.SQL.Text := ADOQuery1.SQL.Text +
"IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N""[dbo]." + FRCARXTableNames[i] + #39 +
") AND type in (N""U"")) "#13#10 +
"DROP TABLE [dbo].[" + FRCARXTableNames[i] + "] "#13#10;
По-моему читабельность повышается...
← →
Константинов © (2007-01-17 01:02) [21]Я далеко не гуру, но вот баловался работой с локальными БД примерно так:
Function GetIDRecord ( const Value : string ) : integer;
begin
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add("SELECT * FROM TABLE1");
ADOQuery1.SQL.Add("WHERE Field1 = "" + Value +"";");
ADOQuery1.Open;
try
ADOQuery1.First;
Result := -1;
if ADOQuery1.Eof then Exit;
Result := ADOQuery1.FieldByName("ID").AsInteger;
finally
ADOQuery1.Close;
end;
end;
По моему, по крайней мере читабельно...
Уж не знаю, как такой запрос скажется на кэше сервера.
← →
Kostafey © (2007-01-17 01:07) [22]> ADOQuery1.SQL.Add("SELECT * FROM TABLE1");
> ADOQuery1.SQL.Add("WHERE Field1 = "" + Value +"";");
Речь вроде шла о несколько более объемных запросах ?
← →
Sergey13 © (2007-01-17 09:33) [23]> [20] Kostafey © (17.01.07 00:55)
Такое впечатление, что удаление ВСЕХ данных из однотипных таблиц и удаление самих этих таблиц - это основной принцип твоей работы с БД. Если это так, то ты явно не доработал в проектировании.
ИМХО.
← →
Kostafey © (2007-01-17 09:36) [24]> [23] Sergey13 © (17.01.07 09:33)
Зато создание таблицц я делеал по одной (поля-то у всех все равно разные).
Только удаление выглядит толково в цикле.
← →
Sergey13 © (2007-01-17 09:40) [25]> [24] Kostafey © (17.01.07 09:36)
Так это и настораживает: создание таблиц, удаление всех данных из них, удаление самих таблиц. Странный (мягко сказать) принцип работы. Подобная работа с метаданными в приложении не есть гут, как правило.
← →
Kostafey © (2007-01-17 09:47) [26]> Так это и настораживает: создание таблиц, удаление всех
> данных из них, удаление самих таблиц. Странный (мягко сказать)
> принцип работы. Подобная работа с метаданными в приложении
> не есть гут, как правило.
А что не так. Нормальная утилита админитсрирования БД получилась почти.
← →
Рамиль © (2007-01-17 09:47) [27]
> Зато создание таблицц я делеал по одной (поля-то у всех
> все равно разные).
Обрати внимание на [23], зачем программе создавать и удалять таблицы? Если только темповые...
← →
Sergey13 © (2007-01-17 09:54) [28]> [26] Kostafey © (17.01.07 09:47)
А зачем ТАК администрировать БД?
Я не знаю твоей задачи и ничего не утверждаю, но мне кажется странным - работают люди, пишут/правят данные, приходит админ, все потер и пересоздал таблицы.
Если же ты пишешь некий универсальный просмотршик/манипулятор данными для СУБД, то непонятно забивание в код конкретных названий объектов.
← →
Kostafey © (2007-01-17 10:04) [29]> Обрати внимание на [23], зачем программе создавать и удалять
> таблицы? Если только темповые...
Да, и темповые в том числе.
> Я не знаю твоей задачи и ничего не утверждаю, но мне кажется
> странным - работают люди, пишут/правят данные, приходит
> админ, все потер и пересоздал таблицы.
Планируется это делать раз в год. (или реже при необходимости)
> Если же ты пишешь некий универсальный просмотршик/манипулятор
> данными для СУБД
Нет нет, ничего такого.
← →
Kostafey © (2007-01-17 10:05) [30]> Обрати внимание на [23], зачем программе создавать и удалять
> таблицы? Если только темповые...
Да, и темповые в том числе.
> Я не знаю твоей задачи и ничего не утверждаю, но мне кажется
> странным - работают люди, пишут/правят данные, приходит
> админ, все потер и пересоздал таблицы.
Планируется это делать раз в год. (или реже при необходимости)
> Если же ты пишешь некий универсальный просмотршик/манипулятор
> данными для СУБД
Нет нет, ничего такого.
← →
Sergey13 © (2007-01-17 10:13) [31]> [29] Kostafey © (17.01.07 10:04)
> Планируется это делать раз в год. (или реже при необходимости)
Зачем? Это нечто вроде перегонки данных в архивы? Велики ли объемы данных?
← →
Kostafey © (2007-01-17 10:19) [32]> Зачем? Это нечто вроде перегонки данных в архивы? Велики
> ли объемы данных?
На самом деле не столь велики. Бэкап архивных таблиц за ~1,5 года работы не превышает 3 мб.
Я руководителю говорил примерно то же. Он сказал, что возможно я прав, но все равно сделать нужно.
← →
Sergey13 © (2007-01-17 10:25) [33]> [32] Kostafey © (17.01.07 10:19)
У тебя начальник думает в категориях файл-сервера 15 летней давности, отсюда и ценные указания.
← →
Рамиль © (2007-01-17 10:28) [34]
> На самом деле не столь велики. Бэкап архивных таблиц за
> ~1,5 года работы не превышает 3 мб.
Пф.. У нас база > 250 Гб и ничего, нормально работает.
← →
Kostafey © (2007-01-17 10:38) [35]> У тебя начальник думает в категориях файл-сервера 15 летней
> давности, отсюда и ценные указания.
> Пф.. У нас база > 250 Гб и ничего, нормально работает.
Знаю, у нас даже в терминах расхождения например таблицу он называет полем.
Ну да ладно, человек он все равно умный и все (в т.ч. и я) его уважают.
Не об этом речь :)
← →
Рамиль © (2007-01-17 10:39) [36]
> человек он все равно умный и все (в т.ч. и я) его уважают.
Так убеди, дай литературу почитать.
← →
Kostafey © (2007-01-17 10:45) [37]> Так убеди, дай литературу почитать.
Как ты это себе представляешь ? У нас разница в возрасте лет 25-30.
Лучше буду вносить свои предложения, но делать то что говорят, а уж то КАК я буду это делать ему все равно не так важно.
← →
clickmaker © (2007-01-17 11:12) [38]
> Kostafey ©
Учись, пока я жив )Unit sqlstmt;
interface
uses SysUtils, Classes, Db, Provider, ADODB, contnrs, ADOInt;
type
TMyParam = class
Name: string;
DataType: TFieldType;
Value: Variant;
end;
TSQLStmt = class
{Класс для формирования SQL - операторов}
private
FParams: TObjectList;
procedure AddParam(const Name: string; const Value: Variant; FieldType: TFieldType);
protected
function GetStatement: string; virtual;
public
constructor Create; virtual;
destructor Destroy; override;
procedure Execute();
property Statement: string read GetStatement;
end;
TSelectJoin = class
public
LeftFieldName: string;
RightTableName: string;
RightFieldName: string;
Value: Variant;
end;
TSelectJoins = class(TList)
private
function GetItem(Index: integer): TSelectJoin;
procedure SetItem(Index: integer; Value: TSelectJoin);
public
function Add(Join: TSelectJoin): integer;
property Items[Index: integer]: TSelectJoin read GetItem write SetItem; default;
end;
TSelect = class(TSQLStmt)
{Класс для формирования оператора select}
private
FFields: TStringList;
FTables: TStringList;
FFilters: TStringList;
FOrdFields: TStringList;
protected
function GetStatement: string; override;
public
constructor Create; override;
destructor Destroy; override;
procedure AddField(TableName, FieldName: string);
procedure AddTable(TableName: string);
procedure AddFilter(Filter: string);
procedure AddOrdField(TableName, FieldName: string);
end;
TInsert = class(TSQLStmt)
{Класс для формирования оператора insert}
private
FTable: string;
FFields: TStringList;
protected
function GetStatement: string; override;
public
constructor Create; override;
destructor Destroy; override;
procedure AddField(FieldName: string; Value: Variant; FieldType: TFieldType);
function FieldCount: integer;
property Table: string read FTable write FTable;
end;
TUpdate = class(TSQLStmt)
{Класс для формирования оператора update}
private
FTable: string;
FFields: TStringList;
FKeyFields: TStringList;
function GetFieldCount: integer;
protected
function GetStatement: string; override;
public
constructor Create; override;
destructor Destroy; override;
procedure AddField(FieldName: string; Value: Variant; FieldType: TFieldType);
procedure AddKeyField(FieldName: string; Value: Variant; FieldType: TFieldType);
property FieldCount: integer read GetFieldCount;
property Table: string read FTable write FTable;
end;
TDelete = class(TSQLStmt)
{Класс для формирования оператора delete}
private
FTable: string;
FKeyFields: TStringList;
protected
function GetStatement: string; override;
public
constructor Create; override;
destructor Destroy; override;
procedure AddKeyField(FieldName: string; Value: Variant; FieldType: TFieldType);
property Table: string read FTable write FTable;
end;
implementation
function List2Line(List: TStrings; Delimiter: string): string;
var
i: integer;
begin
for i:=0 to List.Count-1 do begin
if i<>0 then Result:=Result+Delimiter;
Result:=Result+List[i];
end;
end;
function ParamNames2Line(Params: TObjectList; Delimiter: string): string;
var i: integer;
begin
for i:=0 to Params.Count-1 do begin
if i<>0 then Result:=Result+Delimiter;
Result:=Result+Format(":%s", [TMyParam(Params[i]).Name]);
end;
end;
function FieldsParams2Line(Fields: TStrings; Params: TObjectList;
FirstParam: integer; Delimiter: string): string;
var i: integer;
begin
for i:=0 to Fields.Count-1 do begin
if i<>0 then Result:=Result+Delimiter;
Result:=Result+Format("%s = :%s", [Fields[i], TMyParam(Params[FirstParam+i]).Name]);
end;
end;
function BuildClause(ClauseToken, ClauseText: string): string;
begin
if ClauseText<>"" then Result:=ClauseToken+" "+ClauseText;
end;
function AddCRLF(Str: string): string;
begin
if Str<>"" then Result:=#13#10+Str else Result:="";
end;
function ParamSize(DataType: TDataType): integer;
begin
case DataType of
ftString: Result := 255;
ftMemo, ftBlob: Result := MaxInt;
else Result := 0;
end;
end;
{ TSQLStmt }
constructor TSQLStmt.Create;
begin
FParams:=TObjectList.Create(true);
end;
destructor TSQLStmt.Destroy;
begin
FParams.Free;
end;
procedure TSQLStmt.AddParam(const Name: string; const Value: Variant; FieldType: TFieldType);
var Param: TMyParam;
begin
Param := TMyParam.Create;
Param.Name := Name;
Param.DataType := FieldType;
Param.Value := Value;
FParams.Add(Param);
end;
procedure TSQLStmt.Execute();
var
Query: TADOQuery;
i: integer;
Param: TMyParam;
begin
Query:=CreateQuery;
try
for i := 0 to Query.Parameters.Count-1 do begin
Param := TMyParam(FParams.Items[i]);
Query.Parameters[i].DataType := Param.DataType;
Query.Parameters[i].Direction := pdInput;
Query.Parameters[i].Size := ParamSize(Param.DataType);
Query.Parameters[i].Value := Param.Value;
end;
Query.ExecSQL;
finally
Query.Free;
end;
end;
function TSQLStmt.GetStatement: string;
begin
Result:="";
end;
{ TSelectJoins }
function TSelectJoins.Add(Join: TSelectJoin): integer;
begin
Result := inherited Add(Join);
end;
function TSelectJoins.GetItem(Index: integer): TSelectJoin;
begin
Result:=TSelectJoin(inherited Items[Index]);
end;
procedure TSelectJoins.SetItem(Index: integer; Value: TSelectJoin);
begin
inherited Items[Index]:=Value;
end;
{ TSelect }
constructor TSelect.Create;
begin
inherited Create;
FFields:=TStringList.Create;
FTables:=TStringList.Create;
FFilters:=TStringList.Create;
FOrdFields:=TStringList.Create;
end;
destructor TSelect.Destroy;
begin
FFields.Free;
FTables.Free;
FFilters.Free;
FOrdFields.Free;
inherited Destroy;
end;
procedure TSelect.AddField(TableName, FieldName: string);
begin
AddTable(TableName);
FFields.Add(TableName+"."+FieldName);
end;
procedure TSelect.AddTable(TableName: string);
begin
if FTables.IndexOf(TableName)=-1 then FTables.Add(TableName);
end;
procedure TSelect.AddFilter(Filter: string);
begin
FFilters.Add(Filter);
end;
procedure TSelect.AddOrdField(TableName, FieldName: string);
begin
if FOrdFields.IndexOf(TableName+"."+FieldName)=-1 then
FOrdFields.Add(TableName+"."+FieldName);
end;
function TSelect.GetStatement: string;
begin
Result:=BuildClause("select", List2Line(FFields, ", "));
Result:=Result+AddCRLF(BuildClause("from", List2Line(FTables, ", ")));
Result:=Result+AddCRLF(BuildClause("where", List2Line(FFilters, " and ")));
Result:=Result+AddCRLF(BuildClause("order by", List2Line(FOrdFields, ", ")));
end;
← →
clickmaker © (2007-01-17 11:12) [39]
{ TInsert }
constructor TInsert.Create;
begin
inherited Create;
FFields:=TStringList.Create;
end;
destructor TInsert.Destroy;
begin
FFields.Free;
inherited Destroy;
end;
procedure TInsert.AddField(FieldName: string; Value: Variant; FieldType: TFieldType);
begin
if not VarIsEmpty(Value) then begin
FFields.Add(FieldName);
AddParam(Format("Param%d", [FParams.Count+1]), Value, FieldType);
end;
end;
function TInsert.GetStatement: string;
var Cols, Vals: string;
begin
Cols:=List2Line(FFields, ", ");
Vals:=ParamNames2Line(FParams, ", ");
Result:=Format("insert into %s (%s) values (%s)", [FTable, Cols, Vals]);
end;
function TInsert.FieldCount: integer;
begin
Result:=FFields.Count;
end;
{ TUpdate }
constructor TUpdate.Create;
begin
inherited Create;
FFields:=TStringList.Create;
FKeyFields:=TStringList.Create;
end;
destructor TUpdate.Destroy;
begin
FFields.Free;
FKeyFields.Free;
inherited Destroy;
end;
procedure TUpdate.AddField(FieldName: string; Value: Variant; FieldType: TFieldType);
begin
if not VarIsEmpty(Value) then begin
FFields.Add(FieldName);
AddParam(Format("Param%d", [FParams.Count+1]), Value, FieldType);
end;
end;
procedure TUpdate.AddKeyField(FieldName: string; Value: Variant; FieldType: TFieldType);
begin
if not VarIsEmpty(Value) then begin
FKeyFields.Add(FieldName);
AddParam(Format("Param%d", [FParams.Count+1]), Value, FieldType);
end;
end;
function TUpdate.GetStatement: string;
var Cols, KeyCols: string;
begin
Cols:=FieldsParams2Line(FFields, FParams, 0, ", ");
KeyCols:=FieldsParams2Line(FKeyFields, FParams, FFields.Count, " and ");
Result:=Format("update %s set %s where %s", [FTable, Cols, KeyCols]);
end;
function TUpdate.GetFieldCount: integer;
begin
Result:=FFields.Count;
end;
{ TDelete }
constructor TDelete.Create;
begin
inherited Create;
FKeyFields:=TStringList.Create;
end;
destructor TDelete.Destroy;
begin
FKeyFields.Free;
inherited Destroy;
end;
procedure TDelete.AddKeyField(FieldName: string; Value: Variant; FieldType: TFieldType);
begin
if not VarIsEmpty(Value) then begin
FKeyFields.Add(FieldName);
AddParam(Format("Param%d", [FParams.Count+1]), Value, FieldType);
end;
end;
function TDelete.GetStatement: string;
var KeyCols: string;
begin
KeyCols:=FieldsParams2Line(FKeyFields, FParams, 0, " and ");
Result:=Format("delete from %s where %s", [FTable, KeyCols])
end;
← →
Kostafey © (2007-01-17 11:22) [40]> clickmaker ©
Боже мой ! Что это ? Стасибо огромное, но у меня удут годы чтобы это освоить !
А если серьезно, то обязательно постараюсь разобраться как это применять-то хотя бы.
Консультации та эту тему не предусмотрены ?
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2007.02.11;
Скачать: [xml.tar.bz2];
Память: 0.63 MB
Время: 0.039 c