home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / full / delphi / DELPHI16 / TECHINFO / DELPHI / TIS / TI2820.FX < prev    next >
Encoding:
Text File  |  1995-08-24  |  8.5 KB  |  244 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.   PRODUCT  :  Delphi                                 NUMBER  :  2820
  8.   VERSION  :  All
  9.        OS  :  Windows
  10.      DATE  :  July 14, 1995                            PAGE  :  1/4
  11.  
  12.     TITLE  :  Searching Through Query Result Sets
  13.  
  14.  
  15.  
  16.  
  17. The TQuery component does not offer the index-based search capabilities of
  18. the TTable component (FindKey, GotoKey, and GotoNearest). So how do you
  19. search within the result data set from a TQuery to find a row with a spec-
  20. ific field value?
  21.  
  22. One way to search a query result set is a sequential search. This type of
  23. search starts at the first row in the data set and, in a While loop, 
  24. sequentially compares the value of a field in the row with a search value.
  25. One of two results are possible: a value will be found (success) or the
  26. end of the data set will be reached (failure). The problem with this way
  27. of searching the data set is that the further into the data set a row with
  28. a matching value is, the longer it takes to arrive at that row. And, a
  29. failed search takes longest of all because it must go all the way to the
  30. last row in the data set. If the data set being searched is a large one,
  31. this process may take a considerable amount of time.
  32.  
  33. Here is a function that will perform a sequential search of the result set
  34. from a TQuery:
  35.  
  36.   function SeqSearch(AQuery: TQuery; AField, AValue: String): Boolean;
  37.   begin
  38.     with AQuery do begin
  39.       First;
  40.       while (not Eof) and (not (FieldByName(AField).AsString = AValue)) do
  41.         Next;
  42.       SeqSearch := not Eof;
  43.     end;
  44.   end;
  45.  
  46. This function takes three parameters:
  47.  
  48.   1. AQuery: type TQuery; the TQuery component in which the search is to
  49.              be executed.
  50.   2. AField: type String; the name of the field against which the search
  51.              value will be compared.
  52.   3. AValue: type String; the value being searched for. If the field is of
  53.              a data type other than String, this search value should be
  54.              changed to the same data type.
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.   PRODUCT  :  Delphi                                 NUMBER  :  2820
  69.   VERSION  :  All
  70.        OS  :  Windows
  71.      DATE  :  July 14, 1995                            PAGE  :  2/4
  72.  
  73.     TITLE  :  Searching Through Query Result Sets
  74.  
  75.  
  76.  
  77.  
  78.              
  79. The Boolean return value of this function indicates the success (True) or
  80. failure (False) of the search.
  81.   
  82. An alternative is using a bracketing approach. On a conceptual level, this
  83. method acts somewhat like a b-tree index. It is based on the given that
  84. for a row at a given point in the data set, the value of the field being
  85. searched compared to the search value will produce one of three possible
  86. conditions:
  87.  
  88.   1. The field value will be greater than the search value, or...
  89.   2. The field value will be less than the search value, or...
  90.   3. The field value will be equal to the search value.
  91.  
  92. A bracketing search process uses this means of looking at the current row
  93. in respect to the search value and uses it to successively reduce the rows
  94. to be search by half, until only one row remains. This search field value
  95. for this sole remaining row will either be a match to the search value
  96. (success) or it will not (failure, and no match exists in the data set).
  97.  
  98. Functionally, this process lumps the condition of the search field being
  99. less than or equal to the search value into a single condition. This
  100. leaves only two possible results for the comparison of the current
  101. search field value with the search value: less than/equal to or greater
  102. than. Initially, a range of numbers is established. The low end of the
  103. range is represented by an Integer, at the start of the search process set
  104. to 0 or one less than the first row in the data set. The far end of the
  105. range is also an Integer, with the value of the RecordCount property of
  106. the TQuery. The current row pointer is then moved to a point half way
  107. between the low and high ends of the range. The search field value at that
  108. row is then compared to the search value. If the field value is less than
  109. or equal to the search value, the row being sought must be in the lower
  110. half of the range of rows so the high end of the range is reduced to the
  111. current row position. If the field value is greater than the search value,
  112. the sought value must be in the higher half of the range and so the low
  113. end is raised to the current point. By repeating this process, the number
  114. of rows that are encompassed in the range are successively reduced by
  115. half. Eventually, only one row will remain.
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.   PRODUCT  :  Delphi                                 NUMBER  :  2820
  130.   VERSION  :  All
  131.        OS  :  Windows
  132.      DATE  :  July 14, 1995                            PAGE  :  3/4
  133.  
  134.     TITLE  :  Searching Through Query Result Sets
  135.  
  136.  
  137.  
  138.  
  139.  
  140. Putting this into a modular, transportable function, the code would look
  141. like that below:
  142.  
  143.   function Locate(AQuery: TQuery; AField, AValue: String): Boolean;
  144.   var
  145.     Hi, Lo: Integer;
  146.   begin
  147.     with AQuery do begin
  148.       First;
  149.       {Set high end of range of rows}
  150.       Hi := RecordCount;
  151.       {Set low end of range of rows}
  152.       Lo := 0;
  153.       {Move to point half way between high and low ends of range}
  154.       MoveBy(RecordCount div 2);
  155.       while (Hi - Lo) > 1 do begin
  156.         {Search field greater than search value, value in first half}
  157.         if (FieldByName(AField).AsString > AValue) then begin
  158.           {Lower high end of range by half of total range}
  159.           Hi := Hi - ((Hi - Lo) div 2);
  160.           MoveBy(((Hi - Lo) div 2) * -1);
  161.         end
  162.         {Search field less than search value, value in far half}
  163.         else begin
  164.           {Raise low end of range by half of total range}
  165.           Lo := Lo + ((Hi - Lo) div 2);
  166.           MoveBy((Hi - Lo) div 2);
  167.         end;
  168.       end;
  169.       {Fudge for odd numbered rows}
  170.       if (FieldByName(AField).AsString > AValue) then Prior;
  171.       Locate := (FieldByName(AField).AsString = AValue)
  172.     end;
  173.   end;
  174.  
  175. Because there will never be a difference of less than one between the low
  176. and high ends of the range of rows, a final fudge was added to allow the
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.   PRODUCT  :  Delphi                                 NUMBER  :  2820
  191.   VERSION  :  All
  192.        OS  :  Windows
  193.      DATE  :  July 14, 1995                            PAGE  :  4/4
  194.  
  195.     TITLE  :  Searching Through Query Result Sets
  196.  
  197.  
  198.  
  199.  
  200. search to find the search value in odd numbered rows.
  201.  
  202. This function takes the same three three parameters as the SeqSearch
  203. function described earlier.
  204.  
  205. The return value of this function is of type Boolean, and reflects the
  206. success or failure of the search. As the search does move the row pointer,
  207. the effects of this movement on the implicit posting of changed data and
  208. on where the desired position of the row pointer should be after a failed
  209. search should be taken into account in the calling application. For
  210. instance, a TBookmark pointer might be used to return the row pointer to
  211. where it was prior to a search if that search fails.
  212.  
  213. How is this process better than a sequential search? First, in bracketing
  214. the search value, only a fraction of the number of rows will be visited as
  215. would be the case in a sequential search. Unless the row with the value
  216. being sought is in the first 1,000 rows, this search method will be faster
  217. than a sequential search. Because this process always uses the same number
  218. of records, the search time will be consistent whether searching for the
  219. value in row 1,000 or row 90,000. This is in contrast with the sequential
  220. search that takes longer the farther into the data set the desired row is.
  221.  
  222. Can this method be used with any TQuery result set? No. Because of the way
  223. this method works in basing the direction of the search as either high or
  224. low, it depends on the row being ordered in a descending manner based on
  225. the field in which the search will be conducted. This means that it can
  226. only be used if the data set is naturally in a sequential order or an
  227. ORDER BY clause is used in the SQL statement for the TQuery. The size of
  228. the result set will also be a factor when deciding whether to perform a
  229. sequential or bracketing search. This process is most advantageous for
  230. speed when used with larger result sets. With smaller sets (1,00 or less
  231. rows), though, a sequential search will often be as fast or faster.
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240. DISCLAIMER: You have the right to use this technical information
  241. subject to the terms of the No-Nonsense License Statement that
  242. you received with the Borland product to which this information
  243. pertains.
  244.