2010-10-26 15 views
6

Ich habe mehrere Tabellen mit einer unterschiedlichen Anzahl und Arten von Spalten und einer einzigen Spalte gemeinsam.Wie kombiniere ich Ergebnisse aus mehreren Tabellen mit verschiedenen Spalten?

+--------+---------+------------+-------------+ 
| person | beardID | beardStyle | beardLength | 
+--------+---------+------------+-------------+ 

+--------+-------------+----------------+ 
| person | moustacheID | moustacheStyle | 
+--------+-------------+----------------+ 

Ich möchte alle Ergebnisse abrufen, die einen bestimmten Wert der gemeinsamen Spalte entsprechen. Ich kann es mehrere select-Anweisungen wie folgt aus:

SELECT * FROM beards WHERE person = "bob" 

und

SELECT * FROM moustaches WHERE person = "bob" 

Aber dies erfordert mehrere MySQL-API-Aufrufe, die ineffizient zu sein scheint. Ich hatte gehofft, ich könnte UNION ALL verwenden, um alle Ergebnisse in einem einzigen API-Aufruf zu erhalten, aber UNION verlangt, dass die Tabellen die gleiche Nummer und den gleichen Typ von Spalten haben. Ich konnte eine SELECT-Anweisung schreiben, würde manuell Pad die Ergebnisse aus jeder Tabelle durch Spalten mit NULL-Werte hinzufügen, aber das schnell unhandlich für ein paar Tabellen mit ein paar mehr Spalten bekommen würde.

Ich suche ein Ergebnis ungefähr so ​​gesetzt:

+--------+---------+------------+-------------+-------------+----------------+ 
| person | beardID | beardStyle | beardLength | moustacheID | moustacheStyle | 
+--------+---------+------------+-------------+-------------+----------------+ 
| bob | 1  | rasputin | 1   |    |    | 
+--------+---------+------------+-------------+-------------+----------------+ 
| bob | 2  | samson  | 12   |    |    | 
+--------+---------+------------+-------------+-------------+----------------+ 
| bob |   |   |    | 1   | fu manchu  | 
+--------+---------+------------+-------------+-------------+----------------+ 

Gibt es eine Möglichkeit, dies zu erreichen, die schnell und wartbar ist? Oder mache ich lieber eine separate Abfrage für jede Tabelle?

Klarstellung:

Ich bin nicht auf der Suche nach einem kartesischen Produkt. Ich will keine Reihe für jede Kombination von Bart und Schnurrbart, ich will eine Reihe für jeden Bart und eine Reihe für jeden Schnurrbart.

Also, wenn es 3 passende Bärte und 2 passenden Schnurrbärte sind sollte ich 5 Reihen bekommen, nicht 6.

+1

Während es in den meisten Datenbanken mit einem 'FULL JOIN' gemacht werden konnte, und in MySQL mit ITroubs 'Workaround, bezweifle ich ernsthaft, ob es einen signifikanten Leistungsgewinn gibt, und wahrscheinlich erstellen Sie nur einen Chaos von obskurem Code, dem Ihr Nachfolger Ihnen nicht danken wird. Klarer und präziser Code überwiegt in den meisten Fällen einen Leistungsgewinn in den sehr niedrigen Prozentsätzen. – Wrikken

Antwort

7

dies sollte in Ordnung arbeiten werden. die linke und rechte äußere Verbindung machen diese Arbeit. Leider hat mysql keinen vollständigen Join. das ist, warum Sie es auf diese Art und Weise zu tun, mit einer Gewerkschaft haben

SELECT * FROM `customer` b LEFT OUTER JOIN `charges` ON (0) LEFT OUTER JOIN `day` ON (0) 
UNION 
SELECT * FROM `customer` b RIGHT OUTER JOIN `charges` ON (0) LEFT OUTER JOIN `day` ON (0) 
UNION 
SELECT * FROM `customer` b LEFT OUTER JOIN `charges` ON (0) RIGHT OUTER JOIN `day` ON (0) 

dies ist ein lokaler Test i

gemacht
+1

Brilliant, wirkt wie ein Zauber. Wenn ich also richtig verstehe, verwenden Sie LEFT und RIGHT OUTER JOINs, ohne die Join-Kriterien anzugeben, um Spalten mit NULL-Werten zu den Ergebnissen jeder Tabelle hinzuzufügen (damit die Ergebnismengen übereinstimmende Tabellen enthalten), und dann die Ergebnisse zu vereinheitlichen. – Robert

+2

ja. Die Joins sind nur um sicherzustellen, dass Ihr Ergebnis alle Spalten für Bärte und Schnurrbärte hat. Wenn Sie die ON-Anweisung falsch machen, gibt es nur alle Linien von Bärten oder Schnurrbärten zurück. – ITroubs

+0

Um eine dritte Tabelle hinzuzufügen, würde ich ein Extra hinzufügen OUTER JOIN ON (0) zu jedem dieser SELECTs für die neue Tabelle, plus UNION ALL und eine neue Select-Anweisung OUTER JOINING die neue Tabelle zu diesen beiden Tabellen auf die gleiche Weise. – Robert

0

auf Person Mitglied werden ....

D.h.

Select t1. (Asterix), t2. (Asterix) VON Bärte t1 INNER Schnurrbärte T2 t2.person JOIN = t1.person

+0

Haben Sie das versucht? INNER JOIN ruft das kartesische Produkt der übereinstimmenden Datensätze aus den beiden Tabellen ab. Also ein Ergebnis für jede Kombination von Bart und Schnurrbart. Nicht, was in der Frage überhaupt beschrieben wird. – Robert

+0

@Robert: Nein, ein INNER JOIN produziert kein kartesisches Produkt. –

+0

Entschuldigung, ich verstehe JOINs nicht sehr gut. Was ist der Unterschied zwischen INNER JOIN und dem kartesischen Produkt und der Filterung der Beitrittskriterien? – Robert

0
SELECT * 
FROM beards 
     JOIN moustaches 
     ON moustaches.person = beards.person 
WHERE person = "bob" 
+0

Ich suche eine Reihe für jeden Bart und eine Reihe für jeden Schnurrbart, keine Reihe für jeden Bart und Schnurrbart. – Robert

0

Ich hatte Spaß mit diesem, nicht Sicher, es ist völlig überschaubar mit was man hinzufügen muss, aber es hat das Ziel erreicht.

SELECT * FROM `beards` b LEFT OUTER JOIN `mustaches` ON (0) WHERE person = "bob" 
UNION ALL 
SELECT * FROM `beards` b RIGHT OUTER JOIN `mustaches` ON (0) WHERE person = "bob" 

Sie selbst die Spalten nicht behandeln müssen:

create table beard (
person varchar(20) 
,beardID int 
,beardStyle varchar(20) 
,beardLength int) 

create table moustache(
person varchar(20) 
,moustacheID int 
,moustacheStyle varchar(20)) 


insert into beard 
select 'bob', 1, 'rasputin', 1 
union select 'bob', 2, 'samson', 12 

insert into moustache 
select 'bob', 1, 'fu manchu' 

declare @facialhair table (
person varchar(20) 
,beardID int 
,beardStyle varchar(20) 
,beardLength int 
,moustacheID int 
,moustacheStyle varchar(20)) 

declare @i int 
declare @name varchar(20) 

set @name = 'bob' 
set @i = (select COUNT(*) from beard where person = @name) 
     + (select COUNT(*) from moustache where person = @name) 

print @i 

while @i > 0 
    begin 
     insert into @facialhair (person, beardID, beardStyle, beardLength) 
     select person, beardID, beardStyle, beardLength 
     from beard 
     where person = @name 
    set @i = @[email protected]@ROWCOUNT 

     insert into @facialhair (person, moustacheID, moustacheStyle) 
     select person, moustacheID, moustacheStyle 
     from moustache 
     where person = @name 
    set @i = @[email protected]@ROWCOUNT 
    end 

select * 
from @facialhair 
0

Ich glaube, Sie in jeder Tabelle, indem sie Abfragen für Daten besser wären.Eine andere Möglichkeit besteht darin, Daten aus allen Spalten zu einer großen Zeichenfolge zu verketten (Sie könnten ein Zeichen zum Trennen der Spaltenwerte wählen), dann sollten Sie die Klausel all allow verwenden können, um Ergebnisse aus jeder Abfrage zu kombinieren - aber dann Sie müssen jede Zeile analysieren. Und Datentypen gehen verloren.

+0

und Hauptnachteil wäre Overhead der Berechnung und eine begrenzte Stringgröße, die mysql für group_concat! Sieh dir meine Lösung an. Ich denke, das wäre der einfachste Weg. – ITroubs

+0

@ ITroubs: nette Lösung, die ich sagen sollte – rsc

Verwandte Themen