Einträge in 2 Spalten miteinander vergleichen

Hallo.

Bitte um Hilfe da ich bei einer Aufgabe meiner Uni komplett anstehe und auch keinen Befehl finde der funktioniert.
Wir haben Test Datenbank die wie unten abgebildet aussieht (ist nur ein Auszug der ganzen Tabelle): Ein Eintrag lautet dass ein Kunde (mit seiner Kundennummer) dass Produkt (mit dieser ProduktID) bestellt hat

Die letzte Aufgabenstellung, bei der ich nicht mehr weiter komme lautet: Liste alle Kundennummern, welche ein Produkt nicht bestellen auf. Die Query soll also als Resultat eine Liste aller Kunden ergeben, die ein Produkt, welches in der 2. Spalte mit der ID angeführt ist, nicht bestellen, also wo es keine Reihe aus Kundennummer und ProduktID gibt. Zusätzlich soll noch eine Query angegeben werden, mit der es möglich ist, alle Kunden aufzulisten, die alle Produkte schon min. 1x bestellt haben (also der Umkehrschluss zu vorhin ;-)).

Zusätzlich hab ich die Einschränkung, nur Aggregations, Subqueries, order, group, limit…also basic sql befehle benutzen und keine schleifen etc. mit skripten.

Ich danke jedem im Voraus, der mir hierfür hilft.

Schöne Grüße

KundenNr| ProdID |
-------±----------±----
0028 | CF-101
0028 | CS-347
21345 | CF-101
21345 | CS-190
21345 | CS-317
21345 | CS-347
16991 | HIS-351
32121 | FIN-201
47553 | PHY-101
48678 | CF-101
48678 | CF-101
48678 | CS-317
84321 | CF-101
84321 | CS-190

test=*# select * from maxxx12345 ;
 kundennr | prodid  
----------+---------
 0028     | CF-101
 0028     | CS-347
 21345    | CF-101
 21345    | CS-190
 21345    | CS-317
 21345    | CS-347
 16991    | HIS-351
 32121    | FIN-201
 47553    | PHY-101
 48678    | CF-101
 48678    | CF-101
 48678    | CS-317
 84321    | CF-101
 84321    | CS-190
(14 Zeilen)

wer hat HIS-351 bestellt?

test=*# select * from (select kundennr, array_agg(prodid) as bestellte_artikel from maxxx12345 group by kundennr) foo where bestellte_artikel @> array['HIS-351'];
 kundennr | bestellte_artikel 
----------+-------------------
 16991    | {HIS-351}
(1 Zeile)

Wer nicht?

test=*# select * from (select kundennr, array_agg(prodid) as bestellte_artikel from maxxx12345 group by kundennr) foo where not bestellte_artikel @> array['HIS-351'];
 kundennr |       bestellte_artikel       
----------+-------------------------------
 0028     | {CF-101,CS-347}
 47553    | {PHY-101}
 48678    | {CF-101,CF-101,CS-317}
 21345    | {CF-101,CS-190,CS-317,CS-347}
 84321    | {CF-101,CS-190}
 32121    | {FIN-201}
(6 Zeilen)

wer hat schon alle Produkte bestellt?

test=*# select * from (select kundennr, array_agg(prodid) as bestellte_artikel from maxxx12345 group by kundennr) foo where bestellte_artikel @> (select array_agg(distinct prodid) from maxxx12345);
 kundennr | bestellte_artikel 
----------+-------------------
(0 Zeilen)

Wer hat einen Kaffee für mich?

Sowas wird typischerweise mit einer NOT EXIST Bedingung gemacht.

Z.B.: Kunden die Produkt CF-101 nicht bestellt haben:

select distinct t1.kundennr
from the_table t1
where not exists (select *
                  from the_table t2
                  where t1.kundennr = t2.kundennr 
                    and t2.prodid = 'CF-101');

Online Beispiel: http://rextester.com/AFY26603

Vielen Dank für die Antowrt. Allerdings muss ich hierfür wieder speziell alle Produkt ID in die Abfrage eingeben.
Gemeint war dass sich die Abfrage alle möglichen Produkt ID sucht und danach schaut welcher Kunde noch nicht alle bestellt hat. Gibt es dafür eine Lösung überhaupt? Dankesehr!!!

In welcher Tabelle stehen dann “alle möglichen Produkte”?

Hast meine Antwort übersehen?

Die Nachfrage von @castorp ist natürlich berechtigt :wink:

eine solche Liste kannst Du so erhalten:

test=*# select array_agg(distinct prodid) from maxxx12345;
                       array_agg                       
-------------------------------------------------------
 {CF-101,CS-190,CS-317,CS-347,FIN-201,HIS-351,PHY-101}
(1 Zeile)

test=*# select string_agg(distinct prodid,',') from maxxx12345;
                     string_agg                      
-----------------------------------------------------
 CF-101,CS-190,CS-317,CS-347,FIN-201,HIS-351,PHY-101
(1 Zeile)

Dankesehr! habe nun diese Abfrage probiert:

select distinct t1.KundenNr
from orders as t1
where not exists (select *
                  from orders as t2
                  where t1.KundenNr = t2.KundenNr
                    and t2.ProdID exists (select array_agg(distinct ProdID) from orders));

Das mit der Liste klappt, vielen Dank! Nur wie bau ich dies nun in eine Abfrage, die mir die Liste aller Kunden gibt, welche ein Produkt (und wenns nur ein einziges ist) von dort noch nicht bestellt haben?