Teilmengen
Matthias Apsel
- datenbank
Om nah hoo pez nyeetz, alle!
Ich suche mit einer etwas komplexeren Abfrage bestimmte Schüler aus einer Klasse heraus, nämlich die, die noch unerledigte Aufgaben haben.
Ich suche jetzt alle Schüler dieser Klasse, die in dieser Abfrage nicht dabei sind, d.h. die bereits alle Aufgaben erledigt haben.
Wie stellt man sowas am geschicktesten an?
(MySQL PDO)
Im adminer ist dieses SQL zielführend.
CREATE TEMPORARY TABLE Mahnung ENGINE=INNODB
SELECT
Schüler.ID AS ID,
Name,
Vorname,
`Text`
FROM (
Kreuztabelle
INNER JOIN
Schüler
ON Kreuztabelle.SchülerID = Schüler.ID
)
INNER JOIN
Aufgaben
ON Kreuztabelle.AufgabenID = Aufgaben.ID
WHERE
Schüler.Klasse = 29 AND
Status = 'o' AND
Fälligkeit < '2014-03-09' AND
Erlass_k = 0 AND
Erlass_n = 0 ;
SELECT * FROM Mahnung; -- alle Schüler mit unerledigten Aufgaben
SELECT
Schüler.Name,
Schüler.Vorname
FROM Schüler
LEFT JOIN
Mahnung
ON Schüler.ID = Mahnung.ID
WHERE
ISNULL(Mahnung.ID) AND
Schüler.Klasse = 29; -- alle die, die in Mahnung nicht vorkommen
DROP TABLE Mahnung;
Leider krieg ich das mit PHP nicht umgesetzt.
Matthias
Vorwort: Ich bin im Hotel und habe also meinen Nachtrunk schon genommen.
Matthias
Äh. Der mir aus diesem Forum bekannte Matthias Apsel?
Leider krieg ich das mit PHP nicht umgesetzt.
Hm. Wieso nicht?
1)
Hat Dein Benutzer keine Rechte um temporäre Tabellen anzulegen?
Hast Du nicht beachtet, dass es vier (4) Abfragen sind?
Erste:
CREATE TEMPORARY TABLE Mahnung ENGINE=INNODB
SELECT
Schüler.ID AS ID,
Name,
Vorname,
`Text`
FROM (
Kreuztabelle
INNER JOIN
Schüler
ON Kreuztabelle.SchülerID = Schüler.ID
)
INNER JOIN
Aufgaben
ON Kreuztabelle.AufgabenID = Aufgaben.ID
WHERE
Schüler.Klasse = 29 AND
Status = 'o' AND
Fälligkeit < '2014-03-09' AND
Erlass_k = 0 AND
Erlass_n = 0 ;
Zweite:
SELECT * FROM Mahnung; -- alle Schüler mit unerledigten Aufgaben
Dritte:
SELECT
Schüler.Name,
Schüler.Vorname
FROM Schüler
LEFT JOIN
Mahnung
ON Schüler.ID = Mahnung.ID
WHERE
ISNULL(Mahnung.ID) AND
Schüler.Klasse = 29; -- alle die, die in Mahnung nicht vorkommen
Vierte:
DROP TABLE Mahnung;
Die musst/solltest Du auch einzeln abschicken.
Jörg Reinholz
Om nah hoo pez nyeetz, Jörg Reinholz!
Matthias
Äh. Der mir aus diesem Forum bekannte Matthias Apsel?
Genau der.
Hat Dein Benutzer keine Rechte um temporäre Tabellen anzulegen?
Hast Du nicht beachtet, dass es vier (4) Abfragen sind?
Die musst/solltest Du auch einzeln abschicken.
Danke fuer die Ideen, ich weiss jetzt, wo ich schauen kann.
Matthias
Hi,
Ich suche jetzt alle Schüler dieser Klasse, die in dieser Abfrage nicht dabei sind, d.h. die bereits alle Aufgaben erledigt haben.
im Prinzip so:
SELECT * FROM schüler s WHERE s.klassenid = <gesuchteKlasse> AND s.id NOT IN
(SELECT id FROM schüler WHERE <unerledigte aufgaben vorhanden>)
cu,
Andreas
Om nah hoo pez nyeetz, MudGuard!
SELECT * FROM schüler s WHERE s.klassenid = <gesuchteKlasse> AND s.id NOT IN
(SELECT id FROM schüler WHERE <unerledigte aufgaben vorhanden>)
Ist zumindest schon mal kuerzer als meine Loesung mit dem join. Danke.
Matthias
UNION, EXCEPT und INTERSECT sind typischerweise die Stichworte fuer "Mengen" in SQL Datenbanken :-) NOT IN bzw. IN tutet es aber in 90% der Faelle auch schon.
Frank
Om nah hoo pez nyeetz, alle!
Von dedlfix habe ich eine Lösung erhalten, die ohne eine temporäre Tabelle auskommt.
SELECT
s.Name,
s.Vorname,
a.Text,
a.Kategorie
FROM
Schüler s
LEFT JOIN
Kreuztabelle k
ON k.SchülerID = s.ID AND
k.Status = 'o' AND
k.Erlass_k = 0 AND
k.Erlass_n = 0 AND
EXISTS (
SELECT
*
FROM
Aufgaben a
WHERE
a.ID = k.AufgabenID AND
a.Fälligkeit < '2014-03-10'
)
LEFT JOIN
Aufgaben a ON a.ID = k.AufgabenID
WHERE
s.Klasse = 29
Diese Abfrage liefert zunächst einmal alle Ergebnissätze Schüler - offene Aufgaben. Für die Schüler ohne offene Aufgaben schlägt das SELECT innerhalb von EXISTS fehl, weshalb dann Ergebnissätze
Name, Vorname, NULL, NULL
entstehen, die sich in PHP von einander trennen lassen:
while ($mahnung = $stmt -> fetch(PDO::FETCH_ASSOC)) {
if($mahnung['Text'] != '') {
// Schüler mit offenen Aufgaben
}
else {
// Schüler ohne offene Aufgaben
}
}
Matthias
Hi,
Diese Abfrage liefert zunächst einmal alle Ergebnissätze Schüler - offene Aufgaben. Für die Schüler ohne offene Aufgaben schlägt das SELECT innerhalb von EXISTS fehl, weshalb dann Ergebnissätze
Name, Vorname, NULL, NULL
> entstehen, die sich in PHP von einander trennen lassen:
Und warum nicht gleich beim SQL rausschmeißen?
INNER statt LEFT JOIN. Oder " AND a.text IS NOT NULL" im WHERE- oder ON-Teil?
"Kreuztabelle" find ich als Tabellennamen seltsam.
Da würde ich doch eher was nehmen, was aussagt, welche Tabellen hier verbunden werden, also "schueler\_aufgaben" oder so.
Bei einer größeren DB hast Du sonst schnell Kreuztabelle17, Kreuztabelle42, ...
cu,
Andreas
--
[Warum nennt sich Andreas hier MudGuard?](http://MudGuard.de/)
[O o ostern ...](http://ostereier.andreas-waechter.de/)
Fachfragen per Mail sind frech, werden ignoriert. Das Forum existiert.
Om nah hoo pez nyeetz, MudGuard!
Und warum nicht gleich beim SQL rausschmeißen?
INNER statt LEFT JOIN. Oder " AND a.text IS NOT NULL" im WHERE- oder ON-Teil?
Weil ich beide Gruppen brauche (siehe OP) ;-)
"Kreuztabelle" find ich als Tabellennamen seltsam.
Da würde ich doch eher was nehmen, was aussagt, welche Tabellen hier verbunden werden, also "schueler_aufgaben" oder so.
Bei einer größeren DB hast Du sonst schnell Kreuztabelle17, Kreuztabelle42, ...
Das stimmt. Wollen wir mal hoffen, dass ich es nie mit einer größeren DB zu tun haben werde. Ich tu mich bei dieser schon recht schwer.
Matthias