Hilfe bei Datenbank View
Hallo zusammen,
ich habe an die Datenbank Profis eine kurze Frage, ob so etwas überhaupt denkbar und möglich ist.
Folgendes Szenario:
ich habe drei Tabellen in einer MySQL Datenbank:
1. tAuftrag
2. tArtikel
3. tLocation
4. tauftragartikel
In der tAuftrag habe ich z.B.:
auftragsnr | status | kundennr
tArtikel:
artikelnr | artikel| beschreibung
tLocation:
locationnr | name | plz |
tAuftragartikel:
ID | auftragsnr | artikelnr | menge
Nun möchte ich in einer View gerne eine Ausgabe haben, dass in einer Zeile der Auftrag + die Artikel zum Auftrag ausgegeben werden.
Hier gilt es zu sagen, dass Maximal 4 Artikel je Auftrag möglich sein können.
Wenn ich es nun z.B. so Abfrage:
Bekomme ich natürlich z.B. zwei Zeilen, wenn der Kunde zwei Artikel in der Tabelle "tAuftragartikel" hat (Siehe Anhang):
Jetzt die Frage ist es möglich, dass ich die View so aufbaue:
auftragsnr2 | leistungsdatum | full | artikel 1 | aritkel 2 | artikel 3 | artikel4
Und somit falls es mehrere Artikel in der Tabelle gibt, diese in einer Zeile dargestellt werden?
Ich hoffe es war irgendwie verständlich erklärt...
Danke euch für die Hilfe.
Grüße
Phil
ich habe an die Datenbank Profis eine kurze Frage, ob so etwas überhaupt denkbar und möglich ist.
Folgendes Szenario:
ich habe drei Tabellen in einer MySQL Datenbank:
1. tAuftrag
2. tArtikel
3. tLocation
4. tauftragartikel
In der tAuftrag habe ich z.B.:
auftragsnr | status | kundennr
tArtikel:
artikelnr | artikel| beschreibung
tLocation:
locationnr | name | plz |
tAuftragartikel:
ID | auftragsnr | artikelnr | menge
Nun möchte ich in einer View gerne eine Ausgabe haben, dass in einer Zeile der Auftrag + die Artikel zum Auftrag ausgegeben werden.
Hier gilt es zu sagen, dass Maximal 4 Artikel je Auftrag möglich sein können.
Wenn ich es nun z.B. so Abfrage:
select
`tauftrag`.`auftragsnr2` AS `auftragsnr2`,
`tauftrag`.`leistungsdatum` AS `leistungsdatum`,
`tauftrag`.`full` AS `full`,
`tartikel`.`artikel` AS `artikel`,
from (((`tauftrag`
join `tauftragartikel` on
(`tauftrag`.`auftragsnr` = `tauftragartikel`.`auftragsnr`))
join `tartikel` on
(`tauftragartikel`.`artikelnr` = `tartikel`.`artikelnr`))
join `tlocation` on
(`tauftrag`.`locationnr` = `tlocation`.`locationnr`))
Bekomme ich natürlich z.B. zwei Zeilen, wenn der Kunde zwei Artikel in der Tabelle "tAuftragartikel" hat (Siehe Anhang):
Jetzt die Frage ist es möglich, dass ich die View so aufbaue:
auftragsnr2 | leistungsdatum | full | artikel 1 | aritkel 2 | artikel 3 | artikel4
Und somit falls es mehrere Artikel in der Tabelle gibt, diese in einer Zeile dargestellt werden?
Ich hoffe es war irgendwie verständlich erklärt...
Danke euch für die Hilfe.
Grüße
Phil
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 1212900080
Url: https://administrator.de/contentid/1212900080
Ausgedruckt am: 04.12.2024 um 08:12 Uhr
29 Kommentare
Neuester Kommentar
PIVOT und ich wir werden wohl keine Freunde jedenfalls vertue ich mich da immer. Ist aber ansich nicht so kompliziert. Die Ausgangstabelle hast du eigentlich schon mit deinem Select. Hier mal ein Beispiel:
https://codingsight.com/pivot-tables-in-mysql/
https://codingsight.com/pivot-tables-in-mysql/
Vielleicht ist es auch einfacher passend zu joinen. Sind die 4 Artikel immer gleich oder in welchem Zusammenhang stehen die? Ich muss ja irgendwie eine Zuordnung zur Spalte vorgeben. Gibt es da eine sinnvolle Sortierung? Ich glaube MySQL unterstützt mittlerweile ROW_NUMBER() und CTE. Guck mal ob bei dir
WITH t1 AS (
select
ROW_NUMBER() OVER (PARTITION BY `tauftrag`.`auftragsnr2` ORDER BY `tartikel`.`leistungsdatum`,`tartikel`.`artikel`) AS zeile,
`tauftrag`.`auftragsnr2` AS `auftragsnr2`,
`tauftrag`.`leistungsdatum` AS `leistungsdatum`,
`tauftrag`.`full` AS `full`,
`tartikel`.`artikel` AS `artikel`,
from (((`tauftrag`
join `tauftragartikel` on
(`tauftrag`.`auftragsnr` = `tauftragartikel`.`auftragsnr`))
join `tartikel` on
(`tauftragartikel`.`artikelnr` = `tartikel`.`artikelnr`))
join `tlocation` on
(`tauftrag`.`locationnr` = `tlocation`.`locationnr`))
)
SELECT t1.*,t2.`artikel`,t3.`artikel`,t4.`artikel`
FROM t1
LEFT JOIN t1 t2
ON t1.`auftragsnr2` = t2.`auftragsnr2`
AND t2.zeile = 2
LEFT JOIN t1 t3
ON t1.`auftragsnr2` = t3.`auftragsnr2`
AND t3.zeile = 3
LEFT JOIN t1 t4
ON t1.`auftragsnr2` = t4.`auftragsnr2`
AND t4.zeile = 4
WHERE t1.zeile = 1
Zitat von @Gerber:
Dann gibt es eben die Hilfstabelle, um die Benötigten Artikel (maximal 4 aus der tArtikel) einem Auftrag zuzuordnen.
Ich meinte gibt es eine Information wie z.B. Artikel 1,2,3 oder 4 oder gibt es einfach nur 4 Einträge, Reihenfolge egal?Dann gibt es eben die Hilfstabelle, um die Benötigten Artikel (maximal 4 aus der tArtikel) einem Auftrag zuzuordnen.
Ich weiß MySQL kann das nicht gut aber Fehlermeldung?
Funktioniert nur der Teil Zeile 2 bis 15?
Hallo Phil,
versuche mal:
Das mit den Tabellenalias und ohne die Hochkomma überall sollte MySQL auch verstehen.
Schwachpunkt ist natürlich die Unterabfrage mit dem row_number drin, wenn das der Optimizer nicht ordentlich löst, dann kannst Du da ein Zeitproblem kriegen. Um das zu umgehen bräuchtet Ihr eine Positionsnummer bei den Auftragartikeln (gleiches Problem wie oben bei ukulele, da heißt das zeile).
Gruß, Mad Max
versuche mal:
select a.auftragsnr, a.leistungsdatum, a.kundennr, l.name, l.plz,
max (case p.position when 1 then ar.artikel end) as artikel1,
max (case p.position when 2 then ar.artikel end) as artikel2,
max (case p.position when 3 then ar.artikel end) as artikel3,
max (case p.position when 4 then ar.artikel end) as artikel4
from tAuftrag a
join (select row_number () over w as position, * from tAuftragartikel window w as (partition by auftragsnr order by ID)) p on p.auftragsnr = a.auftragsnr
join tArtikel ar on ar.artikelnr = p.artikelnr
join tLocation l on l.locationnr = a.locationnr
group by a.auftragsnr, a.leistungsdatum, a.kundennr, l.name, l.plz
Das mit den Tabellenalias und ohne die Hochkomma überall sollte MySQL auch verstehen.
Schwachpunkt ist natürlich die Unterabfrage mit dem row_number drin, wenn das der Optimizer nicht ordentlich löst, dann kannst Du da ein Zeitproblem kriegen. Um das zu umgehen bräuchtet Ihr eine Positionsnummer bei den Auftragartikeln (gleiches Problem wie oben bei ukulele, da heißt das zeile).
Gruß, Mad Max
Zitat von @Gerber:
@StefanKittel:
Danke dir für die Antwort.
Ich arbeite dann mit PHP und Javascript. Aber im PHP greife ich eben auf die Views zu.
@StefanKittel:
Danke dir für die Antwort.
Ich arbeite dann mit PHP und Javascript. Aber im PHP greife ich eben auf die Views zu.
Ne "einfacher" aber weniger elegant.
Hole Recordset mit Aufträgen ohne Artikel
For Each mit Recordset
{
$ArtitelText = "";
Hole Recordset mit Artikel für diesen einen Auftrag
For Each mit Recordset
{
$ArtitelText .= $row['ArtikelName'] . ", ";
}
Ausgabe dieses Auftrages mit dem String $ArtitelText
}
Vor allem nutzt du MariaDB, nicht MySQL. Auch wenn die sich ähnlich sind sollte man da genau sein. MariaDB unterstützt ROW_NUMBER() ab Version 10.2:
https://mariadb.com/kb/en/row_number/#:~:text=ROW_NUMBER%20%28%29%20was% ....
Ich habe deinen Code genommen und nur um ROW_NUMBER() ergänzt, deinen Code aber nicht geprüft. Der Fehler steckt aber genau da, was die Fehlermeldung auch sagt: Zeile 7 ist die letzte Zeile des Selects und schließt mit einem Komma ab, dann kommt FROM. Das ist natürlich falsch
Zeile 7 ist korrigiert. Ich nutze allerdings MS SQL Management Studio zur Syntaxprüfung und das mag die Hochstriche eh nicht, wer weiß vielleicht sind noch mehr Fehler drin.
https://mariadb.com/kb/en/row_number/#:~:text=ROW_NUMBER%20%28%29%20was% ....
Ich habe deinen Code genommen und nur um ROW_NUMBER() ergänzt, deinen Code aber nicht geprüft. Der Fehler steckt aber genau da, was die Fehlermeldung auch sagt: Zeile 7 ist die letzte Zeile des Selects und schließt mit einem Komma ab, dann kommt FROM. Das ist natürlich falsch
WITH t1 AS (
select
ROW_NUMBER() OVER (PARTITION BY `tauftrag`.`auftragsnr2` ORDER BY `tartikel`.`leistungsdatum`,`tartikel`.`artikel`) AS zeile,
`tauftrag`.`auftragsnr2` AS `auftragsnr2`,
`tauftrag`.`leistungsdatum` AS `leistungsdatum`,
`tauftrag`.`full` AS `full`,
`tartikel`.`artikel` AS `artikel`
from (((`tauftrag`
join `tauftragartikel` on
(`tauftrag`.`auftragsnr` = `tauftragartikel`.`auftragsnr`))
join `tartikel` on
(`tauftragartikel`.`artikelnr` = `tartikel`.`artikelnr`))
join `tlocation` on
(`tauftrag`.`locationnr` = `tlocation`.`locationnr`))
)
SELECT t1.*,t2.`artikel`,t3.`artikel`,t4.`artikel`
FROM t1
LEFT JOIN t1 t2
ON t1.`auftragsnr2` = t2.`auftragsnr2`
AND t2.zeile = 2
LEFT JOIN t1 t3
ON t1.`auftragsnr2` = t3.`auftragsnr2`
AND t3.zeile = 3
LEFT JOIN t1 t4
ON t1.`auftragsnr2` = t4.`auftragsnr2`
AND t4.zeile = 4
WHERE t1.zeile = 1
Ah okay wir kommen der Sache näher
Habe deinen vollen Code da eingesetzt und der Fehler dürfte so nicht mehr kommen weil ich Aliase vergeben habe. Das kann man alles verfeinern wenn das Query läuft, bitte nochmal testen.
WITH t1 AS (
select
ROW_NUMBER() OVER (PARTITION BY `tauftrag`.`auftragsnr2` ORDER BY `tartikel`.`leistungsdatum`,`tartikel`.`artikel`) AS zeile,
`tauftrag`.`auftragsnr2` AS `auftragsnr2`,
`tauftrag`.`leistungsdatum` AS `leistungsdatum`,
`tauftrag`.`full` AS `full`,
`tartikel`.`artikel` AS `artikel`,
`tauftrag`.`auslieferungsdatum` AS `auslieferungsdatum`,
`tauftrag`.`status` AS `status`,
`tlocation`.`name` AS `name`,
`tlocation`.`plz` AS `plz`,
`tlocation`.`ort` AS `ort`,
`tlocation`.`strasse` AS `strasse`,
`tlocation`.`hausnummer` AS `hausnummer`,
`tauftrag`.`aufbaudurch` AS `aufbaudurch`
from (((`tauftrag`
join `tauftragartikel` on
(`tauftrag`.`auftragsnr` = `tauftragartikel`.`auftragsnr`))
join `tartikel` on
(`tauftragartikel`.`artikelnr` = `tartikel`.`artikelnr`))
join `tlocation` on
(`tauftrag`.`locationnr` = `tlocation`.`locationnr`))
)
SELECT t1.*,t2.`artikel` AS artikel2,t3.`artikel` AS artikel3,t4.`artikel` AS artikel4
FROM t1
LEFT JOIN t1 t2
ON t1.`auftragsnr2` = t2.`auftragsnr2`
AND t2.zeile = 2
LEFT JOIN t1 t3
ON t1.`auftragsnr2` = t3.`auftragsnr2`
AND t3.zeile = 3
LEFT JOIN t1 t4
ON t1.`auftragsnr2` = t4.`auftragsnr2`
AND t4.zeile = 4
WHERE t1.zeile = 1
Was würde ich ändern:
- Die Syntax ist jetzt nicht ganz einheitlich, da hat jeder seinen eigenen Stil und Verständnis.
- In ROW_NUMBER() gibt es ein ORDER BY, das war jetzt erstmal ein von mir geratener Ansatz. Eventuell gibt es noch eine schönere Sortierung.
- Statt t1.* sollte man die Spalten explizit benennen wenn der Code produktiv eingesetzt wird. Ist einfach sauberer. Man kann dann im gleichen Zug aus artikel auch artikel1 machen.
- Die Syntax ist jetzt nicht ganz einheitlich, da hat jeder seinen eigenen Stil und Verständnis.
- In ROW_NUMBER() gibt es ein ORDER BY, das war jetzt erstmal ein von mir geratener Ansatz. Eventuell gibt es noch eine schönere Sortierung.
- Statt t1.* sollte man die Spalten explizit benennen wenn der Code produktiv eingesetzt wird. Ist einfach sauberer. Man kann dann im gleichen Zug aus artikel auch artikel1 machen.
Also das ORDER BY bestimmt die Sortierung
Das heißt bei gleichem Leistungsdatum geht's nach Artikel weiter, alphabetisch. Du kannst ORDER BY eventuell komplett weg lassen oder mit ORDER BY 1 ersetzen oder so, aber das PARTITION BY davor muss bleiben. Ich weiß nicht ob MariaDB das schluckt = testen. Aber: Keine Sortierung bedeutet nicht, das es ein "zuerst" gibt, es ist einfach unspezifisch und theoretisch willkürlich. Wenn du noch irgend eine andere Spalte hast (z.B. einen Zeitstempel) die das sinnvoller ordnen kann würde ich die nehmen.
order by
`db68121`.`tauftrag`.`leistungsdatum`,`db68121`.`tartikel`.`artikel`)