none
Groß und KLeinschreibung in LIKE ignorieren HOWTO? RRS feed

  • Frage

  • Hallo Forum,

    im MS SQL Server schein es standart zu sein das bei

     select * from testtab where name LIKE '%MUELLER%'

    und

    select * from testtab where name LIKE '%Mueller%'

    die gleichen Records zurück geliefert werden egal wie die Groß und kleinschreibung in der Datenbank ist.

    Sowiet so gut,

    IN Oracle scheint es standart zu sein das Groß und Kleinschreibung beachtet wird.

    Kann ich das SQL Statement irgendwie abändern das die gleichen Records zurückkommen,

    oder muss ich den entsprechenden Parameter für diese Datenbank ändern? Und wie heist der

    Parameter in Oracle dafür?

     

    Gruß und TIA

     

    Michael

     

    Montag, 4. Juli 2011 15:52

Antworten

  • Hallo Michael,

    der SQL Server berücksichtigt den Zeichensatz und die Sortierung des jeweiligen Spalte,
    wobei, wenn nichts anderes vorgeben wird, die Datenbanksortierung bei der Anlage der
    Spalte übernommen wird
    Im allgemeinen ist das Latin1_General_CI_AS, was für Case Insensitive, Accent-Sensitive
    steht, und so Groß- und Kleinschreibung keine Rolle spielt.

    Willst Du die Standardvergleiche ändern, musst Du eine COLLATE Klausel angeben, z. B. Latin1_General_CS_AS.

    Entweder direkt bei der Spaltenanlage, wenn das immer so (wie bei Oracle) sein soll
    oder direkt im Ausdruck:

    -- berücksichtigt Groß-Klein
    WHERE name LIKE '%Mueller%' COLLATE Latin1_General_CS_AS
    -- berücksichtigt Groß-Klein NICHT
    WHERE name LIKE '%Mueller%' COLLATE Latin1_General_CI_AS
    
    Beachte, dass Indizes u. U. nicht verwendet werden -
    wobei das einleitende "%" ohnehin ein Indexkiller sein kann ;-)

    Auch bei Oracle kann man Zeichensatz und Sortierung anpassen, siehe u. a.
    http://www.lessanvaezi.com/collation-in-oracle-using-nls_sort/
    http://stackoverflow.com/questions/507504/accent-and-case-insensitive-collate-equivalent-in-oracle

    Gruß Elmar

    • Als Antwort vorgeschlagen Falk Krahl Dienstag, 5. Juli 2011 09:32
    • Als Antwort markiert Michael Brockhoff Dienstag, 5. Juli 2011 14:36
    Montag, 4. Juli 2011 16:29
    Beantworter

