Vraag Hoe doe je veel tot vele outer-joins op de tafel?


Ik heb 3 tabellen, foo, foo2bar en bar. foo2bar is een veel te veel kaart tussen foo en bar. Hier zijn de inhoud.

select * from foo
+------+
| fid  |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
+------+

select * from foo2bar
+------+------+
| fid  | bid  |
+------+------+
|    1 |    1 |
|    1 |    2 |
|    2 |    1 |
|    2 |    3 |
|    4 |    4 |
+------+------+

select * from bar
+------+-------+------+
| bid  | value | zid  |
+------+-------+------+
|    1 |     2 |   10 |
|    2 |     4 |   20 |
|    3 |     8 |   30 |
|    4 |    42 |   30 |
+------+-------+------+

Wat ik wil vragen is: "Geef me een lijst van alle fid en waarden met zid van 30"

Ik verwacht een antwoord voor alle fids, dus het resultaat zou er als volgt uitzien:

+------+--------+
| fid  | value  |
+------+--------+
|    1 |   null |
|    2 |      8 |
|    3 |   null |
|    4 |     42 |
+------+--------+

14
2017-12-16 19:30


oorsprong


antwoorden:


SELECT * FROM foo
  LEFT OUTER JOIN (foo2bar JOIN bar ON (foo2bar.bid = bar.bid AND zid = 30))
  USING (fid);

Getest op MySQL 5.0.51.

Dit is geen subquery, het gebruikt alleen haakjes om de prioriteit van joins te specificeren.


17
2017-12-16 19:39



SELECT * FROM
        foo LEFT JOIN
        (
        Foo2bar JOIN bar
             ON foo2bar.bid = bar.bid AND zid = 30
        )
        ON foo.fid = foo2bar.fid;

ongeteste


6
2017-12-16 19:36



Als u geen rij voor fid = 3 terugkrijgt, is uw server verbroken.

Deze code zou moeten doen wat ik denk dat je wilt:

SELECT
    F.fid,
    SQ.value
FROM
    dbo.Foo F
LEFT OUTER JOIN
     (
     SELECT F2B.fid, B.value
     FROM dbo.Bar B
     INNER JOIN dbo.Foo2Bar F2B ON F2B.bid = B.bid WHERE B.zid = 30
     ) SQ ON SQ.fid = F.fid

Houd er rekening mee dat het mogelijk is om twee waarden voor een fid terug te halen als deze betrekking heeft op twee balken met een spatie van 30.


2
2017-12-16 19:47



Als je het uitwerkt, kun je beginnen met je selectie. Voeg geen kolommen toe die u uiteindelijk niet wilt zien.

SELECT foo.fid, bar.value

Dan kunnen we de WHERE-clausule gebruiken, die u kunt zien, net zoals u het uitdrukte.

SELECT foo.fid, bar.value  
WHERE bar.zid = 30

Nu is het lastige deel om dingen met elkaar te verbinden voor onze FROM-component, met LEFT JOINs omdat we elke fid willen zien, ongeacht of er tussentijdse matches zijn:

SELECT foo.fid, bar.value  
FROM foo  
LEFT JOIN foo2bar ON foo.fid = foo2bar.fid  
LEFT JOIN bar ON foo2bar.bid = bar.bid  
WHERE bar.zid = 30
OR bar.zid IS NULL

2
2017-12-16 19:43



FWIW, de vraag gaat niet echt over een veel-op-veel: dit zou eenvoudigweg als een unie gedaan kunnen worden.

Een echte many-to-many in SQL is een CROSS JOIN


-1
2017-12-16 23:00