Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Alphanumerische Werte eingrenzen (ähnlich Between) (https://www.delphipraxis.net/186574-alphanumerische-werte-eingrenzen-aehnlich-between.html)

blawen 13. Sep 2015 20:55

Datenbank: MySQL • Version: 5.6 • Zugriff über: MyDac

Alphanumerische Werte eingrenzen (ähnlich Between)
 
Ich habe zwei Tabellen, in der einen sind Reparaturdaten erfasst und in der anderen die jeweiligen Stammdaten der Produkte.

Nun möchte ich abfragen, ob Geräte eines bestimmten Seriennummern-Bereichs bereits einmal erfasst worden sind.
Der Aufbau der Seriennummer ist pro Produkt zwar identisch, kann aber rein numerisch oder aber alphanumerisch ausfallen (z.B. 123 und B12).

Bei rein numerischen Seriennummer könnte ich zwar mit "Between" den Bereich einengen, dies funktioniert aber bei alphanumerischen Werten nicht.

Also habe ich versucht, mit den üblichen Operatoren zu arbeiten. Allerdings gelingt es mir nicht, die Abfrage so zu gestalten, dass in beiden Fälle korrekte Werte zurück geliefert werden.
Mit Hochkommata's ("") werden keine rein numerischen Werte "gefunden" und ohne kann ich nicht nach alphanumerischen Werten abfragen :-(

Kann mir jemand einen Tipp geben, was ich falsch mache und wie ich die Abfrage gestalten müsste, damit sie korrekte Werte liefert?

Code:
Select * from REPARATUR INNER JOIN MATERIAL)   ON
REPARATUR.MATERIAL_ID  = MATERIAL.MATERIAL_ID AND
MATERIAL.MATERIALNR    = "10012345"           AND
(REPARATUR.SERIENNUMMER >= 1                  AND
 REPARATUR.SERIENNUMMER <= 100)

Dejan Vu 13. Sep 2015 21:05

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Anstatt 'BETWEEN' kannst Du auch 'LIKE' verwenden, sofern das Seriennummernformat das zulässt.

Du solltest angeben, wie die Seriennummern aufgebaut sind.

Perlsau 13. Sep 2015 21:13

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Hier wäre es aus meiner Sicht erst einmal wichtig zu erfahren, wie denn deine Serien-Nummern-Bereiche organisiert sind. Hat z.B. das erste Zeichen eine bestimmte Bedeutung? Oder anders gefragt: Weisen die Serien-Nummern eine einheitliche Gliederung auf? Z.B.: Bedeutet das erste Zeichen B, daß das Ding aus der Abteilung B stammt?

Worauf ich hinaus will: Wenn eine einheitliche Gleiderung der Serien-Nummern existiert, könnte man diese Gliederung irgendwie berechnen?

Zitat:

Zitat von blawen (Beitrag 1315716)
Mit Hochkommata's ("") werden keine rein numerischen Werte "gefunden" und ohne kann ich nicht nach alphanumerischen Werten abfragen :-(

Das habe ich nicht so ganz verstanden: Erstens sind Hochkommatas nicht ", sondern '.
Zweitens liegen die Seriennummern doch stets als String bzw. VarChar vor, müssen also beim Suchen immer in Hochkommatas eingeschlossen sein. Ob der String nun numerisch interpretierbar wäre oder nicht, kümmert die Datenbank eigentlich erstmal nicht.

blawen 13. Sep 2015 21:16

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Zitat:

Zitat von Dejan Vu (Beitrag 1315717)
Anstatt 'BETWEEN' kannst Du auch 'LIKE' verwenden, sofern das Seriennummernformat das zulässt.

Du solltest angeben, wie die Seriennummern aufgebaut sind.

Grundsätzlich geht es um zwei Arten:

- Rein numerisch und fortlaufend (100,101,102,...)
- Beginnend mit einem Buchstaben und danach wiederum mit einem fortlaufenden Zahlenwert (B100, B101, B202,...)
(Der Buchstaben dient als Versionsindex)

Konkret möchte ich z.B. sämtliche Geräte mit der Seriennummer 100 - 200, bzw. B100 - B200 aufgelistet haben.

Funktioniert 'Like' nicht nur bei übereinstimmenden Suchbegriffen?


