Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 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.055 c
2-1169572080
Godness
2007-01-23 20:08
2007.02.11
Как создать форму в паралельном потоке?


2-1169132592
Ega23
2007-01-18 18:03
2007.02.11
Как узнать собственный IP?


15-1169158353
hmmcensured
2007-01-19 01:12
2007.02.11
накрутка посещаемости и кликов (adSense)


15-1169071857
DillerXX
2007-01-18 01:10
2007.02.11
На сколько выстрелов обычно хватает глушителя?


2-1169538907
daser
2007-01-23 10:55
2007.02.11
Как написать консольное приложение с передачей ему параметров?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский