SQL - Kann mir Ergebnis nicht erklären

Zvoni

Erfahrenes Mitglied
OK, steh gerade auf dem Schlauch weil ich die Ergebnisse der SQL's nicht verstehe
DBMS = DB2
SQL:
SELECT LOFIRM, LOWKNR, LOTENR, LOKDNR || ' - ' || KDNAME AS MINVKD, MIN(LOPR01) AS LOPR01
        FROM X500PRDSD.LPKO
        INNER JOIN X500PRDSD.KDST
        ON KDFIRM=LOFIRM AND KDWKNR=LOWKNR AND KDKDNR=LOKDNR AND KDVENR=0
        WHERE LOFIRM='2' AND LOWKNR='050' AND LOTENR='100273' AND 
        INT(VARCHAR_FORMAT(CURRENT_DATE, 'YYYYMMDD')) BETWEEN LOGUVO AND LOGUBI
GROUP BY LOFIRM, LOWKNR, LOTENR, LOKDNR || ' - ' || KDNAME
ORDER BY LOPR01 FETCH FIRST 1 ROWS ONLY
Ergibt das (Korrekt!) --> Hinweis: FETCH FIRST 1 ROWS ONLY wäre in anderen DBMS ein LIMIT 1 weil ich nur die Kundennummer mit dem niedrigsten VK-Preis haben will
LOFIRMLOWKNRLOTENRMINVKDLOPR01
20501002732001082 - Anonymer Kunde0,25

Dann habe ich dieses SQL
SQL:
SELECT K1.LOFIRM, K1.LOWKNR, K1.LOTENR, K1.KDNRMIN || ' - ' || K2.KDNAME AS KUNDEMIN, K1.KDNRMAX || ' - ' || K3.KDNAME AS KUNDEMAX  
    FROM (SELECT LOFIRM, LOWKNR, LOTENR, MIN(LOKDNR) AS KDNRMIN, MAX(LOKDNR) AS KDNRMAX
        FROM X500PRDSD.LPKO WHERE INT(VARCHAR_FORMAT(CURRENT_DATE, 'YYYYMMDD')) 
                   BETWEEN LOGUVO AND LOGUBI
        GROUP BY LOFIRM, LOWKNR, LOTENR) AS K1
    INNER JOIN (SELECT DISTINCT KDFIRM, KDWKNR, KDKDNR, KDNAME FROM X500PRDSD.KDST WHERE KDVENR=0) AS K2
    ON K2.KDFIRM=K1.LOFIRM AND K2.KDWKNR=K1.LOWKNR AND K2.KDKDNR=K1.KDNRMIN
    INNER JOIN (SELECT DISTINCT KDFIRM, KDWKNR, KDKDNR, KDNAME FROM X500PRDSD.KDST WHERE KDVENR=0) AS K3
    ON K3.KDFIRM=K1.LOFIRM AND K3.KDWKNR=K1.LOWKNR AND K3.KDKDNR=K1.KDNRMAX
WHERE K1.LOFIRM='2' AND K1.LOWKNR='050' AND K1.LOTENR='100273'
Ergibt das (Korrekt!)
LOFIRMLOWKNRLOTENRKUNDEMINKUNDEMAX
20501002732000848 - Geht euch nix an2001188 - Geht euch auch nix an

Mache ich aber das hier:
SQL:
SELECT K1.LOFIRM, K1.LOWKNR, K1.LOTENR, K1.KDNRMIN || ' - ' || K2.KDNAME AS KUNDEMIN, K1.KDNRMAX || ' - ' || K3.KDNAME AS KUNDEMAX, K5.MINVKD, K5.LOPR01  
    FROM (SELECT LOFIRM, LOWKNR, LOTENR, MIN(LOKDNR) AS KDNRMIN, MAX(LOKDNR) AS KDNRMAX
        FROM X500PRDSD.LPKO WHERE INT(VARCHAR_FORMAT(CURRENT_DATE, 'YYYYMMDD')) BETWEEN LOGUVO AND LOGUBI
        GROUP BY LOFIRM, LOWKNR, LOTENR) AS K1
    INNER JOIN (SELECT DISTINCT KDFIRM, KDWKNR, KDKDNR, KDNAME FROM X500PRDSD.KDST WHERE KDVENR=0) AS K2
    ON K2.KDFIRM=K1.LOFIRM AND K2.KDWKNR=K1.LOWKNR AND K2.KDKDNR=K1.KDNRMIN
    INNER JOIN (SELECT DISTINCT KDFIRM, KDWKNR, KDKDNR, KDNAME FROM X500PRDSD.KDST WHERE KDVENR=0) AS K3
    ON K3.KDFIRM=K1.LOFIRM AND K3.KDWKNR=K1.LOWKNR AND K3.KDKDNR=K1.KDNRMAX

    LEFT JOIN (SELECT LOFIRM, LOWKNR, LOTENR, LOKDNR || ' - ' || KDNAME AS MINVKD, MIN(LOPR01) AS LOPR01 FROM X500PRDSD.LPKO
        INNER JOIN X500PRDSD.KDST ON KDFIRM=LOFIRM AND KDWKNR=LOWKNR AND KDKDNR=LOKDNR AND KDVENR=0
        WHERE INT(VARCHAR_FORMAT(CURRENT_DATE, 'YYYYMMDD')) BETWEEN LOGUVO AND LOGUBI
        GROUP BY LOFIRM, LOWKNR, LOTENR, LOKDNR || ' - ' || KDNAME ORDER BY LOPR01 FETCH FIRST 1 ROWS ONLY) AS K5
    ON K5.LOFIRM=K1.LOFIRM AND K5.LOWKNR=K1.LOWKNR AND K5.LOTENR=K1.LOTENR

