daplaya9971
Goto Top

SQL-Abfrage Letzter Wert in WHERE Klausel

Hallo,

ich bräuchte mal bitte eure Hilfe.

In unserem Warenwirtschaftssystem sind die Artikelbestände in 3 verschiedenen Tabellen gespeichert.
In der Tabelle "Artikel" ist der Artikelbestand, in der Tabelle "Lager" der Buchungsbestand und in der Tabelle "LagerB" der Lagerbestand. Natürlich sollte in allen 3 Tabellen der Bestand identisch sein. Jedoch gibt es leider trotzdem ab und zu Artikel, wo dies nicht der Fall ist.

Daher hätte ich gerne eine SQL-Abfrage, wo ich mir zu einem bestimmten Artikel die 3 Bestände anzeigen lassen kann.

Ich habe mir bis jetzt das hier gebastelt:

SELECT 
       a.Artikel, a.Artikelnummer, a.Bezeichnung, a.Bestand AS Artikelbestand, b.Bestand AS Buchungsbestand, c.Bestand AS Lagerbestand 
FROM 
       Artikel a 
LEFT JOIN 
       Lager b ON a.Artikel = b.Artikel 
LEFT JOIN 
       LagerB c ON a.Artikel = c.Artikel 
WHERE 
       a.Artikel = '184428' AND c.Ort = '4'  


Das ist an sich schon nicht schlecht. Aber da in der Tabelle "Lager" teilweise viele Werte stehen, je nach Anzahl der Buchungen von dem Artikel, spuckt es mir halt auch soviele Ergebnisse aus:

sql_alle_bestände_nach_artikelid



Ich möchte aber halt, das es mir aus dieser Tabelle nur den Bestand von dem letzten Wert anzeigt. Ich habe es schon mit LAST(Datum) oder MAX(Zaehler) probiert. Aber das funktionierte leider bei mir nicht so wirklich.
Folgende Felder umfasst die Tabelle "Lager":

lager_id184428


Das Feld Zaehler ist eine fortlaufende Zahl in der Positionstabelle von allen Aufträgen. Daher wäre die MAX-Funktion da eigentlich am besten. Oder man nimmt die Zeile mit dem letzten Datum.

Ich hoffe, ich konnte mich verständlich ausdrücken und ich hoffe noch mehr, das ihr mir weiterhelfen könnt.

Content-ID: 3029506581

Url: https://administrator.de/forum/sql-abfrage-letzter-wert-in-where-klausel-3029506581.html

Ausgedruckt am: 27.12.2024 um 05:12 Uhr

ukulele-7
ukulele-7 09.06.2022 aktualisiert um 14:16:37 Uhr
Goto Top
Für dein Problem gibt es mehrere Herangehensweisen die mal besser mal schlechter sind. Ich denke hier wäre es das Beste (und ist generell auch das übersichtlichste), wenn man erstmal nur den aktuellen Lagerbestand betrachtet, also die Tabellen quasi vorfiltert auf aktuell gültige Datensätze. Ich gehe jetzt mal davon aus das der höchste Zähler zu jeder Artikel-ID dem aktuellen Wert entspricht, alle anderen Datensätze sind "historische" Daten. (Oder vertue ich mich da? so ganz sicher bin ich nicht.)
WITH b AS (
SELECT ROW_NUMBER() OVER (PARTITION BY Artikel ORDER BY Zaehler DESC) AS zeile,*
FROM Lager
), c AS (
SELECT ROW_NUMBER() OVER (PARTITION BY Artikel ORDER BY Zaehler DESC) AS zeile,*
FROM LagerB
)
SELECT 
       a.Artikel, a.Artikelnummer, a.Bezeichnung, a.Bestand AS Artikelbestand, b.Bestand AS Buchungsbestand, c.Bestand AS Lagerbestand 
FROM 
       Artikel a 
LEFT JOIN 
       b ON a.Artikel = b.Artikel AND b.zeile = 1
LEFT JOIN 
       c ON a.Artikel = c.Artikel AND c.zeile = 1
WHERE 
       a.Artikel = '184428' AND c.Ort = '4'  
Das müsste eigentlich so schon funktionieren aber sollte natürlich noch sauber ausformuliert werden (zumindest keine *). Eventuell wird auch die Performance schlechter aber das läßt sich eigentlich kaum vermeiden, je nach Datenmenge.
em-pie
em-pie 09.06.2022 aktualisiert um 14:23:40 Uhr
Goto Top
Moin,

als Alternative zu dem Vorschlag des Kollegen @ukulele-7
SELECT TOP 1
  [Artikel] = a.Artikel
  , [Artikelnummer] = a.Artikelnummer
  , [Bezeichnung] = a.Bezeichnung
  , [Artikelbestand] = a.Bestand
  , [Buchungsbestand] = b.Bestand
  , [Lagerbestand] = c.Bestand