/Edit
Zitat:

Zitat von blawen (Beitrag 1315716)
Ob der String nun numerisch interpretierbar wäre oder nicht, kümmert die Datenbank eigentlich erstmal nicht.

Angenommen, es existiert ein Gerät mit der Seriennummer '150' in der Datenbank.
Mit der Abfrage
Code:
Select * from REPARATUR INNER JOIN (MATERIAL)  ON
 REPARATUR.MATERIAL_ID = MATERIAL.MATERIAL_ID AND
 MATERIAL.MATERIALNR   = "10012345"          AND
 (REPARATUR.SERIENNUMMER >= '1'               AND
  REPARATUR.SERIENNUMMER <= '200')
wird der Datensatz nicht gefunden (leere Datenmenge), ohne Hochkommata hingegen schon.

/Edit2:
Schreibfehler korrigiert (Wert von 100 auf 200 korrigiert)

Dejan Vu 13. Sep 2015 21:41

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Also '100-200' ginge so (ist aber keine schöne Lösung)
Code:
where Seriennummer like '1??' or Seriennummer='200'
Ich verstehe aber nicht, wieso das nicht mit 'BETWEEN' funktioniert sollte, fällt mir gerade ein. Das ist ja eine totale Ordnung, da die Vergleichsoperastionen vollständig definiert sind. Also, in MSSQL geht das jedenfalls.
Code:
where Seriennummer between '100' and '200'

blawen 13. Sep 2015 22:05

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Zitat:

Zitat von Dejan Vu (Beitrag 1315722)
Also '100-200' ginge so (ist aber keine schöne Lösung)

Bei so engen Bereichen würde es gehen, aber bei grösseren Bereichen unpraktikabel.
Zitat:

Ich verstehe aber nicht, wieso das nicht mit 'BETWEEN' funktioniert sollte, fällt mir gerade ein. Das ist ja eine totale Ordnung, da die Vergleichsoperastionen vollständig definiert sind. Also, in MSSQL geht das jedenfalls.
Bei MySQL funktioniert es (anscheinend) nur mit reinen Zahlenwerten.
Zumindest
Code:
where Seriennummer between 100 and 200
liefert mir eine Datenmenge zurück,
Code:
where Seriennummer between '100' and '200'
hingegen nicht.

jobo 13. Sep 2015 22:42

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Zitat:

Zitat von blawen (Beitrag 1315721)
es existiert ein Gerät mit der Seriennummer '150' in der Datenbank.
Mit der Abfrage
Code:
Select * from REPARATUR INNER JOIN (MATERIAL)  ON
 REPARATUR.MATERIAL_ID = MATERIAL.MATERIAL_ID AND
 MATERIAL.MATERIALNR   = "10012345"          AND
 (REPARATUR.SERIENNUMMER >= '1'               AND
  REPARATUR.SERIENNUMMER <= '100')
wird der Datensatz nicht gefunden (leere Datenmenge), ohne Hochkommata hingegen schon.

Wieso sollte bei <= '100', 150 angezeigt werden?
Weiter unten in den Posts steht da nun 200 und 150 wird trotzdem nicht angezeigt?
Du hast das sicher irgendwo einen Bock drin.

Lass die Daten sortiert ausgeben, frage auf =150 ab. Irgendwas stimmt da nicht.
Wie ist der Typ dieser Spalte definiert?

blawen 13. Sep 2015 23:06

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Zitat:

Zitat von jobo (Beitrag 1315726)
Wieso sollte bei <= '100', 150 angezeigt werden?

Sorry, war ein dummer Tippfehler im Posting (200 wäre der korrekte Wert, habe ich im Posting korrigiert).

Aktuell habe ich es so gelöst, dass zuerst ein 'between' versucht wird. Führt dies zu keinem Ergebnis, mache ich eine neue Abfrage mit logischen Operatoren.
So komme ich zwar zu meinen Daten, aber dies müsste doch sicher einfacher gehen.

