SQL-Abfrage: Reporting/Controlling Daten

Adriano10

Benutzer
Beiträge
19
Ich bin leider Anfänger in SQL. Ich habe folgende Aufgabe:

Anforderung ist folgedne:
  • Menge Aktionszeitraum (Summe verkaufte Stück pro Artikel und Land)
  • Umsatz Aktionszeitraum, (Summe Umsatz pro Artikel und Land)
  • Menge Vergleichszeitraum, (Summe verkaufte Stück pro Artikel und Land)
  • Umsatz Vergleichszeitraum (Summe Umsatz pro Artikel und Land)
Vielleicht kann jemand mir weiterhelfen..

Ich habe Query gebaut, aber habe ich Fehlermeldung: "SQL-Fehler [21000]: [SQL0811] Ergebnis der Anweisung enthält mehr als eine Zeile."
T01.OLPRDC = Articelnummer,
T04.OHODAT = Datum.

#############################

SELECT
T01.OLPRDC,
sum(T01.OLITET) AS "Umsatz Aktion",
SUM(T01.OLOQTY) AS "Menge Aktion",
(
SELECT
sum(T01.OLITET) AS "Umsatz Vergleich"
FROM
FRI510AFWF.SROORSPL T01
JOIN FRI510AFWF.SRONAM T02 ON
T01.OLCUNO = T02.NANUM
JOIN FRI510AFWF.SRBSOH T04 ON
T01.OLORNO = T04.OHORNO
JOIN FRI510AF.SROPRG T06 ON
T01.OLPRDC = T06.PGPRDC
JOIN FRI510AF.SRBCTLD1 T03 ON
T01.OLORDT = T03.CTOTYP
WHERE
T04.OHODAT BETWEEN '20230305' AND '20230405' --Vergleichzeitraum
AND T01.OLSTAT <> 'D'
AND T01.OLIORD = 'N'
AND T01.OLORDT NOT IN ('IV', 'IS', 'BL', 'IG', 'V4', 'IU')
AND T02.NACOUN IN ('DE')
AND T04.OHHAND <> 'PSHOP'
AND T01.OLPRDC IN('38099478', '11046624') GROUP BY T01.OLPRDC),

(
SELECT
SUM(T01.OLOQTY) AS "Menge Vergleich"
FROM
FRI510AFWF.SROORSPL T01
JOIN FRI510AFWF.SRONAM T02 ON
T01.OLCUNO = T02.NANUM
JOIN FRI510AFWF.SRBSOH T04 ON
T01.OLORNO = T04.OHORNO
JOIN FRI510AF.SROPRG T06 ON
T01.OLPRDC = T06.PGPRDC
JOIN FRI510AF.SRBCTLD1 T03 ON
T01.OLORDT = T03.CTOTYP
WHERE
T04.OHODAT BETWEEN '20230305' AND '20230405' --Vergleichzeitraum
AND T01.OLSTAT <> 'D'
AND T01.OLIORD = 'N'
AND T01.OLORDT NOT IN ('IV', 'IS', 'BL', 'IG', 'V4', 'IU')
AND T02.NACOUN IN ('DE')
AND T04.OHHAND <> 'PSHOP'
AND T01.OLPRDC IN('38099478', '11046624') GROUP BY T01.OLPRDC)
FROM
FRI510AFWF.SROORSPL T01
JOIN FRI510AFWF.SRONAM T02 ON
T01.OLCUNO = T02.NANUM
JOIN FRI510AFWF.SRBSOH T04 ON
T01.OLORNO = T04.OHORNO
JOIN FRI510AF.SROPRG T06 ON
T01.OLPRDC = T06.PGPRDC
JOIN FRI510AF.SRBCTLD1 T03 ON
T01.OLORDT = T03.CTOTYP
WHERE
T04.OHODAT BETWEEN '20230105' AND '20230405' --Aktionszeitraum
AND T01.OLSTAT <> 'D'
AND T01.OLIORD = 'N'
AND T01.OLORDT NOT IN ('IV', 'IS', 'BL', 'IG', 'V4', 'IU')
AND T02.NACOUN IN ('DE')
AND T04.OHHAND <> 'PSHOP'
AND T01.OLPRDC IN('38099478', '11046624')
GROUP BY
T01.OLPRDC;
 
Werbung:
Ergebnis der Anweisung enthält mehr als eine Zeile
Das muss sich auf ein oder beide Subselects beziehen.
Wenn Du ein Subselect in die Select Clause quetscht, muss Du sicherstellen, dass auch nur ein Datensatz rauskommt, sonst gibt es diesen Fehler.
Was genau dazu führt, kann man aus der Ferne ohne Daten und Modell nicht beurteilen.