WHERE K1.LOFIRM='2' AND K1.LOWKNR='050' AND K1.LOTENR='100273'

bekomme ich das:
LOFIRMLOWKNRLOTENRKUNDEMINKUNDEMAXMINVKDLOPR01
20501002732000848 - Geht euch nix an2001188 - Geht euch auch nix an--

HÄ?
Ist doch ein LEFT JOIN
 

Zvoni

Erfahrenes Mitglied
*GROLL*

Habs gefunden. Der FETCH FIRST ROWS innerhalb des LEFT JOIN's war es.
Den ORDER BY und FETCH FIRST nach draussen, und schon passts
SQL:
SELECT K1.LOFIRM, K1.LOWKNR, K1.LOTENR, K1.KDNRMIN || ' - ' || K2.KDNAME AS KUNDEMIN, K1.KDNRMAX || ' - ' || K3.KDNAME AS KUNDEMAX, K5.MINVKD, K5.LOPR01     
    FROM (SELECT LOFIRM, LOWKNR, LOTENR, MIN(LOKDNR) AS KDNRMIN, MAX(LOKDNR) AS KDNRMAX 
        FROM X500PRDSD.LPKO WHERE INT(VARCHAR_FORMAT(CURRENT_DATE, 'YYYYMMDD')) BETWEEN LOGUVO AND LOGUBI 
        GROUP BY LOFIRM, LOWKNR, LOTENR) AS K1 
    INNER JOIN (SELECT DISTINCT KDFIRM, KDWKNR, KDKDNR, KDNAME FROM X500PRDSD.KDST WHERE KDVENR=0) AS K2 
    ON K2.KDFIRM=K1.LOFIRM AND K2.KDWKNR=K1.LOWKNR AND K2.KDKDNR=K1.KDNRMIN  
    INNER JOIN (SELECT DISTINCT KDFIRM, KDWKNR, KDKDNR, KDNAME FROM X500PRDSD.KDST WHERE KDVENR=0) AS K3 
    ON K3.KDFIRM=K1.LOFIRM AND K3.KDWKNR=K1.LOWKNR AND K3.KDKDNR=K1.KDNRMAX 

    LEFT JOIN (SELECT LOFIRM, LOWKNR, LOTENR, LOKDNR || ' - ' || KDNAME AS MINVKD, MIN(LOPR01) AS LOPR01 FROM X500PRDSD.LPKO 
        INNER JOIN X500PRDSD.KDST ON KDFIRM=LOFIRM AND KDWKNR=LOWKNR AND KDKDNR=LOKDNR AND KDVENR=0 
        WHERE INT(VARCHAR_FORMAT(CURRENT_DATE, 'YYYYMMDD')) BETWEEN LOGUVO AND LOGUBI 
        GROUP BY LOFIRM, LOWKNR, LOTENR, LOKDNR || ' - ' || KDNAME) AS K5 
    ON K5.LOFIRM=K1.LOFIRM AND K5.LOWKNR=K1.LOWKNR AND K5.LOTENR=K1.LOTENR 
WHERE K1.LOFIRM='2' AND K1.LOWKNR='050' AND K1.LOTENR='100273' 
ORDER BY K5.LOPR01 FETCH FIRST 1 ROWS ONLY
 

Zvoni

Erfahrenes Mitglied
Hmmm....war es doch nicht (bzw. nur bedingt).
Ich muss die Abfrage auf eine Gruppe von LOTENR machen, und da macht ein FETCH FIRST 1 ROWS ONLY nicht wirklich Sinn.
Werd ich wohl über ROW_NUMBER und PARTITION's gehen müssen

EDIT:
Jepp, ROW_NUMBER mit PARTITION war's. Kann ich mir dann das MIN(LOPR01) und das GROUP BY sparen
 
Zuletzt bearbeitet:

Yaslaw

alter Rempler
Moderator
Annahme: LOPR01 ist aus der Tabelle LPKO.
Der FETCH FIRST brauchst du überhaubt nicht. Du bestimst ja den MIN pro gruppierten Eintrag. Und alle diese Felder brauchst du ja anschliesend für den JOIN. Also hast du eh nur den MN, der auf den JOIN passt.
 

Zvoni

Erfahrenes Mitglied
Annahme: LOPR01 ist aus der Tabelle LPKO.
Der FETCH FIRST brauchst du überhaubt nicht. Du bestimst ja den MIN pro gruppierten Eintrag. Und alle diese Felder brauchst du ja anschliesend für den JOIN. Also hast du eh nur den MN, der auf den JOIN passt.
Korrekt.
Habs über ROW_NUMBER mit PARTITION gelöst, da mir der LEFT JOIN (Post 2 Ab Zeile 10) mehrere Resultate pro LOFIRM, LOWKNR, LOTENR liefert (unterschiedliche LOKDNR), ich von denen aber nur den mit kleinstem LOPR01 brauche.
Deshalb einfach ne
ROW_NUMBER() OVER(PARTITION BY LOFIRM, LOWKNR, LOTENR ORDER BY LOPR01) AS RN

und in der ON-Klausel filtere ich auf RN=1