"Советы по Delphi. Версия 1.0.6" - читать интересную книгу автора (Озеров Валентин)

Быстрый поиск в базах данных

Я представляю на Ваш суд утилиту быстрого поиска по базе данных. Данная технология производит поиск по полям, преобразуя их значения в строки (все значения преобразуются в верхний регистр, включая действительные числа). Данное решение может быть не самым быстрым, однако на поверку оно оказывается быстрее остальных, обнаруженных мною в Интернете (может вам повезет больше). Более того, представьте, что действительное значение какого-либо поля равно 4.509375354, а значение поиска равно 7, в этом случае утилита засчитает "попадание". Утилита удобна также тем, что она за один проход производит поиск более, чем в одном поле. Это удобно, если у Вас имеются, к примеру, два поля с адресами. Это моя первая "серьезная" разработка, так как первое, с чем я столкнулся, изучая Delphi, стала необходимость включения процедуры поиска в любое приложение, работающее с базой данных. А так как поиск – вещь тоже сугубо специфическая, как и любое приложение, то мне пришлось побороть свой страх перед "крутым программированием" и попробовать написать свой поисковый механизм, удовлетворивший меня (и, надеюсь, других) своей скоростью и возможностью "мульти"-поиска по нескольким полям. Я надеюсь, что он поможет тем программистам, кто часто сталкивается с подобными задачами. Технология довольно легка для понимания, но если у Вас возникли какие-либо вопросы, пошлите мне письмо электронной почтой, я буду рад Вам помочь. Посмотрев код, можно легко узнать поддерживаемые типы полей (добавить новые не составит проблем). Если кто-либо обнаружит ошибочный код или расширит функциональность утилиты, пожалуйста, пошлите это мне, я буду весьма благодарен. Спасибо.

unit Finder;


interface

uses DB, DBTables, SysUtils;

function GrabMemoFieldAsPChar(TheField: TMemoField): PChar;

function DoFindIn(TheField: TField; SFor: String): Boolean;

function FindIt(TheTable : TDataSet; TheFields: array of integer; SearchBackward: Boolean; FromBeginning: Boolean; SFor: String): boolean;

{применение функции FindIt – if FindIt(NotesSearchT, [NotesSearchT.FieldByName('Leadman').Index], False, True, SearchText.Text) then DoSomething; }


implementation


function GrabMemoFieldAsPChar(TheField: TMemoField): PChar;

begin

 with TBlobStream.Create(TheField, bmRead) do begin

  GetMem(Result, Size + 1);

  FillChar(Result^, Size + 1, #0);

  Read(Result^, Size);

  Free;

 end;

end;


function DoFindIn(TheField : TField; SFor : String): Boolean;

var

 PChForMemo: PChar;

begin

 Result:= False;

 case TheField.DataType of

 ftString: begin

  if (Pos(SFor, UpperCase(TheField.AsString))gt; 0) then Result := True;

 end;

 ftInteger: begin

  if (Pos(SFor, TheField.AsString)gt; 0) then Result:= True;

 end;

 ftBoolean: begin

  if SFor = UpperCase(TheField.AsString) then Result:= True;

 end;

 ftFloat: begin

  if (Pos(SFor, TheField.AsString) gt; 0) then Result := True;

 end;

 ftCurrency: begin

  if (Pos(SFor, TheField.AsString) gt; 0) then Result := True;

 end;

 ftDate..ftDateTime: begin

  if (Pos(SFor, TheField.AsString) gt; 0) then Result := True;

 end;

 ftMemo:  begin

  SFor[Ord(SFor[0]) + 1]:= #0;

  PChForMemo:= GrabMemoFieldAsPChar(TMemoField(TheField));

  StrUpper(PChForMemo);

  if not (StrPos( PChForMemo, @SFor[1] ) = nil) then Result:= True;

  FreeMem(PChForMemo, StrLen(PChForMemo + 1));

 end;

 end;

end;


function FindIt(TheTable: TDataSet; TheFields: array of integer; SearchBackward: Boolean; FromBeginning: Boolean; SFor: String): boolean;

var

 i, HighTheFields, LowTheFields: integer;

 BM: TBookmark;

begin

 TheTable.DisableControls;

 BM:= TheTable.GetBookmark;

 try

  LowTheFields:= Low(TheFields);

  HighTheFields:= High(TheFields);

  SFor:= UpperCase(SFor);

  Result:= False;

  if FromBeginning then TheTable.First;

  if SearchBackwardthen begin

   TheTable.Prior;

   while not TheTable.BOF do begin

    for i:= LowTheFields to HighTheFields do begin

     if DoFindIn(TheTable.Fields[TheFields[i]], SFor) then begin

      Result := True;

      Break;

     end;

    end;

    if Result then Break else TheTable.Prior;

   end;

  end else begin

   TheTable.Next;

   while not TheTable.EOF do begin

    for i:= LowTheFields to HighTheFields do begin

     if DoFindIn(TheTable.Fields[TheFields[i]], SFor) then begin

      Result:= True;

      Break;

     end;

    end;

    if Result then Break else TheTable.Next;

   end;

  end;

 finally

  TheTable.EnableControls;

  if not Result then TheTable.GotoBookmark(BM);

  TheTable.FreeBookmark(BM);

 end;

end;


end.