Alle Antworten

  • Hallo Michael,

    der SQL Server berücksichtigt den Zeichensatz und die Sortierung des jeweiligen Spalte,
    wobei, wenn nichts anderes vorgeben wird, die Datenbanksortierung bei der Anlage der
    Spalte übernommen wird
    Im allgemeinen ist das Latin1_General_CI_AS, was für Case Insensitive, Accent-Sensitive
    steht, und so Groß- und Kleinschreibung keine Rolle spielt.

    Willst Du die Standardvergleiche ändern, musst Du eine COLLATE Klausel angeben, z. B. Latin1_General_CS_AS.

    Entweder direkt bei der Spaltenanlage, wenn das immer so (wie bei Oracle) sein soll
    oder direkt im Ausdruck:

    -- berücksichtigt Groß-Klein
    WHERE name LIKE '%Mueller%' COLLATE Latin1_General_CS_AS
    -- berücksichtigt Groß-Klein NICHT
    WHERE name LIKE '%Mueller%' COLLATE Latin1_General_CI_AS
    
    Beachte, dass Indizes u. U. nicht verwendet werden -
    wobei das einleitende "%" ohnehin ein Indexkiller sein kann ;-)

    Auch bei Oracle kann man Zeichensatz und Sortierung anpassen, siehe u. a.
    http://www.lessanvaezi.com/collation-in-oracle-using-nls_sort/
    http://stackoverflow.com/questions/507504/accent-and-case-insensitive-collate-equivalent-in-oracle

    Gruß Elmar

    • Als Antwort vorgeschlagen Falk Krahl Dienstag, 5. Juli 2011 09:32
    • Als Antwort markiert Michael Brockhoff Dienstag, 5. Juli 2011 14:36
    Montag, 4. Juli 2011 16:29
    Beantworter
  • Danke, werde es gleich mal ausprobieren!

     

     

    Dienstag, 5. Juli 2011 09:14
  • Hallo Elmar,

    also die ersten tests gegen eine Oracle datenbank sahen ersteinmal gut aus:

    SELECT *FROM MyTableWHERE NLSSORT(MyField, 'NLS_SORT = Latin_CI') = NLSSORT('BobDillon', 'NLS_SORT = Latin_CI')  funktioniert

    nur mit LIKE kommen keine ergebnisse zurück:

     

    SELECT *FROM MyTableWHERE NLSSORT(MyField, 'NLS_SORT = Latin_CI') LIKE NLSSORT('Bob%', 'NLS_SORT = Latin_CI')

     

    hast du eine Ahnung woran das liegen kann?

     

    Gruß

     

    Michael

     

    Dienstag, 5. Juli 2011 11:49
  • Hallo Michael,

    ich habe mich zwar länger von Oracle ferngehalten. An Deiner Stelle würde ich durcharbeiten:

    5 Linguistic Sorting and String Searching

    dort wird Thema Globalisierung ausführlich behandelt.
    Und auch wenn Oracle (wie üblich) andere Wege geht, so weit ich einschätzen kann,
    ist Gleiches erreichbar wie bem SQL Server.

    Es ist ja nicht so, als ob man vom IBM-MainFrame-Zeitalter nicht wegkommen könnte,
    als die Welt in 26 (Groß-)Buchstaben gefasst wurde ;-)

    Gruß Elmar

    Dienstag, 5. Juli 2011 12:29
    Beantworter
  • Hallo Elmar,

     

    eigentlich sollte es so gehen:

    SQL> ALTER SESSION SET NLS_COMP=LINGUISTIC;
    SQL> ALTER SESSION SET NLS_SORT=BINARY_CI;
    SQL> SELECT ename FROM emp1 WHERE ename LIKE 'McC%e';

    ENAME
    ----------------------
    McCoye
    Mccathye

    Nur bei meiner Oracle  Express Datenbank scheint das nicht zu gehen

    Version im Testeinsatz:

    Oracle Database Express Edition (Oracle Database XE)

     

    Gruß Michael


    Dienstag, 5. Juli 2011 14:36
  • Habe es jetzt einfach so gelöst:

    SELECT *FROM MyTableWHERE UPPER(MyField)  LIKE UPPER ('Bob%')

     

    das passt dann auch für MSSQL und Oracle

     

    Gruß

    Michael

     

    Donnerstag, 7. Juli 2011 12:05
  • Hallo Michael,

    das ist genau das, was ich vermeiden würde -
    und als die schlechteste aller Lösungen ansehe.

    Mit solchen Funktionen "killst" Du nicht nur jede Index-Verwendung,
    sondern verlangst dass Anwender wie zu IBM Lochkartenzeiten arbeiten
    => man könnte gleich alle Daten in Grossbuchstaben eingeben und drucken.

    Ein Grundverständnis über Zeichensätze sollte man heute für Anwendungen
    (nicht nur Datenbanken) erarbeiten, schon gerade weil die Welt immer kleiner wird.
    (Was kommt wohl bei UPPER / LOWER in chinesisch raus?)

    P.S.: Ich hatte leider nicht die Zeit mir eine Oracle Installation anzutun,
    wobei es Dir wenig nützen würde, wenn ich mich da schlauer mache ;-)

    Gruß Elmar

    Donnerstag, 7. Juli 2011 13:28
    Beantworter
  • Hallo Elmar,

    tja ich hätte es ja gerdne so gemacht:

    ALTER SESSION SET NLS_COMP=LINGUISTIC GO
    ALTER SESSION SET NLS_SORT=BINARY_CI GO
    SELECT ename FROM emp1 WHERE ename LIKE 'McC%e' GO

    In nem Testtool hat es dann auch gegen eine 'richtige' Oracle Datenbank funktioniert,

    nur die Anwendung die den SQL String absetzt setzt den so ab:

     

    dataAdapter.Fill(...

     

    und da kann man wohl nicht mehrere SQL Strings hintereinander (auf einen Schlag) absetzen.

    Da die Datensätze nur Deutsch sind und nur varchar und nicht nvarchar (oder wie auch immer das auf Oracle Seite heist).

    Und die Suchabfragen nur ab und zu per Hand vom User abgesetzt werden kann ich mit der Krücke ganz gut leben.

    Nen Pluspunkt von UPPER ist allerdings ganz klar das das gegen beide Datenbanken identisch funktioniert.

     

    Aber der Punkt mit dem Index ist natürlich auch nicht zu verachten.

     

    Der Benutzer selbst bekommt von seiner Eingabe eh nichts mit, ich

    ändern einfach alle seine Eingaben in UPPER, er muss also selbst nicht in Grossbuchstaben die

    Suchanfragen eintippen.

     

    Gruß

    Michael 

    Freitag, 8. Juli 2011 09:27
  • Hallo Michael,

    1.) Die Einstellungen für NLS_COMP, NLS_SORT können nicht nur für eine Sitzung geändert
    werden sondern auch global. Und es wäre grundsätzlich empfehlenswert eine passende
    Einstellung zu wählen - so wie man es beim SQL Server auch beim Setup macht,
    siehe Festlegen und Ändern der Serversortierung

    Das man Oracle etwas mühseliger konfigurieren muss, sollte einen nicht davon abhalten es zu tun.

    Damit dürften 99 % alle Fälle die Einstellungen erledigt sein - denn eine
    abweichende Datenbank- oder gar Spaltensortierung ist nur in Sonderfällen notwendig.

    (Und bei Deinem Vorgehen würde es "knallen", da beim SQL Server eine COLLATION Klausel
    notwendig wird, wenn Spalten unterschiedlicher Sortierung verglichen werden -
    womit das Ganze nicht mehr portabel wäre; und ich vermute, auch Oracle dürfte verwirrt reagieren ;-).

    2.) Sinnvoller wäre die Datenbanksysteme deutlicher zu trennen, so dass Du nicht genötigt bist,
    den kleinsten gemeinsamen Nenner beim SQL zu finden.

    Darauf zu spekulieren, dass man mit DataAdapter.Fill hinkommt, wird über erfahrugsgemäß
    über kurz oder lang nicht funktionieren, wenn die Anweisungen komplexer werden.

    3.) .NET (und Windows) arbeitet seit langem mit Unicode und neue Anwendungen
    ohne zu entwerfen ist IMHO von vorgestern (Windows 95 lässt grüssen ;-)
    (Und Argumente wie Speicherbedarf sind bei Terabyte Platten nicht mehr zu vertreten.)

    4.) Der Anwender bekommt es schon mit, wenn die SUCHE ein unterschiedliches Verhalten zeigt.
    So würde sich z. B. eindeutige Indizes würden sich anders verhalten als die Suche.
    UPPER ist nämlich nicht immer so gleich, wie man meint:

    SELECT CASE WHEN N'Groß' = N'Gross' COLLATE Latin1_General_CI_AS THEN 'Standard Gleich' ELSE 'Standard Ungleich' END,
      CASE WHEN N'Groß' = N'Gross' COLLATE Latin1_General_CS_AS THEN 'Accent Gleich' ELSE 'Accent Ungleich' END,
      CASE WHEN UPPER(N'Groß') = UPPER('Gross') COLLATE Latin1_General_CS_AS THEN 'UPPER Accent Gleich' ELSE 'UPPER Accent Ungleich' END,
      CASE WHEN UPPER(N'Groß') = UPPER('Gross') COLLATE Latin1_General_BIN THEN 'Binär Gleich' ELSE 'Binär Ungleich' END
    
    

    (Und ich hatte mir vor Jahren schon mal krumme Erklärungen eines Softwareherstellers
    dazu anhören müssen - da ging es soweit, das Fehler daraus resultierten).

    5.) Ob Du da mehr Arbeit reinsteckst, ist letztendlich Deine Sache.
    Ich würde aber am Anfang etwas mehr Arbeit reinstecken,
    anstatt später auf ewig dran rumzudoktern (und zu fluchen ;-)

    Gruß Elmar

    Freitag, 8. Juli 2011 10:12
    Beantworter
  • Hallo Elmar,

     

    ersteinmal danke für deine Ausführliche Antwort ;)!

     

    Den Globalen Parameter in der Ini Datei hab ich bis jetzt immer übersehen:

    •As initialization parameters on the server
     
    You can include parameters in the initialization parameter file to specify a default session NLS environment. These settings have no effect on the client side; they control only the server's behavior. For example:
     NLS_TERRITORY = "CZECH REPUBLIC"
    

    damit könnte ich es den DB Admins überlassen, aber man kennt das ja die stellen sich manchmal etwas störrisch an.

     

    Zu den anderen Punkte, gebe ich dir vollkommen recht, nur habe ich den Source der Anwendung die das SQL Script absetzt nicht im Zugriff. Ich muss also mit dem arbeiten was ich habe.

     

    Trotzdem danke!

     

     

    Gruß

    Michael

     

     

    Freitag, 8. Juli 2011 10:34