FROM Artikel a 
LEFT JOIN Lager b ON a.Artikel = b.Artikel 
LEFT JOIN LagerB c ON a.Artikel = c.Artikel 
WHERE a.Artikel = '184428' AND c.Ort = '4'  
ORDER BY b.UPDATE desc

Gruß
em-pie
ukulele-7
ukulele-7 09.06.2022 um 14:47:43 Uhr
Goto Top
Die Lösung von @em-pie ist noch einfacher und auch gut unter der Voraussetzung das immer genau ein Artikel abgefragt wird. Sobald mehrere Artikel im WHERE-Teil stehen wird es nicht gehen.
em-pie
em-pie 09.06.2022 aktualisiert um 15:18:28 Uhr
Goto Top
Zitat von @ukulele-7:

Die Lösung von @em-pie ist noch einfacher und auch gut unter der Voraussetzung das immer genau ein Artikel abgefragt wird. Sobald mehrere Artikel im WHERE-Teil stehen wird es nicht gehen.

Das könnte man mit einer CTE und Grouping by lösen
with cte_Stock as (
 SELECT artikel, MAX(update) as update
 FROM lager
 GROUP BY artikel
)

SELECT
  [Artikel] = a.Artikel
  , [Artikelnummer] = a.Artikelnummer
  , [Bezeichnung] = a.Bezeichnung
  , [Artikelbestand] = ISNULL(a.Bestand, 0)
  , [Buchungsbestand] = ISNULL(b.Bestand, 0)
  , [Lagerbestand] = ISNULL(c.Bestand, 0)
FROM Artikel a 
LEFT JOIN Lager b ON a.Artikel = b.Artikel 
  and b.ARTIKEL = cte_stock.Artikel 
  and b.UPDATE = cte_stock.Update
LEFT JOIN LagerB c ON a.Artikel = c.Artikel
WHERE a.Artikel = '184428' AND c.Ort = '4'  

Ist aber ungetestet

Gruß
em-pie
DaPlaya9971
DaPlaya9971 09.06.2022 um 16:24:00 Uhr
Goto Top
Zitat von @ukulele-7:

Ich gehe jetzt mal davon aus das der höchste Zähler zu jeder Artikel-ID dem aktuellen Wert entspricht, alle anderen Datensätze sind "historische" Daten. (Oder vertue ich mich da? so ganz sicher bin ich nicht.)


Ja das ist richtig.


Bei der Tabelle Artikel und LagerB gibt es nur jeweils einen Datensatz wegen der WHERE-Klauseln:

WHERE a.Artikel = '184428' (das ist die Artikel-ID)
AND c.Ort = '4' (das ist die ID vom Lager)

Somit müssen die beiden Tabellen nicht weiter gefiltert werden.


Nur bei der Tabelle "Lager" (was der Buchungsbestand ist) müsste man anderweitig den letzten (also aktuellsten) Datensatz filtern anhand des Feldes "Zaehler" oder das aktuellste Datum.


Ich bedanke mich schonmal für eure Antworten und werde morgen mich mal weiter dran setzen.


PS:
Mir fällt auch gerade was anderes ein:

Könnte man die Abfrage so gestalten, das alle Artikel abfragt, ob die 3 Werte gleich sind?
Und sozusagen nur Artikel einblendet, wo die Werte unterschiedlich sind?


Meistens zeigt sich das Problem mit verschiedenen Beständen dahingehend, das unsere Kunden einen Artikel in unserem Onlineshop bestellen (dieser als Verfügbar angezeigt wird), aber in unserem Warenwirtschaftsprogramm in der Artikelbearbeitung der Artikel mit Bestand 0 angezeigt wird.
In der Artikelbearbeitung wird der Bestand aus der Tabelle "Artikel" genommen und für den Onlineshop der Bestand welcher in der Tabelle "Lager" steht.
ukulele-7
ukulele-7 09.06.2022 um 16:40:42 Uhr
Goto Top
Aber natürlich, genau dafür ist SQL geschaffen. Dann würde natürlich die Einschränkung auf einen Artikel das ganze wenig nützlich machen daher lasse ich das hier einfach mal weg.
WITH b AS (
SELECT ROW_NUMBER() OVER (PARTITION BY Artikel ORDER BY Zaehler DESC) AS zeile,*
FROM Lager
)
SELECT 
       a.Artikel, a.Artikelnummer, a.Bezeichnung, a.Bestand AS Artikelbestand, b.Bestand AS Buchungsbestand, c.Bestand AS Lagerbestand 
FROM 
       Artikel a 
LEFT JOIN 
       b ON a.Artikel = b.Artikel AND b.zeile = 1
LEFT JOIN 
       LagerB c ON a.Artikel = c.Artikel AND c.zeile = 1
WHERE 
       c.Ort = '4'  
AND ( isnull(a.Bestand,0) != isnull(b.Bestand,0)
OR isnull(a.Bestand,0) != isnull(c.Bestand,0) )
MadMax
MadMax 09.06.2022 um 18:33:15 Uhr
Goto Top
Moin,

hier wird ja schon feste mit Abfragen hantiert, aber was ist das eigentlich für eine Datenbank, habe ich das übersehen? Ukulele geht offensichtilch von einem SQL-Server aus, em-pie hat sich vornehm zurückgehalten und die Abfrage recht allgemein gehalten.

Und noch eine Frage zum Lagerbestand: Du schreibst, da ist kein filtern nötig, weil es durch die Einschränkung auf den Ort eindeutig ist. Aber wenn es mehrere Lagerorte gibt, müßtest Du nicht dann die Menge aller Lagerorte summieren, bevor Du sie mit den anderen beiden Mengen vergleichst? Oder ist Ort '4' ein Pseudolagerort, der die Summe angibt?

Gruß, Mad Max
Crusher79
Crusher79 09.06.2022 um 23:31:41 Uhr
Goto Top
Zitat von @MadMax:
hier wird ja schon feste mit Abfragen hantiert, aber was ist das eigentlich für eine Datenbank, habe ich das übersehen? Ukulele geht offensichtilch von einem SQL-Server aus, em-pie hat sich vornehm zurückgehalten und die Abfrage recht allgemein gehalten.


Muss ich dir beipflichten. Wobei mir das so bekannt vorkommt. Ist das Pervasive?

Normale SELECT Statements sind kein Problem. CTE etc. würden je nach Ableger ander aussehen, bzw. nicht existent sein. Das solltest du wirklich mal kurz kundtun.

Generell löst das aber dein Problem nicht ganz: Die Werte gehen auseinander, weil Transaktionen nicht sauber abgeschlossen wurden. INSERT oder UPDATE Fehler. Wenn das oft vorkommt wäre die Frage nach dem warum? Wäre alles in einer Transkation müsste es passen, bzw. sauber zurück gerollt werden. Vermute separate Task. Wenn es dann hängen bleibt wird Rest nicht sauber aktualisiert.

Vlt. mal den MA auf die Finger schauen, ob die die Masken Eingaben irgendwo abbrechen können und die Fehlbestände verursachen? Wenn die Software nicht abstürzt ist die Ursache meist eine unsaubere Programmierung.
DaPlaya9971
DaPlaya9971 10.06.2022 um 08:13:09 Uhr
Goto Top
Zitat von @MadMax:
hier wird ja schon feste mit Abfragen hantiert, aber was ist das eigentlich für eine Datenbank, habe ich das übersehen? Ukulele geht offensichtilch von einem SQL-Server aus, em-pie hat sich vornehm zurückgehalten und die Abfrage recht allgemein gehalten.

Es ist eine MariaDB.


Zitat von @MadMax:
Und noch eine Frage zum Lagerbestand: Du schreibst, da ist kein filtern nötig, weil es durch die Einschränkung auf den Ort eindeutig ist. Aber wenn es mehrere Lagerorte gibt, müßtest Du nicht dann die Menge aller Lagerorte summieren, bevor Du sie mit den anderen beiden Mengen vergleichst? Oder ist Ort '4' ein Pseudolagerort, der die Summe angibt?

Bei uns gibt es so gesehen nur ein Lager, da wir keine Außenlager oder ähnliches haben. Also ist im Ort "4" bereits der Gesamtbestand der Artikel


Zitat von @Crusher79:
Vlt. mal den MA auf die Finger schauen, ob die die Masken Eingaben irgendwo abbrechen können und die Fehlbestände verursachen? Wenn die Software nicht abstürzt ist die Ursache meist eine unsaubere Programmierung.

Das kommt relativ selten vor. In unserer Artikeldatenbank befinden sich etwa 98.400 Datensätze.
Unser derzeitige Onlineshop sowie einige unser Programme sind komplett selbst programmiert. Das ist in den vielen Jahren, wie wir diese WaWi bereits nutzen, "historisch gewachsen". Vieles nicht ordentlich, aber geht soweit.
Es würde aber keinen Sinn ergeben, da jetzt noch groß an Arbeit rein zu stecken, da wir bereits daran arbeiten zu einem anderen Warenwirtschaftssystem und einen neuen Onlineshop zu wechseln. Nur wird das anhand der enormen Menge an Daten (Artikel, Kunden, Lieferanten) und Arbeitsabläufe (Wareneingang, Warenausgang) noch eine Weile dauern.
Deswegen will ich einfach nur schauen, ob es in der Datenbank bei den 3 Beständen Differenzen gibt und diese händisch korrigieren.