Delphi-Quellcode:
// Da Between nur numerische Werte enthalten darf und die logischen Operatoren
// bei rein numerischen Werten wiederum keine Datenmenge zurückliefern, wird
// aktuell dieser Workarround benutzt.
// Da Alphanumerische Werte bei einer between Abfrage zu einer Exception führen,
// wird dies in ein "try-except" verpackt
try
  quSuchen.SQL.Text := 'Select * from REPARATUR INNER JOIN                ' +
                       '(MATERIAL) ON                                     ' +
                       'REPARATUR.MATERIAL_ID  = MATERIAL.MATERIAL_ID AND ' +
                       'MATERIAL.MATERIALNR    = :MaterialNr         AND ' +
                       '(REPARATUR.SERIENNUMMER between :SerNr_Start AND :SerNr_Ende)';

  quSuchen.ParamByName('MATERIALNR').AsString := edMaterialNr.Text;
  quSuchen.ParamByName('SerNr_Start').AsInteger := StrToInt(edSerienNr_Start.Text);
  quSuchen.ParamByName('SerNr_Ende').AsInteger := StrToInt(edSerienNr_Ende.Text);
  quSuchen.Active := True;
except
end;

if quSuchen.RecordCount = 0 
then begin
  try
    quSuchen.SQL.Text := 'Select * from REPARATUR INNER JOIN                ' +
                         '(MATERIAL) ON                                     ' +
                         'REPARATUR.MATERIAL_ID  = MATERIAL.MATERIAL_ID AND ' +
                         'MATERIAL.MATERIALNR    = :MaterialNr         AND ' +
                         '(REPARATUR.SERIENNUMMER >= :SerNr_Start       AND ' +
                         ' REPARATUR.SERIENNUMMER <= :SerNr_Ende)       AND ' +
                         'REPARATUR.DATUM BETWEEN :Datum_Start AND :Datum_Ende';

    quSuchen.ParamByName('MATERIALNR').AsString := edMaterialNr.Text;
    quSuchen.ParamByName('SerNr_Start').AsString := edSerienNr_Start.Text + '%';
    quSuchen.ParamByName('SerNr_Ende').AsString := edSerienNr_Ende.Text + '%';
    quSuchen.ParamByName('DATUM_START').AsDate  := edDatum_Start.Date;
    quSuchen.ParamByName('DATUM_ENDE').AsDate   := edDatum_Ende.Date;
    quSuchen.Active := True;
  except
  end;
end;

BUG 14. Sep 2015 00:44

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Wie sieht es denn mit strcmp aus? Damit sollte sich so etwas doch zusammenbasteln lassen.
Andererseits könntest du überlegen, ob du die Zugehörigkeit zu einem Seriennummernbereich nicht schon in der Datenbank modellieren willst.

Dejan Vu 14. Sep 2015 06:26

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Zitat:

Zitat von blawen (Beitrag 1315725)
Bei so engen Bereichen würde es gehen, aber bei grösseren Bereichen unpraktikabel.

Na nö... Eher bei 'krummen' Bereichen wie '142-379'

Deine Lösung mit '>= and <=' ist doch super, nur haben die '%' Zeichen dort nichts verloren. Das sind Wildcards für die LIKE Suche.

Das ich darauf nicht früher gekommen bin... (also mit '>= AND <=')...:oops:

idefix2 14. Sep 2015 08:22

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Statt eine Exception abzufangen könntest du doch mit trystrtoint überprüfen, ob dein SerNr_Start rein numerisch oder alphanumerisch ist,und entsprechend mit der ersten oder mit der zweiten Abfrageversion weitermachen.

Blup 14. Sep 2015 08:47

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Selbst wenn der Vergleich von Strings unterstützt wird, ist das Ergebnis bei variabler Stellenanzahl für die Abfrage nicht unbedingt hilfreich:

"B1" < "B100" < "B11" < "B2"

Eine allgemein gültige Lösung ist nur durch Trennung des Präfix von der Zählnummer möglich.

Man könnte schon in der Tabelle zwei zusätzliche Spalten dafür anlegen, die Spalte für die vollständige Nummer würde ich aber trotzdem vorsehen:
- "D1" || 20 -> "D120" und "D" || 120 wird ebenfalls "D120", ein eindeutiger Index über die vollständige Artikelnummer verhindert das.
- Eventuell gibt es eine Bildungsvorschrift mit fester Stellenanzahl für den numerischen Teil "D" || 20 -> "D020"

