Vinzenz Mai: SELECT mit JOIN und LIMIT GROUP BY Problem

Beitrag lesen

Hallo,

Nun möchte ich immer 5 Rechnungen auf einmal anzeigen:

SELECT

rechnungen.kundennummer AS rekunr,
rechnungen.rechnungsnummer AS renr,
rechnungen.rechnungid  AS reid,

kundendaten.anrede AS kuan,
kundendaten.name AS kuna,
kundendaten.kundennummer AS kunr,

positionen.rechnungsnummer AS ponr,
positionen.anzahl * positionen.preis AS gesamt

FROM rechnungen
  LEFT JOIN kundendaten
  ON rechnungen.kundennummer = kundendaten.kundennummer
  LEFT JOIN positionen
  ON rechnungen.rechnungsnummer = positionen.rechnungsnummer
  GROUP BY gesamt
  ORDER BY rechnungen.rechnungsnummer
  LIMIT $anzeige, 5

was für ein Glück, das nur MySQL ein derart fehlerhaftes Statement ausführt.

Was möchtest Du nun genau haben?
Jeweils die zusammengefaßten Daten von fünf Rechnungen?

Kundennummer,
Rechnungsnummer
Rechnungsid (wozu diese, wenn es eine Rechnungsnummer gibt?)
Werden Rechnungsnummern wiederverwendet? Wenn ja, darfst Du die Positionen auch nur über die rechnungid zuordnen.

Anrede
Name
und nochmals die Kundennummer    (läßt man weg)
und nochmals die Rechnungsnummer (läßt man ebenfalls weg)
tja und dann den Rechnungsbetrag dieser einen Rechnung.

1. Schritt:
Berechne den Rechnungsbetrag jeder Rechnung (dazu benötigst Du die Aggregatsfunktion SUM(). Du benötigst nur die Tabelle positionen.
Gruppiere nach Rechnungsnummer.

2. Schritt:
Lass Dir die Rechnungsdetails anzeigen. Da die Zuordnung eindeutig sein sollte, und alle anderen Spalten der Tabelle Rechnung eindeutig von der Rechnungsnummer abhängen, könntest und solltest Du nach dem Join problemlos nach allen Spalten außer dem Rechnungsbetrag gruppieren.

3. Schritt
Die Kundendaten sollten ebenfalls eindeutig von der Rechnungsnummer abhängen, so dass Du problemlos die Kundendaten dazujoinen kannst und nach *allen* Spalten außer dem Rechnungsbetrag gruppieren kannst.

Ist Dir dies zuviel des Gruppierens, so joine die Rechnungstabelle mit der 1. Abfrage (Berechnung des Rechnungsbetrages) als temporärer View und anschließend die Kundendaten dazu. Durch den temporären View entfällt das weitere Gruppieren.

Du hast nach der einzigen Spalte gruppiert, nach der Du *nicht* gruppieren, sondern auf die Du eine Aggregatsfunktion anwenden solltest.

Ungetesteter Code für den Einsatz des temporären Views

1. Schritt:
Berechne den Rechnungsbetrag je Rechnung (Rechnungsnummer):

  
SELECT                  -- Gib mir  
    p.rechnungsnummer   -- die Rechnungsnummer  
    SUM(p.anzahl * p.betrag) rechnungsbetrag  -- und den Rechnungsbetrag,  
                        -- der sich aus der Summe der Positionsbeträge  
                        -- berechnet, die sich wiederum aus dem Produkt  
                        -- von Einzelpreis und Anzahl berechnen  
FROM                    -- aus der Tabelle  
    positionen p        -- Positionen, die mit dem Alias p angesprochen wird  
                        -- auf das optionale AS verzichten wir aus  
                        -- Kompatibilitätsgründen :-)  
GROUP BY                -- gruppiert nach  
    p.rechnungsnummer   -- den Rechnungsnummern, d.h. ein Eintrag je  
                        -- Rechnungsnummer  

Schritt 2:
Wir nutzen die Abfrage aus Schritt 1 als temporären View und joinen diese Abfrage mit der Rechnungstabelle:

  
SELECT                     -- Gib mir  
    r.rechnungsnummer,     -- die Rechnungsnummer  
    r.kundennummer,        -- die zugehörige Kundennummer  
    r.rechnungid,          -- die Rechnungsid  
    p.rechnungsbetrag      -- und den Rechnungsbetrag  
FROM                       -- der  
    rp.rechnungen r        -- Rechnungen, die wir bequemerweise über r  
                           -- ansprechen. Verzicht auf AS siehe oben.  
INNER JOIN (               -- die mit den Rechnungspositionen  
    SELECT                 -- aus Schritt 1  
        p.rechnungsnummer,  
        SUM(p.anzahl * p.preis) rechnungsbetrag  
    FROM  
        positionen p  
    GROUP BY  
        p.rechnungsnummer  
    ) rp                   -- (der temporäre View benötigt zwingend einen  
                           -- Aliasnamen (rp für rechnungspositionen))  
ON                         -- über die  
    r.rechnungsnummer = rp.rechnungsnummer  -- Rechnungsnummer verknüpft ist.  

Die Vervollständigung mit den Kundendaten überlasse ich Dir als Übung.
Anmerkung: Vollständige Tabellennamen als Aliasnamen zu verwenden bzw. zur genauen Spaltenansprache, ist in den wenigsten Fällen sinnvoll und trägt meist nicht zur Lesbarkeit einer Abfrage bei.

Bei SQL-Problemen ist es nicht sinnvoll, PHP-Code zu posten, der SQL-Code erzeugt. Zuerst sollte man händisch das gewünschte SQL-Statement schreiben, bevor man versucht, es mit $programmiersprache zusammenzubauen. Es ist natürlich nicht notwendig, jeden benötigten LIMIT-Wert von Hand auszutesten :-)

Freundliche Grüße

Vinzenz