Ich bin im Bereich SQL nicht sonderlich fit, daher Frage ich hier nach Hilfe.
Meine Berufsausbildung liegt mittlerweile 15 Jahre zurück ;)
ukulele-7
ukulele-7 10.06.2022 um 08:33:52 Uhr
Goto Top
MariaDB kann sowohl CTE als auch ROW_NUMBER(), sollte also laufen. Geht auch ohne CTE durch Subselect, aber nicht ohne ROW_NUMBER() in der Variante.

Die Eingrenzung auf Ort macht aber eigentlich keinen Sinn wenn es nur einen Ort gibt. Nichts desto trotz musst du die Abfrage erstmal testen.
em-pie
em-pie 10.06.2022 um 08:46:49 Uhr
Goto Top
Zitat von @MadMax:

Moin,

hier wird ja schon feste mit Abfragen hantiert, aber was ist das eigentlich für eine Datenbank, habe ich das übersehen? Ukulele geht offensichtilch von einem SQL-Server aus, em-pie hat sich vornehm zurückgehalten und die Abfrage recht allgemein gehalten.
Zweifelsfrei konnte man am ersten Post schon erkennen, dass es ein SQL-Server ist.
Wäre es NoSQL gewesen, sähe das sicherlich auf den Screenshots anders aus face-wink

Fernab kommt hier im Board gefühlt in 80% der Fälle ein MS SQL-Server zum Einsatz. Die Trefferquote ist somit recht hoch, auf anhieb den MS SQL-Dialekt zu treffen.
Beide Statements (der von @ukulele-7 und mir) funktionieren aber mit MySQL/ MariaDB sowie MS SQL.
Bei einer DB2 oder einer Oracle DB sieht das dann wiederum anders aus.
ukulele-7
ukulele-7 10.06.2022 aktualisiert um 10:23:48 Uhr
Goto Top
Postgres nicht vergessen, sonst wird @akretschmer sauer.

Bei Access könnte es Probleme geben, aber nur mit der Syntax. Das Query im WITH.-Teil kann man auch als Subquery schreiben, nur ROW_NUMBER() ist in wenigen SQL-DBs ein Problem.
DaPlaya9971
DaPlaya9971 10.06.2022 aktualisiert um 11:22:32 Uhr
Goto Top
Zitat von @ukulele-7:
Die Eingrenzung auf Ort macht aber eigentlich keinen Sinn wenn es nur einen Ort gibt. Nichts desto trotz musst du die Abfrage erstmal testen.

Naja doch schon. Es gibt noch andere Orte. Aber diese spielen hinsichtlich dieser Artikel keine Rolle.


Ich habe jetzt noch ein wenig gebastelt und habe das Dank eurer Hilfe schonmal hinbekommen, die Bestände zu einem bestimmten Artikel mir anzeigen zu lassen. Ich habe diese Abfrage hier:

SELECT 
   TOP 1 b.Bestand AS Buchungsbestand, a.Bestand AS Artikelbestand, c.Bestand AS Lagerbestand, a.Artikel, a.Artikelnummer, a.Bezeichnung 
FROM 
   Artikel a 
LEFT JOIN 
   Lager b ON a.Artikel = b.Artikel 
LEFT JOIN 
   LagerB c ON a.Artikel = c.Artikel 
WHERE 
   a.Artikelnummer = '55000' AND c.Ort = '4'   
ORDER BY 
   b.Zaehler DESC


art55000


Das schonmal für bestimmte Artikel mir sehr hilfreich.
Werde mich dann nächste Woche mal an die Abfrage setzen, die mir nur die Artikel anzeigt, wo die Bestände verschieden sind.
MadMax
MadMax 10.06.2022 um 18:02:38 Uhr
Goto Top
OK, wenn CTE und row_number gehen, dann bin ich bei ukulele mit seiner Abfrage von gestern, 16.40 Uhr. Mal abgesehen davon, daß beim join auf LagerB "AND c.zeile = 1" weg muß.

Gruß, Mad Max
ukulele-7
ukulele-7 13.06.2022 um 08:27:47 Uhr
Goto Top
Ups ja das ist übrig geblieben.
3310487509
3310487509 03.11.2022, aktualisiert am 07.11.2022 um 13:11:19 Uhr
Goto Top
Wenn Sie Ihre Situation genau betrachten, können Sie sehen, dass Sie einerseits den Vorteil haben, Daten in verschiedenen Tabellen zu halten, andererseits aber auch die Herausforderung haben, solche verstreuten Daten zu durchsuchen.

 SELECT COUNT(*),_topRecord 
    FROM subArticles 
GROUP BY _topRecord?