2009-06-10 16 views
5

Ich habe drei Tabellen:Verbinden einer Tabelle mehrmals mit anderen Tabellen

Tabelle Benutzer (Benutzer-ID Benutzername)

Tabelle Key (userid keyid)

Tabelle Laptop (userid laptopid)

Ich möchte alle Benutzer, die entweder einen Schlüssel oder einen Laptop oder beides haben. Wie schreibe ich die Abfrage, so dass es eine Verknüpfung zwischen Tabelle Benutzer und Tabelle Schlüssel sowie eine Verknüpfung zwischen Tabelle Benutzer und Tabelle Laptop verwendet?

Das Hauptproblem besteht darin, dass in dem aktuellen Szenario gibt es zwölf oder so schließt sich Tisch, etw wie:

"wählen .. Von einem LEFT JOIN b auf (...), c d kommt auf (..), e, f, g, wo ... ",

und ich sehe, dass a bis b verbunden sein könnte, und ein auch f verbunden werden könnte. Unter der Annahme, dass ich die Tabellen a, b und f nicht nebeneinander aufstellen kann, wie schreibe ich die SQL-Abfrage?

+0

Jeder Benutzer muss Schlüssel oder Laptop haben. Recht? –

+0

du magst recht haben, könnte falsch sein, aber so total egal! immer noch Spaß, aber :) – umar

+0

F1: möchten Sie nur Benutzer (userid) oder auch wissen, was genau hatten sie? F2: Kann ein Benutzer mehr als ein Element eines Typs (2 Laptops oder 3 Schlüssel) haben? – van

Antwort

1
select distinct u.userid, u.username 
from User u 
    left outer join Key  /* k on u.userid = k.userid */ 
    left outer join Laptop /* l on u.userid = l.userid */ 
where k.userid is not null or l.userid is not null 

EDIT "Das Hauptproblem besteht darin, dass in dem aktuellen Szenario gibt es zwölf oder so Tabellen-Joins, etw wie: " wählen .. Aus einem LEFT JOIN b auf (...) , c d auf (..), e, f, g, wo ... ", und ich sehe kommen, dass eine b verbunden sein könnte, und ein auch f verbunden sein könnte. Also vorausgesetzt, ich nicht das machen kann Die Tabellen a, b und f erscheinen Seite an Seite. Wie schreibe ich die SQL-Abfrage? "

Sie verbindet so viele linke äußere haben je nach Bedarf. Verbinden Sie die Tabelle mit dem Primärschlüssel für den Rest der Tabellen oder auf einem anderen Feld, in dem Feldwert einer Tabelle soll Feldwert von anderer Tabelle übereinstimmen.

zB erklärt, besser als Worte

select * 
from a 
left outer join b on a.pk = b.fk -- a pk should match b fk 
left outer join c on a.pk = c.fk -- a pk should match c fk 
left outer join d on c.pk = d.fk -- c pk should match d fk 

und so weiter

+0

Ich beendete die Frage zu zeigen, meine Hauptschwierigkeit ist nicht in der Lage, die drei Tabellen Seite an Seite erscheinen, mit so etwas wie vollständige Tabelle Joins (ich meine: "von c, d" etc) zwischen – umar

+0

Edited ans als per ur editiert Q –

+1

Sie vermissen immer noch eine Where-Klausel wie "where k.userid ist nicht null oder l.userid ist nicht null" in Ihrer ersten Antwort, um die Benutzer ohne etwas herauszufiltern. –

9

Sie mehrere verwenden können, schließt sich mehrere Tabellen kombinieren:

select * 
from user u 
left join key k on u.userid = k.userid 
left join laptop l on l.userid = u.userid 

A "LEFT JOIN" findet auch Benutzer die keinen Schlüssel oder Laptop haben. Wenn Sie beide durch "innere Verbindung" ersetzen, würde es nur Benutzer mit einem Laptop und einem Schlüssel finden.

Wenn ein „join links“ keine Zeile finden, es in seinen Feldern NULL zurück. So können Sie alle Benutzer auswählen, die entweder einen Laptop oder einen Schlüssel wie dieses:

select * 
from user u 
left join key k on u.userid = k.userid 
left join laptop l on l.userid = u.userid 
where k.userid is not null or l.userid is not null 

NULL ist etwas Besonderes, dass Sie es wie vergleichen „Feld ist nicht null“ anstelle von „Feld <> null“.

Nach Ihrem Kommentar hinzugefügt: Sagen Sie, Sie haben eine Tabelle Maus, die zu Laptop, aber nicht zu Benutzer verwandt ist. Sie können diese wie beitreten:

select * 
from user u 
left join laptop l on l.userid = u.userid 
left join mouse m on m.laptopid = l.laptopid 

Wenn dies nicht Ihre Frage nicht beantworten, muss man es etwas mehr klären.

+0

ich denke das letzte u.userid sollte k.userid sein –

+0

yeah! Es ist die richtige Antwort wie meine Antwort. +1 –

+0

Entschuldigung dafür, dass ich die Frage vorher nicht geklärt habe: Ich habe der Frage weitere Details hinzugefügt, so dass Ihre Antwort mein Problem anscheinend nicht löst – umar

1

Wie Sie den Fall beschrieben, Sie wollten nur wissen, ob jemand einen Laptop oder einen Schlüssel hat.Ich würde die Abfrage mit einer Unterabfrage schreiben, anstatt ein Join:

select * 
from user 
where userid in (select userid from key union select userid from laptop) 

Der Grund dafür ist, durch ein, dass eine Person mit mehreren Laptops oder mehreren Tasten anschließen wird mehrmals aufgeführt werden (es sei denn, Sie distinct verwenden). Und selbst wenn Sie distinct verwenden, erhalten Sie eine weniger effiziente Abfrage (zumindest auf Oracle scheint der Abfrageoptimierer nicht in der Lage zu sein, einen effizienten Plan zu erstellen).

+1

Es wird kein Cross-Join sein, wenn Sie den linken äußeren Join angeben. Der linke äußere Join ist schneller als die Unterabfrage. –

+0

Ich habe es schnell in einer Oracle-Datenbank ausprobiert: Du hast recht, es verursacht keinen Cross-Join. Aber es war auch nicht schneller als die Unterabfrage-Methode - tatsächlich mehr als doppelt so langsam. – waxwing

+0

Ich möchte sehr wenig Änderung an der Abfrage außer dem Hinzufügen von mehr JOIN und ON-Klauseln machen, so dass ich jetzt nach einer Möglichkeit suche, es ohne Unterabfragen zu tun. Ich bin nicht sicher abt Oracle, aber ich habe im Allgemeinen gehört, dass Joins sind schneller als Sub-Abfragen ... vielleicht für große Menge an Daten – umar

0
SELECT * 
FROM User 
LEFT JOIN Key ON User.id = Key.user_id 
LEFT JOIN Laptop ON User.id = Laptop.user_id 
WHERE Key.id IS NOT NULL OR Laptop.id IS NOT NULL 
0

Lösung ein [Bearbeitet zu korrigieren, was Rashmi Pandit hingewiesen.]:

SELECT * FROM [User] u 
INNER JOIN [Key] k 
ON u.userid = k.userid 

UNION 

SELECT * FROM [User] u 
INNER JOIN Laptop l 
ON u.userid = l.userid 

[...] 

Lösung zwei:

SELECT * FROM [User] u 
LEFT JOIN [Key] k 
ON u.userid = k.userid 
LEFT JOIN Laptop l 
ON u.userid = l.userid 
LEFT JOIN [...] 
WHERE k.userid IS NOT NULL 
OR l.userid IS NOT NULL 
OR [...] 

Nur eine Vermutung, überprüfen Sie könnten auch der Ausführungsplan für diese zwei, um zu sehen, ob die UNION schwerer ist oder umgekehrt.

2
-- // Assuming that a user can have at max 1 items of each type 
SELECT  u.* 
-- // Assuming that a user can have more then 1 items of each type, just add DISTINCT: 
-- // SELECT  DISTINCT u.* 
FROM  "User" u 
LEFT JOIN "Key" u1 ON u.UserID = u1.UserID 
LEFT JOIN "Laptop" u2 ON u.UserID = u2.UserID 
LEFT JOIN "Server" u3 ON u.UserID = u3.UserID 
-- // ... 
WHERE  COALESCE(u1.UserID, u2.UserID, u3.UserID /*,...*/) IS NOT NULL 
+0

+1 interessante Verwendung von coalesce :) – Andomar

Verwandte Themen