Du kannst probehalber die Subselects mit Limit / Top auf einen Datensatz einschränken, dann müssen sie laufen (wenn keine anderen Fehler drin sind)

Generell sind Subselects in der Select Clause nicht besonders cool. Sie scheinen praktisch, machen die Ausführung aber oft unglaublich langsam.
Alle Subselects kann man auch zu einem normalen Join transformieren. Der kann per Definition 0, einen oder viele Ergebnisse liefern.
Die müssten dann nach Bedarf ebenfalls eingegrenzt werden, im Join oder per Aggregation. Zumindest bekommt man diesen Fehler nicht mehr und sieht die Daten vor der Nase, die mehr Zeilen liefern, als gewollt.
 
Und noch 2 Sachen:
- Man kann SQL formatieren
- Man kann Aliase sprechend und redundanzfrei vergeben

In Deinen Subselect verwendest Du offenbar identische, abstrakte Table Aliase wie im Hauptselectstatement. Wieso quält man sich und andere mit sowas? T01,T02,T03,T06,.. sagt mir grad gar nichts. T05 fehlt, hat das was zu bedeuten? Müssen wir um T05 trauern? Nein, die Frage ist nicht ernst, die Aliase signalisieren mir, dass sie eigentlich bedeutungslos sind. Was logisch gesehen stimmt, aber vollkommen unpragmatisch ist.
Ein Alias (für Spalten oder Tabellen oder Subselects) darf ohne weiteres einen -frei wählbaren- Sinn enthalten. Wie ein Tabellenname selbst ja auch. Das gilt grundsätzlich, aber in einem SQL Forum besonders.
Eindeutige und sinngebende Aliase hätten den Vorteil, dass man in Deinem Statement sofort sehen könnte, ob und welchen Bezug die Subselects überhaupt zum Hauptselect haben. Auf den ersten Blick sieht es fast so aus, dass es keinen gibt. Ich verspüre wenig Lust, jetzt Aliase zu zählen und zu schauen, welcher eindeutig ist und welcher nicht. Und ob es dadurch einen Bezug zum Hauptstatemen gibt oder nicht.
 
In beiden Subselects wird nur sum(spalte) abgefragt aber es steht ein GROUP BY T01.OLPRDC ganz am Ende (des Subselects). Auch wenn die Spalte T01.OLPRDC nicht angezeigt wird so wird dennoch dannach gruppiert und es können mehrere Summen zurück gegeben werden. Wenn du das GROUP BY einfach weg läßt, dann wird alles summiert und die Abfrage ist erstmal lauffähig.

Allerdings gruppierst du im Haupt-Select nach der selben Spalte daher vermute ich mal du willst nur die Summe aus Einträgen mit der selben Spalte zusammen ziehen. Das geht grundsätzlich, du kannst im Subselect Bezug nehmen auf Daten aus dem Hauptselect, also z.B. statt den GROUP BY im WHERE-Teil ergänzen:
Code:
AND T01.OLPRDC = hauptselect.OLPRDC
Hier kommt dann aber ein Problem zum tragen: Du verwendest im Hauptselect die selben Aliase wie in den Subselects, das wirst du abändern müssen:
Code:
SELECT
H01.OLPRDC,
sum(H01.OLITET) AS "Umsatz Aktion",
SUM(H01.OLOQTY) AS "Menge Aktion",
(
SELECT
sum(T01.OLITET)
FROM
FRI510AFWF.SROORSPL T01
JOIN FRI510AFWF.SRONAM T02 ON
T01.OLCUNO = T02.NANUM
JOIN FRI510AFWF.SRBSOH T04 ON
T01.OLORNO = T04.OHORNO
JOIN FRI510AF.SROPRG T06 ON
T01.OLPRDC = T06.PGPRDC
JOIN FRI510AF.SRBCTLD1 T03 ON
T01.OLORDT = T03.CTOTYP
WHERE
T04.OHODAT BETWEEN '20230305' AND '20230405' --Vergleichzeitraum
AND T01.OLSTAT <> 'D'
AND T01.OLIORD = 'N'
AND T01.OLORDT NOT IN ('IV', 'IS', 'BL', 'IG', 'V4', 'IU')
AND T02.NACOUN IN ('DE')
AND T04.OHHAND <> 'PSHOP'
AND T01.OLPRDC IN('38099478', '11046624')
AND T01.OLPRDC = H01.OLPRDC) AS "Umsatz Vergleich",

