marcel2
Goto Top

MySQL - Kleinster Wert aus mehreren Tabellen

Hallo,

ich habe identische Daten von mehreren Lieferanten in mehreren Tabellen einer MySQL 5 Datenbank. Jetzt muss ich aus allen Tabellen den kleinsten Preis ermitteln.

Meine bisherige Abfrage funktioniert schon soweit.
Mit Hilfe der Funktion Greatest() wird ein Preisaufschlag zu dem Preis "vk_preis" berechnet. Bisher kam der Preis aus der Tabelle db.tb1.vk_preis, jetzt soll es aber der kleinste Preis aus allen Tabellen sein (db.tb1.vk_preis, db.tb2.vk_preis, db.tb3.vk_preis, db.tb4.vk_preis...)

Ich denke das muss ich über min() machen. Aber irgendwie komme ich jetzt nicht drauf, wo ich das da einbauen soll.

Nachfolgend habe ich begonnen die Abfrage anzupassen. Ab Greatest ist noch alles wie es bisher war und es auch funktioniert:


select distinct
db.tb1.id,
db.tb1.anz_tu,
db.tb1.breite,
db.tb1.hersteller,
db.tb1.lager,
db.tb1.vk_preis,
db.tb1.art_nr,

db.rs_preis_calc.von_preis,
db.rs_preis_calc.bis_preis,
db.rs_preis_calc.euro_aufschlag,
db.rs_preis_calc.proz_aufschlag,

db.tb2.art_nr as tb2_art_nr,
db.tb2.lager as tb2_lager,
db.tb2.vk_preis as tb2_vk_preis,
db.tb3.art_nr as tb3_art_nr,
db.tb3.lager as tb3_lager,
db.tb3.vk_preis as tb3_vk_preis,
db.tb4.art_nr as tb4_art_nr,
db.tb4.lager as tb4_lager,
db.tb4.vk_preis as tb4_vk_preis,
db.tb5.art_nr as tb5_art_nr,
db.tb5.lager as tb5_lager,
db.tb5.vk_preis as tb5_vk_preis,
db.tb6.art_nr as tb6_art_nr,
db.tb6.lager as tb6_lager,
db.tb6.vk_preis as tb6_vk_preis,

GREATEST(if (euro_aufschlag>0 and db.tb1.vk_preis > 0 , (db.tb1.vk_preis*1) + euro_aufschlag, 0),
if (proz_aufschlag>0, (
db.tb1.vk_preis*1)+(db.tb1.vk_preis*(proz_aufschlag/100)), 0),
db.tb1.vk_preis) AS akpreis,
GREATEST(if (euro_aufschlag>0 , (db.tb1.vk_preis*1) + euro_aufschlag, 0),
if (proz_aufschlag>0, (
db.tb1.vk_preis*1)+(db.tb1.vk_preis*(proz_aufschlag/100)), 0),
db.tb1.vk_preis) AS vkpreis

from db.rs_preis_calc, db.tb1

left join db.tb2 on db.tb1.art_nr = db.tb2.art_nr
left join db.tb3 on db.tb1.art_nr = db.tb3.art_nr
left join db.tb4 on db.tb1.art_nr = db.tb4.art_nr
left join db.tb5 on db.tb1.art_nr = db.tb5.art_nr
left join db.tb6 on db.tb1.art_nr = db.tb6.art_nr

where ((db.tb1.art_nr is not null) and (
db.tb1.vk_preis > von_preis) and (
db.tb1.vk_preis <= bis_preis) and (
999999 = db.rs_preis_calc.id) and (
0 = db.rs_preis_calc.preisgruppe)and (
db.tb1.anz_tu = '120') and (
db.tb1.breite = '2155'))

order by
db.tb1.hersteller,
db.tb1.breite


Die Stellen ala "db.tb2.vk_preis as tb2_vk_preis," habe ich jetzt schon für die Preisermittlung eingefügt. Weiter komme ich jetzt nicht.

Die Frage ist nun, wie bekomme ich den geringsten Preis aus allen Tabellen und zwar so, das auf diesen noch der Aufschlag addiert werden.

Hat jemand einen Tipp für mich?

Vielen Dank schon mal und die besten Grüße

Marcel

Content-ID: 86341

Url: https://administrator.de/contentid/86341

Ausgedruckt am: 22.11.2024 um 21:11 Uhr

filippg
filippg 24.04.2008 um 20:16:47 Uhr
Goto Top
Hallo,

ich kenne mich mit MySQL nicht wirklich aus. Aber unter MSSQL würde ich eine Stored Procedure erstellen, die aus jeder Tabelle den kleinsten Wert auswählen und in temporäre Tabelle einführt. Danach dann halt aus der den kleinsten auswählen...

Wobei... SELECT min(preis) FROM (Select min(preis) From a UNION Select min(preis) FROM b ....) sollte eigentlich passen und auch nicht wirklich unelegant sein.

Gruß

Filipp
Marcel2
Marcel2 25.04.2008 um 09:05:07 Uhr
Goto Top
Hallo Filipp,

danke für Deine Antwort.

Wobei... SELECT min(preis) FROM (Select
min(preis) From a UNION Select min(preis)
FROM b ....) sollte eigentlich passen und
auch nicht wirklich unelegant sein.

Sehe ich das richtig, das ich auf diese Art den kleinsten Wert aus JEDER Tabelle bekomme?
Wenn ja, darum geht es mir nicht. Ich brauche den kleinsten Wert aus ALLEN Tabellen.
Also aus z.B. 6 Tabellen wird der Preis ausgelesen, davon brauche ich nun die Tabelle mit dem niedrigsten Preis und dann muss ich noch aus dieser Tabelle die id und den Lagerbestand auslesen.

Um diese "Kleinigkeit" soll die obige Abfrage erweitert werden.

Gerne nehme ich weitere Tipps entgegen.

Danke + Gruß

Marcel
filippg
filippg 25.04.2008 um 20:05:43 Uhr
Goto Top
Hallo,

wie wär's denn mit Ausprobieren?

Eigentlich sollte das Statement nur einen Werte zurückgeben. Erst werden aus jeder Tabelle der jeweils kleinste Werte genommen, diese werden über UNION zusammengefügt, und dann wird aus dieser Menge der wiederum kleinste genommen.

Gruß

Filipp
Marcel2
Marcel2 26.04.2008 um 18:32:19 Uhr
Goto Top
Hallo Filipp,

sorry, ich habe mir Deinen Vorschlag noch mal etwas genauer angesehen und auch bezüglich Union und Sub Select recherchiert. Hatte Deinen Vorschlag einfach nicht richtig verstanden.
wie wär's denn mit Ausprobieren?
Würde ich wirklich sehr gerne, aber noch habe ich etwas Probleme mit der Umsetzung. Wie bekomme ich das in mein obiges Beispiel eingebaut?

Ist das folgende vom Ansatz her richtig und wie geht es weiter?

(
select distinct
...(wie oben)...
min(db.tb1.vk_preis),
...(wie oben bis where())...
)
UNION
(
Select ...wie geht es hier weiter?...
)

order by
db.tb1.hersteller,
db.tb1.breite

Ich bräuchte noch mal einen kleinen Schubs, denke dann komme ich weiter.

Vielen Dank und eine schönes Wochenende wünscht Dir

Marcel
Biber
Biber 03.05.2008 um 18:42:17 Uhr
Goto Top
Moin Marcel.

die Struktur Deiner Tabellen (und wie es soweit kommen konnte) ist mir etwas unklar.

Wenn ich es richtig lese, gibt es EINE Tabelle tbl, in der sich alle denkbaren Artikel
  • sowohl mit den Stammdaten-Attribute wie Länge, Breite, Höhe, Gewicht etc
  • als auch den Lager/Bestandsinfo
  • als auch den Preis/Zuschlags/Kalkulationsdaten befinden
  • und die Artikel-ID gilt genauso wie die Stammdaten-Attribute datenbankweit in weiteren x Tabellen????

Ich hoffe, ich habe das ganz falsch verstanden, aber dann schildere doch bitte nochmal den Sachverhalt bzw. die (grobe) Struktur der Tabellen.
Insbesondere ob diese "tbl" wirklich alle Artikel enthält oder ob es auch sein kann, dass es Artikel 4711 nur in tbl2 oder tbl4 gibt und nicht in "tbl".

Grüße
Biber
Marcel2
Marcel2 03.05.2008 um 19:20:33 Uhr
Goto Top
Hallo Biber,

danke für Deinen Beitrag.

Also es gibt tb1, tb2, tb3...
Diese Tabellen erhalten Artikel mit einer eindeutigen ID. Es kann durchaus sein, das nicht in allen Tabellen alle Artikel vorhanden sind. Alle Tabellen haben aber den gleichen Aufbau. Es sind darin alle Daten der Artikel, einschließlich Preis und Lagerbestand enthalten.

Die Daten für die Preiskalkualtion sind in einer eigenen Tabelle und können nach Preis gestaffelt angelegt sein. Also z.B. 0-29 € - 5 € Aufschlag, 30-49 € - 8 € Aufschlag usw.

Es geht darum aus allen (Artikel-) Tabellen den kleinsten Wert des oder der gesuchten Artikel und den dazugehörigen Lagerbestand zu bekommen (und gleichzeitig natürlich den Preis zu berechnen) Die Preisberechnung funktioniert so wie oben dargestellt. Mein Problem ist den kleinste Preis zu bekommen

Wenn ich mich jetzt auf dieses Problem konzentriere dann erhalte ich mit der folgenden Abfrage die Preise aus allen Tabellen. Aber wie bekomme ich daraus den kleinsten Wert ermittelt?

SELECT tb1.breite, tb1.vk_preis, tb2.vk_preis, tb3.vk_preis
FROM db.tb1 AS tb1
LEFT JOIN db.tb2 AS tb2 ON tb1.id = tb2.id
LEFT JOIN db.tb3 AS tb3 ON tb1.id = tb3.id
where tb1.breite = 123

Ich muss quasi den kleinsten Wert aus tb1.vk_preis, tb2.vk_preis und tb3.vk_preis bekommen.
Hast Du eine Ahnung wie das geht?

Ich hoffe die Informationen sind jetzt ausreichend und bedanke für mich im voraus für jeden Tipp.

Gruß Marcel
Biber
Biber 03.05.2008 um 20:24:46 Uhr
Goto Top
Moin Marcel,

IMHO ist Dein oben gepostetes Statement fachlich falsch, wenn sich nicht unbedingt alle Artikel(-IDs) in der tbl1 befinden müssen.

Ich würde eher mit einem UNION ALL ansetzen, wie schon filippg geschrieben hat.
In dem Union sollten alle Felder enthalten sein, die Du für Anzeige, weitere Berechnungen oder die WHERE-Klausel brauchst. Sowie ein weiteres Feld, das Dir den Quelltabellennamen angibt.

Also sinngemäß:
SELECT First( allTb.Id) , min(allTb.VK_preis), First(AllTb.QuellTab)
FROM
( Select  tb1.id, tb1.breite, tb1.vk_preis, "TB1" as QuellTab from tb1  
UNION All
Select  tb2.id, tb2.breite, tb2.vk_preis, "TB2" from tb2  
Union all
Select  tb3.id, tb3.breite, tb3.vk_preis, "TB3" from tb3  
) as AllTb
Where Alltb.breite = 123;

Grüße
Biber
Marcel2
Marcel2 04.05.2008 um 00:42:24 Uhr
Goto Top
Hallo Biber,

Tausend Dank für die Mühe die Du Dir gemacht hast.
Das sieht sehr viel versprechend aus. Auch wenn ich es noch nicht komplett verstehe.

