Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Suche: Suchstrings (https://www.delphipraxis.net/1688-suche-suchstrings.html)

Kuckuckskind 18. Dez 2002 13:05


Suche: Suchstrings
 
Hallo,

ich habe folgenden "Schönheitsfehler" bei meiner SELECT-Abfrage.

Die SELECT-Abfrage sieht im Prinzip wie folgt aus:
Code:
SELECT * FROM buecher WHERE titel ="%'+Edit1.Text+'%"
So, wenn ich nun z.B. den Suchbegriff "der" eingebe, bekomem ich sowohl Buchtitel, in denen der als Artikel gebracuht wird als auch ein Wortbestandteil ist. Das ist zwar nicht ideal, damit könnte ich aber leben. Die Abfrage musste ich deshalb so gestalten, weil Buchtitel überwiegend ja auch mehreren Worten bestehen (z.B. "Kochen mit dem Blubb"). Wenn ich ohne Platzhalter (%) die Suche gestalte, wird dieses Buch nicht gefunden, wenn ich nur das zweite Wort eingebe.
ibt es eine Möglichkeit, das zu ändern? Ich hoffe, ihr habt mein Problem verstanden... wirklich schlimm ist es so ja nicht, es ist aber ziemlich störend, wenn man viele Suchergebnisse ausgegeben bekommt, die eigentlich nicht zum ursprünglichen Sinn des Suchbegriffs passen...

harrybo 18. Dez 2002 14:43

Hi Kuckuckskind,

ich kann Dein Problem möglicherweise nicht genau verstehen. Könntest Du kurz anhand eines Beispiels beschreiben, was das Ergebnis der SELECT Abfrage sein soll? Also z.B.

Eingabe soll sein: "der"
Suchergebnis soll sein: "Mein Freund der Baum", "Der Prozess"
Nicht im Ergebnis soll sein: "Wanderer, wo willst Du hin?"

(Angabe der Datenbank wäre auch hilfreich, wegen unterschiedlicher Syntax)

gruß, harrybo

Christian Seehase 18. Dez 2002 15:02

Moin Kuckuckskind,

wie Du schon sagtest, kommst Du um die % nicht herum, aber hast Du schon mal versucht den Suchbegriff um Blanks zu ergänzen (vorne und hinten)?

Dann solltest Du einzeln stehende Worte herausfinden können.

Ob die dann gesetzt werden sollen um ein einzeln stehendes Wort zu finden, oder nicht um den Begriff auch in einem Wortbestandteil zu finden, liesse sich ja über ein Option (z.B. mit CheckBox abfragen) realisieren.

xbu58 18. Dez 2002 18:53

Hallo Kuckuckskind

Bei alle Datenbanken, welche SQL92 unterstützen (das heisst alle neueren DB-Server wie MS-SQLServer ab Version 6.5, alle Sybase Server nicht alter als 4 Jahre, Orakle ab Version 7 usw.) kann mit folgenden WHERE solche Abfragen gemacht werden:
Code:
SELECT * FROM TableName WHERE StringField LIKE '%der%'
Gruss
Xaver

harrybo 19. Dez 2002 12:35

Hi,
der Trick mit den Blanks von Christian Seehase sollte funktionieren, falls es das ist, was Du suchst. Da der Suchbegriff der gesamte Titel sein kann, am Anfang, in der Mitte oder am Ende stehen kann, sähe die Abfrage dann so aus:
Code:
SELECT * FROM Tabelle WHERE ((StringField LIKE '%der%') OR (StringField LIKE '%der %') OR (StringField LIKE '% der%'))
gruß, harrybo

Christian Seehase 19. Dez 2002 12:40

Moin harrybo,

korrigier mich bitte, wenn ich jetzt was falsches sage aber:

%der% beinhaltet doch auch schon %der % und % der%, oder?
(und entspricht somit Kuckuckskinds Ursprungsabfragemaske)

xbu58 19. Dez 2002 14:38

Hallo Chris

Deine Aussage ist richtig, wenn man nach allem sucht, was 'der' enthält. Will man aber das Wort 'der' finden ist ein Blank nötig, da Du ansonsten auch das Wort 'wieder' findest. Das Blank wird jedoch problematisch, wenn das Wort am Anfang oder Ende des Strings steht.
Beispiel:
'Der dumme Hund' kann mit '% der' nicht gefunden werden.

Deshalb sollte man meiner Meinung nach, solche Entscheidungen dem Anwender überlassen.

Gruss
Xaver

harrybo 19. Dez 2002 14:41

Hi Christian,
mein Fehler. Du sagst definitiv nichts Falsches. Kommt davon, wenn man auf die Schnelle antwortet. Die erste Bedingung sollte Suchbegriff = Titel sein, darf also gar keine Wildcards enthalten - also:
Code:
SELECT * FROM Tabelle WHERE ((StringField LIKE 'der') OR (StringField LIKE '%der %') OR (StringField LIKE '% der%'))
Das ganze kann man dann natürlich noch parametrisieren (prozedur, bzw. Query). Aber warten wir mal ab, was Kuckuckskind dazu meint...

gruß, harrybo

xbu58 19. Dez 2002 15:06

Noch einen Hinweis im Zusammenhang mit LIKE. LIKE besitzt noch einige andere Möglichkeiten für den Ein-/Ausschluss von Rows. Hier ein kurzer Auszug aus der Help vom SQLServer:

Code:
Mit NOT LIKE 'sys%' werden alle Objekte angezeigt, die nicht Systemtabellen sind. Sind insgesamt 32 Objekte vorhanden und LIKE ermittelt 13 dieser Objekte, die dem Muster entsprechen, ermittelt NOT LIKE die 19 Objekte, die dem Muster nicht entsprechen.

Mit einem Muster wie in LIKE '[^s][^y][^s]%' werden möglicherweise nicht immer die gleichen Namen gefunden. Anstelle von 19 Namen werden möglicherweise nur 14 angezeigt, da Namen, die mit s beginnen oder deren zweiter Buchstabe y oder deren dritter Buchstabe s ist, aus dem Resultset ebenso entfernt werden wie die Namen der Systemtabellen. Grund dafür ist die schrittweise Auswertung von Musterzeichenfolgen mit negativen Platzhalterzeichen - es wird Platzhalter für Platzhalter ausgewertet. Wenn der Vergleich an einem beliebigen Punkt der Auswertung fehlschlägt, wird das entsprechende Objekt aus dem Resultset entfernt.
Die gesamte Beschreibung der Funktionalität umfasst ca. 5 Seiten. Ich empfehle deshalb, die Beschreibung für den betreffenden DBServer zu lesen.

Gruss
Xaver

Kuckuckskind 19. Dez 2002 19:54

Zitat:

Zitat von harrybo
Das ganze kann man dann natürlich noch parametrisieren (prozedur, bzw. Query). Aber warten wir mal ab, was Kuckuckskind dazu meint...

:lol:

Hi,

das (
Code:
SELECT * FROM Tabelle WHERE ((StringField LIKE 'der') OR (StringField LIKE '%der %') OR (StringField LIKE '% der%'))
) ist gar keien so schlechte Idee! Ich glaube, das werde ich mal ausprobieren!

Fällt euch vielleicht eine Lösung dazu ein, wie ich einen Titel finden kann, der aus mehreren Einzelwörtern besteht, wenn einzelen Worte aus dem Titel eingegeben wurden?
Bsp.:
Buchtitel "Mein Freund der Baum"
eingegebener Suchstring: "Freund Baum"

bisher habe ich meine Suchabfragen immer so formuliert, dass nur auseinander folgende Wörter gefunden werden konnten.

Achja, ich benutze übrigens Paradox und bei meinem ersten Beitrag habe ich mich mal wieder verschrieben und statt "=" natürlich "LIKE" gemeint :roll:

Gruß Thea

xbu58 19. Dez 2002 20:07

Hallo Thea

Du kannst einfach das WHERE mit einem AND ergänzen und den gewünschten Text suchen
Code:
SELECT * FROM TableName WHERE SearchField LIKE '%Text1%' AND SearchField LIKE '%Text2%'
Berücksichtige aber die schon gemachten Aussagen bezüglich der LIKE-Suche! Wichtig ist, dass OR mit Klammern entsprechen getrent sind
Beispiel:
Code:
WHERE (SField LIKE '% Freund%' OR SField LIKE '%Freund %') AND (SField LIKE '% Baum%' OR SField LIKE '%Baum %)
Eben wie gehabt....

Gruss
Xaver

PS: Musst einfach sehen, dass Du vor lauter Bäumen den Wald nicht mehr siehst oder so etaw...

Kuckuckskind 19. Dez 2002 20:21

Dazu müsste ich den eingegebenen String aber irgendwie aufteilen, nach dme Prinzip

Code:
if irgendeinZeichen vom eingegebenenString =' ' dann
 teile den String in mehrere Teile
suche nach jedem Einzelstring
Gell? Und nun noch ein Code bitte, den Delphi auch versteht :mrgreen:

xbu58 19. Dez 2002 20:46

Na sonst noch Wünsche? Du hast Glück, dass ich heute gut drauf bin.... :dancer:

Also hier ein Beispiel wie ich es löschen würde:

1. Eingabefeld auf eine Form legen. Am besten ein TEdit
2. Button für die Suche ebenfalls auf das Form (hast Du sicher schon)

3. In OnButtonClick folgenden Code einfügen:
Code:
procedure .....
var
  xStr,
  xWord,
  xWhere : string;
  xPos  : integer;
begin
  xWhere := '';
  xStr := Trim(Edit1.Text);
  while xStr <> '' do
  begin
    xPos := Pos(' ', xStr);
    if xPos > 0 then
    begin
      xWord := Trim(Copy(xStr, 1, xPos));
      if xWord <> '' then
      begin
        if xWhere <> '' then
          xWhere := xWhere +' AND SearchField LIKE %'+ xWord + '%'
        else
          xWhere := ' SearchField LIKE %'+ xWord + '%';
      end;
      Delete(xStr, 1, xPos);
      xStr := Trim(xStr);
    end
    else if xStr <> '' then
    begin
      if xWhere <> '' then
        xWhere := xWhere +' AND SearchField LIKE %'+ xWord + '%'
      else
        xWhere := ' SearchField LIKE %'+ xWord + '%';
      xStr := '';
    end;
  end;
  if xWhere <> '' then
  begin
    Query.SQL.Text := 'SELECT * FROM TableName '+
                      'WHERE '+xWhere;
    .... und so weiter...
  end;
end;
Du musst das natürlich noch etwas ergänzen, mit dem was in den vorgängigen Nachrichten so alles gesagt wurde. Will Dir ja nicht gleich das ganze Programm liefern :cat:

Gruss
Xaver

PS: ich verwende x bei lokalen Variablen; hat aber nichts mit meinem Namen zu tun.... :warn:

Kuckuckskind 20. Dez 2002 01:14

Oh, danke schön, fühlte mich jetzt zeitweise etwas überfordert... ich schulde dir einen Glühwein ;)

xbu58 20. Dez 2002 06:52

Bitte gern geschehen, aber wie fühlt man sich nach einem virtuellen Glühwein? Etwa so? :kotz:
Gruss
Xaver

Kuckuckskind 21. Dez 2002 14:03

Nein, dann fühlt man sich so: :hello: :dancer: :dancer2: *g*

Ähm, also, um noch mal zum Programm zurückzukehren:
Es klappt alles perfekt, wenn man nach zwei Suchbegriffen sucht, aber es geht nicht, wenn man nur einen Begriff eingibt! Dann bekommt man alle Datensätze ausgegeben, die in der Tabelle sind. Irgendwie muss man noch eine Überprüfung einbauen, ob sich in dem Suchstring überhaupt ein Leerzeichen befindet und daraus eine if-Bedingung ableiten.

xbu58 21. Dez 2002 14:07

Ok, kannst Du einmal den Code, den Du hinein gehäckt hast hinein kopieren, dann sehe ich in mal an.

Gruss
Xaver

Kuckuckskind 21. Dez 2002 14:27

Also, zu Testzwecken hab ich dafür ein neues Programm geschrieben:

Code:
unit usuche;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, XPMenu, Grids, DBGrids, DB, DBTables;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    DataSource1: TDataSource;
    Query1: TQuery;
    DBGrid1: TDBGrid;
    XPMenu1: TXPMenu;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
 var
  xStr, xWord, xWhere: String;
  xPos: Integer;
begin
 if Edit1.Text = '' then
  ShowMessage('Bitte Suchbegriff eingeben!')
 else begin

 xWhere := '';
 xStr := Trim(Edit1.Text);
 while xStr <> '' do
  begin
   xPos := Pos(' ', xStr);
   if xPos > 0 then
    begin
     xWord := Trim(Copy(xStr, 1, xPos));
     if xWord <> '' then
      begin
       if xWhere <> '' then
        xWhere := xWhere +' AND Titel LIKE "%'+ xWord + '%"'
       else
        xWhere := ' Titel LIKE "%'+ xWord + '%"';
      end;
      Delete(xStr, 1, xPos);
      xStr := Trim(xStr);
    end
   else
    if xStr <> '' then
     begin
      if xWhere <> '' then
       xWhere := xWhere +' AND Titel LIKE "%'+ xWord + '%"'
      else
       xWhere := ' Titel LIKE "%'+ xWord + '%"';
      xStr := '';
     end;
  end;
   if xWhere <> '' then
    begin
     Query1.Close;
     Query1.SQL.Clear;
     Query1.SQL.Text := 'SELECT * FROM buecher WHERE '+xWhere;
     Query1.Open;
    end;
   
end;
end;

end.
Müssen zwar noch ein paar Veränderungen vorgenommen werden, damit der Codein das richtige Programm übernommen werden kann, so müsste es aber trotzdem funktionieren!

xbu58 21. Dez 2002 14:43

Nein brucht keine zusätzliche if-Entscheidung. War mein Fehler. Die zweite Zuweisung an xWhere ist nicht korrekt

Wie es jetzt ist:
Code:
   ......
    end
   else
    if xStr <> '' then
     begin
      if xWhere <> '' then
       xWhere := xWhere +' AND Titel LIKE "%'+ xWord + '%"'
      else
       xWhere := ' Titel LIKE "%'+ xWord + '%"';
      xStr := '';
     end;
  end;
   if xWhere <> '' then
    begin
   ....
Wie es aussehen sollte:

Code:
   ......
    end
   else
    if xStr <> '' then
     begin
      if xWhere <> '' then
       xWhere := xWhere +' AND Titel LIKE "%'+ xStr + '%"'
      else
       xWhere := ' Titel LIKE "%'+ xStr + '%"';
      xStr := '';
     end;
  end;
   if xWhere <> '' then
    begin
   ....
An Stelle von xWord muss natürlich xStr stehen. xWord ist ja in Falle, dass nur ein Wort eingegeben wurde leer!

Übrigens, ich empfehle, dass Du bei der Einrückung darauf achtest, den Code immer um 2 Stellen einzurücken. Ist bei grösseren Programmen sehr hilfreich.
Beispiel:


Code:
procedure ......
var
  xVars....
begin
  if
  begin
  end
  else if ..
  begin
    while ...
    begin
    end;
  end;
end;
So kannst Du mit dem Cursor immer vom begin zu end fahren und weisst sofort, was zusammen gehört.

Gruss
Xaver

Kuckuckskind 21. Dez 2002 14:55

:spin: Danke schön! Wenn das jetzt klappt, bin ich für die nächsten drei Tage nicht mehr ansprechbar ;) (-> dann hab ich nämlich zu tun...)

:xmas:

xbu58 21. Dez 2002 14:58

Na ja, da kann man nur viel Vergnügen wünschen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:35 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz