Entwickler-Ecke

Datenbanken - JOIN-Problem: Bestimmte Selektion sicherstellen


Narses - Do 20.05.10 22:53
Titel: JOIN-Problem: Bestimmte Selektion sicherstellen
Moin!

Ich habe da mal wieder ein (MySQL-)Problem, bei dem ihr mir sicher helfen könnt: ;)

Es gibt eine User-Tabelle, die ein paar Felder hat, hier reichen zunächstmal 2:
tuser.id: auotinc
tuser.email: Email-Adresse
etc.pp.

Dann gibt es eine Vorgangs-Tabelle:
tincident.id: autoinc
tincident.name: Vorgang
tincident.assigned: Benutzer, der dafür zuständig ist
etc.pp.

Und es gibt noch eine Nachrichten-Marker-Tabelle, die Benutzer markiert, die zu einem bestimmten Vorgang benachrichtigt werden wollen:
tnotify.id: autoinc
tnotify.incident_id: Vorgangs-Nr.
tnotify.user_id: User-Nr.

Sagen wir mal, der Vorgang Nr. 123 wird geändert, die Benutzer sollen benachrichtigt werden. An sich keine große Sache:

SQL-Anweisung
1:
2:
3:
SELECT tuser.email
FROM tnotify LEFT JOIN tuser ON tnotify.user_id = tuser.id
WHERE tnotify.incident_id = 123
Liefert brav, was es soll. :) (In der Praxis hole ich natürlich noch ein paar mehr Felder aus der User-Tabelle, nicht nur die Email)

Jetzt das "Problem": :hair:
Am Vorgang ist auch ein Benutzer hinterlegt, der für das Ding zuständig ist. Dieser soll immer eine Nachricht bekommen, egal ob er sie wünscht oder nicht. :P Gut, kann man mit einem UNION dranhängen, dann habe ich aber ggfs. zwei mal eine Nachricht gesendet, weil der Bearbeiter ja auch schon in der ersten Ergebnismenge enthalten sein könnte. :|

Wie knote ich jetzt diesen Bearbeiter in die Ergebnismenge rein, ohne diesen im Zweifel doppelt zu haben? :think: :nixweiss:

cu
Narses

//EDIT: Ich bemerke gerade beim Basteln an der Abfrage, dass UNION offenbar nur die Auswahl erweitert, der Datensatz kommt in der Ergebnismenge nicht doppelt vor, wenn ich das so abfrage: (User 3 hat einen Eintrag in tnotify und ist Bearbeiter)

SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
SELECT tuser.email
FROM tnotify LEFT JOIN tuser ON tnotify.user_id = tuser.id
WHERE tnotify.incident_id = 123
UNION 
SELECT tuser.email
FROM tuser
WHERE tuser.id = 3
Kann das sein? :gruebel: :?

//EDIT2:
MySQL-Hilfe zu UNION hat folgendes geschrieben:
Geben Sie das Schlüsselwort ALL an, dann enthält das Ergebnis alle passenden Datensätze aus allen SELECT-Anweisungen. Wenn Sie DISTINCT angeben, werden doppelte Datensätze aus dem Ergebnis entfernt. Wird kein Schlüsselwort benutzt, dann entspricht das Standardverhalten dem von DISTINCT (Entfernung doppelter Datensätze).
Scheint also per Default zu passen, ist ja witzig... :?
Schonmal jemand an dieser Stelle Erfahrungen gesammelt? Probleme gehabt? :nixweiss:


MarkusB - Fr 21.05.10 08:34

Moin Narses,

vielleicht so:


SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
SELECT tuser.email
FROM tnotify LEFT JOIN tuser ON tnotify.user_id = tuser.id
WHERE tnotify.incident_id = 123
  AND tuser.id <> 3         
UNION 
SELECT tuser.email
FROM tuser
WHERE tuser.id = 3


Grüß Markus
:?!?:


BenBE - Fr 21.05.10 12:29

Ohne USES auch so:


SQL-Anweisung
1:
2:
3:
SELECT tuser.email
FROM tincident, tuser LEFT JOIN tnotify ON (tnotify.user_id = tuser.id) OR (tuser.id = tincident.assigned)
WHERE tincident.id = tnotify.incident_id AND tnotify.incident_id = 123


Merke: Die LEFT-JOIN-Syntax ist im Wesentlichen syntaktischer Zucker :P

Oder halt ohne JOIN einfach über die WHERE abfackeln.


Narses - Fr 21.05.10 12:34

Moin!

user profile iconMarkusB hat folgendes geschrieben Zum zitierten Posting springen:
vielleicht so:
Das habe ich im Wesentlichen auch erst probiert, aber das scheint UNION schon direkt zu filtern (s.o.). :idea:


user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Ohne USES auch so:
Du meinst UNION? ;)

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:

SQL-Anweisung
1:
2:
3:
SELECT tuser.email
FROM tincident, tuser LEFT JOIN tnotify ON (tnotify.user_id = tuser.id) OR (tuser.id = tincident.assigned)
WHERE tincident.id = tnotify.incident_id AND tnotify.incident_id = 123
Das sieht spannend aus, muss ich mir gleich mal genauer reinziehen... :les:

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Merke: Die LEFT-JOIN-Syntax ist im Wesentlichen syntaktischer Zucker :P
Sieht aber hübsch aus... :schmoll:

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Oder halt ohne JOIN einfach über die WHERE abfackeln.
:?:

cu
Narses


BenBE - Fr 21.05.10 12:38

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Moin!

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Ohne USES auch so:
Du meinst UNION? ;)

Stimmt; vorhin grad aufgestanden ... Ist heut noch zu früh ^^

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:

SQL-Anweisung
1:
2:
3:
SELECT tuser.email
FROM tincident, tuser LEFT JOIN tnotify ON (tnotify.user_id = tuser.id) OR (tuser.id = tincident.assigned)
WHERE tincident.id = tnotify.incident_id AND tnotify.incident_id = 123
Das sieht spannend aus, muss ich mir gleich mal genauer reinziehen... :les:

k.

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Merke: Die LEFT-JOIN-Syntax ist im Wesentlichen syntaktischer Zucker :P
Sieht aber hübsch aus... :schmoll:

Man sollte auch wissen, was dahinter steht ;-)

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Oder halt ohne JOIN einfach über die WHERE abfackeln.
:?:

cu
Narses

Für user profile iconNarses heute ein Beispiel GANZ ohne LEFT JOIN:


SQL-Anweisung
1:
2:
3:
4:
5:
SELECT tuser.email
FROM tincident, tuser, tnotify
WHERE ((tnotify.user_id = tuser.id) OR (tuser.id = tincident.assigned)) 
AND (tincident.id = tnotify.incident_id) 
AND (tnotify.incident_id = 123)


Narses - Sa 22.05.10 10:16

Moin!

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:

SQL-Anweisung
1:
2:
3:
SELECT tuser.email
FROM tincident, tuser LEFT JOIN tnotify ON (tnotify.user_id = tuser.id) OR (tuser.id = tincident.assigned)
WHERE tincident.id = tnotify.incident_id AND tnotify.incident_id = 123
Das sieht spannend aus, muss ich mir gleich mal genauer reinziehen... :les:

k.
Klappt nicht:
MySQL-Server hat folgendes geschrieben:
#1054 - Unknown column 'tincident.assigned' in 'on clause'
:|

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:

SQL-Anweisung
1:
2:
3:
4:
5:
SELECT tuser.email
FROM tincident, tuser, tnotify
WHERE ((tnotify.user_id = tuser.id) OR (tuser.id = tincident.assigned)) 
AND (tincident.id = tnotify.incident_id) 
AND (tnotify.incident_id = 123)
Liefert den zuständigen Menschen doppelt in der Ergebnismenge.

Scheint noch etwas buggy, oder? :zwinker:

Fazit: Das UNION oben tut´s, wenn kein überragend guter Vorschlag mehr kommt, bleibt´s auch so. ;)

cu
Narses


MarkusB - So 23.05.10 06:54

Moin!

Noch ein Versuch:


SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
SELECT tuser.email
FROM tuser, tnotify 
WHERE tuser.id = tnotify.user_id
  AND tnotify.incident_id = 123
UNION DISTINCT
SELECT tuser.email
FROM tuser, tincident 
WHERE tuser.id = tincident.assigned
  AND tincident_id = 123


Viele Grüße
Markus
:?!?:


BenBE - So 23.05.10 12:33

@Narses: Du hättest auch bei meiner Variante einfach nur nach dem Select ein DISTINCT schreiben brauchen; obwohl mich das etwas wundert, woher der Doppelte dort kommt.


Narses - So 23.05.10 13:45

Moin!

user profile iconMarkusB hat folgendes geschrieben Zum zitierten Posting springen:
Noch ein Versuch:
Danke für deinen Einsatz. :zustimm: Aber lies doch nochmal bitte meinen ersten Beitrag, besonders die beiden Nachträge. Im Wesentlichen habe ich es jetzt schon so, nur dass man den zuständigen Menschen nicht aus der ersten Menge rausnehmen muss, dass macht das UNION schon defaultmäßig. ;) :idea:


user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
@Narses: Du hättest auch bei meiner Variante einfach nur nach dem Select ein DISTINCT schreiben brauchen; obwohl mich das etwas wundert, woher der Doppelte dort kommt.
Ja, das ist schon klar. ;) Den Preis gibt´s aber nur für eine Lösung OHNE UNION und OHNE DISTINCT (also für eine "flache" Abfrage). :mrgreen:

cu
Narses