Genau deshalb kann ich auch nicht erkennen, was die Ursache der folgenden Fehlermeldung ist:

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(allTb.ean_nr) , min(allTb.vk_preis), First(allTb.QuellTab)
FROM
(Select tb1.' at line 1

Diese Fehlermeldung wurde mit dem folgenden Code erzeugt:

SELECT First(allTb.id) , min(allTb.vk_preis), First(allTb.QuellTab)
FROM
(Select tb1.id, tb1.breite, tb1.vk_preis, "TB1" as QuellTab from datenbank.tabelle1 as tb1
Union all
Select tb2.id, tb2.breite, tb2.vk_preis, "TB2" from datenbank.tabelle2 as tb2
Union all
Select tb3.id, tb3.breite, tb3.vk_preis, "TB3" from datenbank.tabelle3 as tb3
) as allTb
Where allTb.breite = 123;

Was kann daran falsch sein?

Nochmals vielen Dank

Grüße Marcel
filippg
filippg 04.05.2008 um 02:21:58 Uhr
Goto Top
Hallo,

ich hatte da gleich in meinem Ansatz einen Fehler, bin ich gestern zufällig auch drauf gestoßen:
Ein "Select ... FROM (Select...)" ist (zumindest in MS SQL) nicht zulässig. Würde auch zu deiner Fehlermeldung passen.
Ich habe mir dann beholfen, indem ich aus dem inneren Select (also hier die ganzen UNIONs) ein View gemacht habe, auf den kann ich auch wieder ein Select anwenden. Hat mich ein wenig gewundert, ist glaube ich letztlich auch lediglich eine Syntax-Frage, und nicht eine Problem fehlender Funktionalität.

Gruß

Filipp
Biber
Biber 04.05.2008 um 13:52:00 Uhr
Goto Top
Moin Marcel und filippg,

hätte ich vielleicht dazuschreiben müssen, dass ich nichts an einem (MySQL-)Server getestet habe. Und ich denke, dass fillipg mit seiner Analyse Recht hat.

Also pack das innere Select in einen eigenen VIEW:
 CREATE VIEW AllTb (ArtID, Breite, VK_Preis, QuellTab, Anz_tu, Lager)  AS
(Select tb1.id, tb1.breite, tb1.vk_preis, "TB1" as QuellTab , tb1.anz_tu,  tb1.Lager from datenbank.tabelle1 as tb1  
Union all
Select tb2.id, tb2.breite, tb2.vk_preis, "TB2" , tb2.anz_tu,  tb2.Lager from datenbank.tabelle2 as tb2  
Union all
Select tb3.id, tb3.breite, tb3.vk_preis, "TB3" , tb3.anz_tu,  tb3.Lager from datenbank.tabelle3 as tb3  
) 

Ich habe hier den möglichen VIEW noch um ein, zwei Felder erweitert, die vielleicht als mögliche Kriterien sinnvoll sein könnten (Anz_Tu, Lager..).

Im Prinzip könnten alle Tabellenfelder in den VIEW, die in allen Tbx-Tabellen vorhanden sind.
Nur.... eigentlich erscheint es mir zunehmend fragwürdiger, welche Existenzberechtigung diese vielen Tabellen gleichen Aufbaus überhaupt haben.
Eine Tabelle (ggf. mit einem Zusatzfeld "QuellTab" oder "Lieferant" oder was immer fachlich diese TBs unterschiedlich macht wäre sinnvoller.

Anyhow, erstmal ausgehend von dem, was wir jetzt haben wäre der zweite Schritt:
SELECT First(ArtId) , min(VK_preis), First(QuellTab)
FROM AllTB
Where Alltb.Breite = 123
... wobei, fällt mir grad auf, dieses Statement das falsche Ergebnis liefern dürfte, falls in mehreren QuellTabs der gleiche "minimale" Preis steht.
Na gut, machen wir im nächsten Step - probier bitte erstmal diesen Zwischenschritt.

Grüße
Biber
Marcel2
Marcel2 04.05.2008 um 21:02:15 Uhr
Goto Top
Hallo Biber,

Also pack das innere Select in einen eigenen
VIEW:
 CREATE VIEW AllTb (ArtID,
> Breite, VK_Preis, QuellTab, Anz_tu, Lager) 
> AS
> (Select tb1.id, tb1.breite, tb1.vk_preis, "TB1" as QuellTab , tb1.anz_tu,  tb1.Lager from datenbank.tabelle1 as tb1  
> Union all
> Select tb2.id, tb2.breite, tb2.vk_preis, "TB2" , tb2.anz_tu,  tb2.Lager from datenbank.tabelle2 as tb2  
> Union all
> Select tb3.id, tb3.breite, tb3.vk_preis, "TB3" , tb3.anz_tu,  tb3.Lager from datenbank.tabelle3 as tb3  
> ) 
> 

Das habe ich gemacht, aber bekomme leider immer noch eine Fehlermeldung:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Union all
(Select tb2.id, tb2.breite, tb2.vk_preis, "TB2" from datenbank.' at line 4

Eine Frage hierzu: Was genau bewirkt eigentlich "TB1", "TB2" und "TB3" in den Selects?
Ich habe hier den möglichen VIEW noch um ein, zwei Felder erweitert, die vielleicht als mögliche Kriterien sinnvoll sein könnten (Anz_Tu, Lager..).

Im Prinzip könnten alle Tabellenfelder in den VIEW, die in allen Tbx-Tabellen vorhanden sind.
Das ist Super das Du diese Möglichkeiten gleich mit berücksichtigt hast. Werde ich auf jeden Fall brauchen können.
Nur.... eigentlich erscheint es mir zunehmend fragwürdiger, welche Existenzberechtigung diese vielen
Tabellen gleichen Aufbaus überhaupt haben. Eine Tabelle (ggf. mit einem Zusatzfeld "QuellTab" oder "Lieferant" oder was immer fachlich
diese TBs unterschiedlich macht wäre sinnvoller.
Ich habe lange überlegt und bin bei allen Nachteilen zu dem Schluss gekommen, das es die beste und vor allem sicherste Lösung ist, mit mehreren Tabellen zu arbeiten.
Es ist nämlich so, das von verschiedenen Usern Datenimporte in die Datenbank vorgenommen werden können. Ich möchte mit der Verteilung auf mehrere Tabellen vermeiden, das ein User durch einen fehlerhaften Import das gesamte System zum erliegen bringen kann.
Anyhow, erstmal ausgehend von dem, was wir jetzt haben wäre der zweite Schritt:
SELECT First(ArtId), min(VK_preis), First(QuellTab)
> FROM AllTB
> Where Alltb.Breite = 123
> 
Wie schon weiter oben gesagt, es kommt leider immer noch eine Fehlermeldung. Ich kann den Fehler leider nicht erkennen.
... wobei, fällt mir grad auf, dieses Statement das falsche Ergebnis liefern dürfte, falls in mehreren QuellTabs der
gleiche "minimale" Preis steht. Na gut, machen wir im nächsten Step - probier bitte erstmal diesen Zwischenschritt.
OK, das werden wir dann auch noch abstellen können. Sobald das andere erst mal läuft. Hoffe Du bleibst bis da hin an Board.

Vielen Dank für Deine Mühe

Grüße Marcel
filippg
filippg 04.05.2008 um 21:35:03 Uhr
Goto Top
Mein Gott, jetzt stell dich halt nicht so an. Wie du sicher schon festgestellt hast besteht das ganze Statement aus mehreren Komponenten. Probiere halt mal eins von den Selects alleine. Dann mal zwei mit Union, dann... manchmal muss man sich an den Fehler halt rantasten.

Das "datenbank.tabelle1 as tb1" legt eine Alias fest, danach soll "tabelle1" auch unter "tb1" ansprechbar sein. Sonst müsste es davor auch "Select tabelle1.id, tabelle1.breite,..." statt "Select tb1.id, tb1.breite, ..." heißen. Ich könnte mir auch vorstellen, dass hier der Fehler liegt. Wenn man einen Alais für Tabellen festlegt muss man das "AS" glaube ich weglassen, dass ist nur für Aliase für Spalten.

Gruß

Filipp
Biber
Biber 04.05.2008 um 21:45:27 Uhr
Goto Top
@Marcel
... und wie Filipp schon geschrieben hat, ist es am ehesten durch Probieren zu lösen.
Da ich hier im Moment auch kein mySQL im Zugriff habe, bleibt mir auch nur Raten oder Suchmaschine - Ausprobieren entfällt.

Was eventuell außer dem "AS" oder "nicht AS"-Tabellenname sein kann ist, dass die Inhalte "TB1","TB2"... in einfache statt in doppelte Anführungszeichen gehören.
Eine Frage hierzu: Was genau bewirkt eigentlich "TB1", "TB2" und "TB3" in den Selects?
Damit will ich nur ein künstliches Feld in dem View haben, aus dem ich erkennen kann, aus welcher Ursprungstabelle der gefundene Artikel stammt.

Grüße
Biber