Alternativ berechnet man den numerischen Teil der Nummer zur Laufzeit in einer Funktion oder View.
Nachteil:
- Bildungsvorschriften können sich im Laufe der Zeit ändern, oder es existieren sogar unterschiedliche je Präfix.
- So kann der Index für die Nummer nicht genutzt werden.

Deshalb halte ich die erste Variante für günstiger.

p80286 14. Sep 2015 12:18

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
mal ganz dumm gefragt, warum packst Du eigentlich alle Bedingungen in das JOIN?
U.U bist Du so erfolgreicher:
Code:
Select * 
from REPARATUR JOIN MATERIAL ON (REPARATUR.MATERIAL_ID = MATERIAL.MATERIAL_ID)
Where ganzvielebedingungen......
Einige Datenbanken(/treiber) verschlucken sich an großen JOINs.

Gruß
K-H

baumina 14. Sep 2015 13:13

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Dem stimme ich zu, nur ganz selten macht es Sinn Bedingungen in den Join statt in die Where-Clause zu nehmen. Meine Lösung für ein ähnliches Problem war:

SQL-Code:
WHERE (right(tblfebg.Kennung,4) >= 1000)
AND (right(tblfebg.Kennung,4) < 2000)

frankyboy1974 14. Sep 2015 13:26

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
hallo,

@baumina

kannst du mir bitte für diese Aussage ein Beispiel nennen

Zitat:

Dem stimme ich zu, nur ganz selten macht es Sinn Bedingungen in den Join statt in die Where-Clause zu nehmen
Ich sehe ehrlich gesagt gar keinen Unterschied, ob ich an der Stelle mit Where weiter mache, oder denn Join weiterführe. Aber du wirst mir sicherlich ein gutes Beispiel nennen können, beim dem der Unterschied deutlich wird, wann es Sinn macht und wann nicht.

mfg

baumina 14. Sep 2015 13:40

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Beim INNER JOIN ist es egal, für RIGHT und LEFT JOIN gilt LEFT JOIN and RIGHT JOIN Optimization

p80286 14. Sep 2015 14:56

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Zitat:

Zitat von frankyboy1974 (Beitrag 1315778)
Ich sehe ehrlich gesagt gar keinen Unterschied, ob ich an der Stelle mit Where weiter mache, oder denn Join weiterführe.

Hätte ich bis vor kurzem auch zugestimmt, bis ich einen
Code:
T1 LEFT JOIN T2 ON (T1.ID=T2.ID and T2.Wert=xxx and T2.wert1=yyyy)
hatte, der sich wie ein INNER JOIN verhielt. Ist zwar Oracle aber da sollte es eigentlich auch gehen.

Gruß
K-H

jobo 14. Sep 2015 17:02

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Zitat:

Zitat von frankyboy1974 (Beitrag 1315778)
@baumina

kannst du mir bitte für diese Aussage ein Beispiel nennen

Zitat:

Dem stimme ich zu, nur ganz selten macht es Sinn Bedingungen in den Join statt in die Where-Clause zu nehmen

Ich bin zwar nicht baumina, aber muss dazu auch meinen Senf loswerden.

Ich bin es von "oracle" sql gewohnt, ohne ANSI Join Syntax zu arbeiten, gefällt mir auch viel besser, ist aber tatsächlich wohl nur Gewohnheit.
Im "Oracle" Style schreibt man alles hinter das "where" und ist glücklich. Technisch kann man auch alles in die ANSI Join Notation reinquetschen, also sozusagen das Gegenteil des "Oracle" Style.
Mal abgesehen von den Vorschriften, die es gibt, die sowieso zur Trennung von join und Bedingung bzw. Filter anhalten.
Man nimmt sich einfach ohne Not die Übersicht(lichkeit) und nicht nur sich, auch den Kollegen.
Über die Join Notation formuliert man die Kriterien zur (korrekten) Mengenbildung, die Filter im Where dienen tatsächlich dann nur noch dazu, das Ergebnis auszusieben.
Das sieht vielleicht nach Erbsenzählerei aus, kann einem bei komplexen Abfragen aber durchaus mal den Kopf retten. Es trägt zum Verständnis der Abfrage bei und ist hilfreich bei der Fehlersuche und vielleicht sogar schon bei der Erstellung.

Etwas plastisch wird das vielleicht bei typischen Programmieraufgaben, wo eine Filtermaske implementiert werden muss. Was auch immer der User möchte, den zusammengesetzten Filterausdruck setzt ganz sorgenfrei in die Where Clause, genau da gehört er hin. Die Joinkriterien des Selectstatements bleiben unangetastet.

idefix2 14. Sep 2015 17:51

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Intuitiv hätte ich gemeint, dass so eine Abfrage effizienter abgearbeitet werden kann, wenn einige Bedingungen, die viele Datensätze ausscheiden, schon im join festgelegt werden, weil dann die Ergebnismenge des joins kleiner ist? Was ist daran falsch?

Sir Rufo 14. Sep 2015 18:47

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Zitat:

Zitat von idefix2 (Beitrag 1315804)
Intuitiv hätte ich gemeint, dass so eine Abfrage effizienter abgearbeitet werden kann, wenn einige Bedingungen, die viele Datensätze ausscheiden, schon im join festgelegt werden, weil dann die Ergebnismenge des joins kleiner ist? Was ist daran falsch?

Daran ist erst einmal gar nichts falsch.

Ob das aber wirklich effizienter abgearbeitet wird und wenn, bei welcher Datenmenge und welcher Datenstruktur, hängt sehr stark vom DBMS und dem Optimizer ab.

Man kann pauschal da gar nichts sagen, nur ein konkreter Test kann hier die letztendliche Erkenntnis bringen.

Manchmal gibt es auch recht konkrete Aussagen zu einem konkreten DBMS
https://www.percona.com/blog/2010/04...oin-and-where/

Oder sowas http://stackoverflow.com/questions/1...r-than-a-where

(Ich suche noch einen Link zu einer Seite, auf der unterschiedliche Performance-Tests mit einem MS-SQL Server gemacht wurden, und dort gab es teilweise unterschiedliche Laufzeitverhalten abhänging von der Satzanzahl. Der scheint sich im Moment aber gut zu verstecken)

jobo 14. Sep 2015 20:07

AW: Alphanumerische Werte eingrenzen (ähnlich Between)
 
Zitat:

Zitat von Sir Rufo (Beitrag 1315809)
(Ich suche noch einen Link zu einer Seite, auf der unterschiedliche Performance-Tests mit einem MS-SQL Server gemacht wurden, und dort gab es teilweise unterschiedliche Laufzeitverhalten abhänging von der Satzanzahl. Der scheint sich im Moment aber gut zu verstecken)

Sag Bescheid, wenn Du ihn gefunden hast :)

Zitat:

Ob das aber wirklich effizienter abgearbeitet wird und wenn, bei welcher Datenmenge und welcher Datenstruktur, hängt sehr stark vom DBMS und dem Optimizer ab.
Genau! Und an der Stelle erledigt sich eigentlich jede Fragestellung, die nicht exakt an einem System (Hersteller) einer Version (plus Hardware, Cache Größen, Partitionierung etc. pp) entlang läuft .

Ich hab im Rahmen dieses Threads ein paar Sachen auf Oracle ausprobiert. Ein Feld 80 % mit NULL "gefüllt", mit Index, 9 Mio Datensätze. Sucht man nach einem Wert, dessen Häufigkeit deutlich unter 1% ist, wird der Index verwendet, der nächste Wert liegt bei ca 4% Häufigkeit, da wird dann schon Fulltablescan gemacht. Ich bin überrascht.

Das Problem an Threads wie diesen ist, dass immer wieder bestimmte Regeln für richtig erklärt werden, es aber einfach nicht sind, im schlimmsten Fall nicht mal im Besonderen. Thematisch ein Legendenklassiker. Aktuelle Systeme haben sehr pfiffige Optimizer, denen häufig eine Menge Blödsinn und eine Menge KI angedichtet wird.

Deswegen (auch falls ich mich wiederhole)
Prio 1: Fachlich solide Abfrage schreiben und auf den Optimizer vertrauen.
Prio 2: Doku
Prio 3: Tuning, falls nötig, dann aber besonders gut dokumentieren, warum man so komische Abfragen schreibt/ Indizes erstellt/ ..


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:31 Uhr.

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