Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.02.11;
Скачать: CL | DM;

Вниз

Размышления о построении 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;
Скачать: CL | DM;

Наверх




Память: 0.64 MB
Время: 0.047 c
15-1169119293
Rtn
2007-01-18 14:21
2007.02.11
Как востановить БД, из backup, под другим именем


15-1169555154
default
2007-01-23 15:25
2007.02.11
Рамка выделения штрих-пунктиром как в графических редакторах


2-1169807810
Juice
2007-01-26 13:36
2007.02.11
Вещественные числа и округление


15-1169129466
Bless
2007-01-18 17:11
2007.02.11
Какое на аравийском полуострове есть христианское государство?


6-1157533660
wolchonok29
2006-09-06 13:07
2007.02.11
ПРоблема с сетью