Between mit falschem Ergebnis

Themen rund um den praktischen Einsatz von Firebird. Fragen zu SQL, Performance, Datenbankstrukturen, etc.

Moderator: thorben.braun

Antworten
Benutzeravatar
martin.koeditz
Beiträge: 443
Registriert: Sa 31. Mär 2018, 14:35

Hallo zusammen,

vielleicht können wir mit meinem aktuellen Problem das Thema der letzten Tage fortführen.

Ich habe folgende Tabelle:

Code: Alles auswählen

CREATE TABLE KST 
(
  KSTNR        VARCHAR(20) not null,
  BEZEICHNUNG  VARCHAR(200) NOT NULL,
  KSTTYP       SMALLINT DEFAULT 0 NOT NULL,
  CONSTRAINT PK_KST PRIMARY KEY (KSTNR)
);
commit;

INSERT INTO KST VALUES ('1000', 'Kst kleiner', 2);
INSERT INTO KST VALUES ('11000', 'Kst innerhalb', 1);
INSERT INTO KST VALUES ('311000', 'Kst größer', 2);
commit;
Möchte ich nun nur Werte innerhalb von 10000-99999 berücksichtigen, schlägt die Abfrage mit between fehl:

Code: Alles auswählen

select KSTNR, Bezeichnung, 
case when KSTNR between '10000' and '99999' then 'innerhalb' else 'außerhalb' end as Berechnung
from kst
Dies ist das Ergebnis:

Code: Alles auswählen

KSTNR                BEZEICHNUNG          BERECHNUNG
----------------------------------------------------
1000                 Kst kleiner          außerhalb 
11000                Kst innerhalb        innerhalb 
311000               Kst größer           innerhalb 
Die letzte Zeile müsste m.E. ebenfalls außerhalb des Bereichs liegen. Wo ist hier mein Denkfehler?

Gruß
Martin
Martin Köditz
it & synergy GmbH
bfuerchau
Beiträge: 485
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Das Ergebnis ist korrekt, da ja bei Vergleichen Leerzeichen am Ende nicht relevant sind.
D.h. aber, dass das kürze Feld bei einem Vergleich passend zur Läge des Vergleiches mit Leerzeichen aufgefüllt werden. Der Vergleich selber ist ein Stringvergleich.
Somit ist ("_" als Leerzeichen zu verstehen):

"1000_" < "10000" => außerhalb, da x'20' < x'30' ist.

und für den Rest reichen die ersten beiden Stellen:

"11" >= "10" und <= "99" => innerhalb
"31" >= "10" und <= "99" => innerhalb

Es ist immer ein Problem, Zeichenvergleiche wie numerische Vergleiche zu sehen.
Für einen inhaltlichen Vergleich solltest du das Feld auf Int casten und die Vergleiche numerisch angeben. Da wäre 311.000 > 99.999.
Benutzeravatar
martin.koeditz
Beiträge: 443
Registriert: Sa 31. Mär 2018, 14:35

Guten Morgen bfuerchau,

danke für die Klarstellung. Sowas hatte ich mir schon gedacht. Deshalb bin ich auf den Vergleich mittels CHAR_LENGTH() umgestiegen.

Code: Alles auswählen

select KSTNR, Bezeichnung, 
case when CHAR_LENGTH(KSTNR) = 5 then 'innerhalb' else 'außerhalb' end as Berechnung
from kst
Damit bekomme ich auch die korrekten Ergebnisse.

Dank und Gruß
Martin
Martin Köditz
it & synergy GmbH
bfuerchau
Beiträge: 485
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Denke dabei aber auch an die andere Diskussion bzgl CHAR und VARCHAR.
CHAR_LENGTH liefert die Länge des Feldes bei CHAR und nicht die Länge des Inhalts.
Um die Zeichenlänge zu erhalten ist ein Trim trailing erforderlich:

https://firebirdsql.org/refdocs/langref ... ength.html
Antworten