(
SELECT
SUM(T01.OLOQTY)
FROM
FRI510AFWF.SROORSPL T01
JOIN FRI510AFWF.SRONAM T02 ON
T01.OLCUNO = T02.NANUM
JOIN FRI510AFWF.SRBSOH T04 ON
T01.OLORNO = T04.OHORNO
JOIN FRI510AF.SROPRG T06 ON
T01.OLPRDC = T06.PGPRDC
JOIN FRI510AF.SRBCTLD1 T03 ON
T01.OLORDT = T03.CTOTYP
WHERE
T04.OHODAT BETWEEN '20230305' AND '20230405' --Vergleichzeitraum
AND T01.OLSTAT <> 'D'
AND T01.OLIORD = 'N'
AND T01.OLORDT NOT IN ('IV', 'IS', 'BL', 'IG', 'V4', 'IU')
AND T02.NACOUN IN ('DE')
AND T04.OHHAND <> 'PSHOP'
AND T01.OLPRDC IN('38099478', '11046624')
AND T01.OLPRDC = H01.OLPRDC) AS "Menge Vergleich"
FROM
FRI510AFWF.SROORSPL H01
JOIN FRI510AFWF.SRONAM H02 ON
H01.OLCUNO = H02.NANUM
JOIN FRI510AFWF.SRBSOH H04 ON
H01.OLORNO = H04.OHORNO
JOIN FRI510AF.SROPRG H06 ON
H01.OLPRDC = H06.PGPRDC
JOIN FRI510AF.SRBCTLD1 H03 ON
H01.OLORDT = H03.CTOTYP
WHERE
H04.OHODAT BETWEEN '20230105' AND '20230405' --Aktionszeitraum
AND H01.OLSTAT <> 'D'
AND H01.OLIORD = 'N'
AND H01.OLORDT NOT IN ('IV', 'IS', 'BL', 'IG', 'V4', 'IU')
AND H02.NACOUN IN ('DE')
AND H04.OHHAND <> 'PSHOP'
AND H01.OLPRDC IN('38099478', '11046624')
GROUP BY
H01.OLPRDC;
Auch wenn das Ergebnis dann eventuell stimmt hast du sehr viele, auf den ersten Blick redundante Joins. Ich denke da kann man anders vorgehen.
 
Vermutlich kannst du das kürzen auf :
Code:
SELECT
H01.OLPRDC,
sum(CASE WHEN H04.OHODAT BETWEEN 20230105 AND 20230405 THEN H01.OLITET ELSE 0 END) AS "Umsatz Aktion",
sum(CASE WHEN H04.OHODAT BETWEEN 20230105 AND 20230405 THEN H01.OLOQTY ELSE 0 END) AS "Menge Aktion",
sum(CASE WHEN H04.OHODAT BETWEEN 20230305 AND 20230405 THEN H01.OLITET ELSE 0 END) AS "Umsatz Vergleich",
sum(CASE WHEN H04.OHODAT BETWEEN 20230305 AND 20230405 THEN H01.OLOQTY ELSE 0 END) AS "Menge Vergleich"
FROM
FRI510AFWF.SROORSPL H01
JOIN FRI510AFWF.SRONAM H02 ON
H01.OLCUNO = H02.NANUM
JOIN FRI510AFWF.SRBSOH H04 ON
H01.OLORNO = H04.OHORNO
JOIN FRI510AF.SROPRG H06 ON
H01.OLPRDC = H06.PGPRDC
JOIN FRI510AF.SRBCTLD1 H03 ON
H01.OLORDT = H03.CTOTYP
WHERE
( H04.OHODAT BETWEEN 20230105 AND 20230405 --Aktionszeitraum
OR H04.OHODAT BETWEEN 20230305 AND 20230405 ) --Vergleichzeitraum
AND H01.OLSTAT <> 'D'
AND H01.OLIORD = 'N'
AND H01.OLORDT NOT IN ('IV', 'IS', 'BL', 'IG', 'V4', 'IU')
AND H02.NACOUN IN ('DE')
AND H04.OHHAND <> 'PSHOP'
AND H01.OLPRDC IN('38099478', '11046624')
GROUP BY
H01.OLPRDC;
BETWEEN vergleicht übrigens Zahlen oder Datumswerte, das heißt hier wird konvertiert. Daher habe ich mal die Anführungszeichen weg gelassen, die Spalte wird ggf. noch konvertiert.
 
Vermutlich kannst du das kürzen auf :
Code:
SELECT
H01.OLPRDC,
sum(CASE WHEN H04.OHODAT BETWEEN 20230105 AND 20230405 THEN H01.OLITET ELSE 0 END) AS "Umsatz Aktion",
sum(CASE WHEN H04.OHODAT BETWEEN 20230105 AND 20230405 THEN H01.OLOQTY ELSE 0 END) AS "Menge Aktion",
sum(CASE WHEN H04.OHODAT BETWEEN 20230305 AND 20230405 THEN H01.OLITET ELSE 0 END) AS "Umsatz Vergleich",
sum(CASE WHEN H04.OHODAT BETWEEN 20230305 AND 20230405 THEN H01.OLOQTY ELSE 0 END) AS "Menge Vergleich"
FROM
FRI510AFWF.SROORSPL H01
JOIN FRI510AFWF.SRONAM H02 ON
H01.OLCUNO = H02.NANUM
JOIN FRI510AFWF.SRBSOH H04 ON
H01.OLORNO = H04.OHORNO
JOIN FRI510AF.SROPRG H06 ON
H01.OLPRDC = H06.PGPRDC
JOIN FRI510AF.SRBCTLD1 H03 ON
H01.OLORDT = H03.CTOTYP
WHERE
( H04.OHODAT BETWEEN 20230105 AND 20230405 --Aktionszeitraum
OR H04.OHODAT BETWEEN 20230305 AND 20230405 ) --Vergleichzeitraum
AND H01.OLSTAT <> 'D'
AND H01.OLIORD = 'N'
AND H01.OLORDT NOT IN ('IV', 'IS', 'BL', 'IG', 'V4', 'IU')
AND H02.NACOUN IN ('DE')
AND H04.OHHAND <> 'PSHOP'
AND H01.OLPRDC IN('38099478', '11046624')
GROUP BY
H01.OLPRDC;
BETWEEN vergleicht übrigens Zahlen oder Datumswerte, das heißt hier wird konvertiert. Daher habe ich mal die Anführungszeichen weg gelassen, die Spalte wird ggf. noch konvertiert.
vielen Dank, das ist sehr hilfreich
 
Und noch 2 Sachen:
- Man kann SQL formatieren
- Man kann Aliase sprechend und redundanzfrei vergeben

In Deinen Subselect verwendest Du offenbar identische, abstrakte Table Aliase wie im Hauptselectstatement. Wieso quält man sich und andere mit sowas? T01,T02,T03,T06,.. sagt mir grad gar nichts. T05 fehlt, hat das was zu bedeuten? Müssen wir um T05 trauern? Nein, die Frage ist nicht ernst, die Aliase signalisieren mir, dass sie eigentlich bedeutungslos sind. Was logisch gesehen stimmt, aber vollkommen unpragmatisch ist.
Ein Alias (für Spalten oder Tabellen oder Subselects) darf ohne weiteres einen -frei wählbaren- Sinn enthalten. Wie ein Tabellenname selbst ja auch. Das gilt grundsätzlich, aber in einem SQL Forum besonders.
Eindeutige und sinngebende Aliase hätten den Vorteil, dass man in Deinem Statement sofort sehen könnte, ob und welchen Bezug die Subselects überhaupt zum Hauptselect haben. Auf den ersten Blick sieht es fast so aus, dass es keinen gibt. Ich verspüre wenig Lust, jetzt Aliase zu zählen und zu schauen, welcher eindeutig ist und welcher nicht. Und ob es dadurch einen Bezug zum Hauptstatemen gibt oder nicht.
ja, leider ich habe viele Redudante, das ist erstes Mal, dass ich so große Abfrage gebaut habe. Daher kann ich mit den Redutanten nicht ganz gut umgehen.

Vielen Dank für die Empfehlungen
 
Werbung:
leider ich habe viele Redudante
klingt als ob Du mich falsch verstanden hast.
Du solltest sprechende und eindeutige Aliase verwenden. Die kannst Du sofort in Deinem Statement austauschen. Das hat wenig mit SQL Verständnis zu tun. Du musst einfach Aliase "erfinden", ob Du Dich bei der Namensfindung an Grimms Märchenerzählungen orientierst oder an diversen Pantoffeltierchen. Irgendwelche eindeutigen Namen sind besser als doppeldeutige.

Und das hat auch nichts mit der Fehlermeldung zu tun. Der Hinweis von @ukulele zum Group By dürfte den Fehler beseitigen.
 
Zurück
Oben