2010-09-23 11 views
16

Ho tre tabelle: R, S e P.SQL che unisce tre tabelle, unire precedenza

Tabella R Si unisce con S attraverso una chiave esterna; ci dovrebbe essere almeno un record in S, quindi mi possono aderire:

SELECT 
     * 
    FROM 
     R 
    JOIN S ON (S.id = R.fks) 

Se c'è nessun record in S allora ottengo nessuna riga, va bene.

Poi tavolo S unisce con P, in cui record è P possono o non possono essere presenti e uniti con S.

Così faccio

SELECT 
     * 
    FROM 
     R 
    JOIN S ON (S.id = R.fks) 
    LEFT JOIN P ON (P.id = S.fkp) 

E se io volessi il secondo si uniscono per essere legato a S non R, come se potessi utilizzare le parentesi:

SELECT 
     * 
    FROM 
     R 
    JOIN (S ON (S.id = R.fks) JOIN P ON (P.id = S.fkp)) 

O è già un comportamento naturale del prodotto cartesiano tra R, S e P?

+0

Puoi approfondire questa parte "E se volevo il secondo si uniscono per essere legato a S non R" In questo momento le tabelle vengono unite come R unendosi con S e poi a sinistra unirsi a P. –

+0

sto cercando per capire se c'è un modo in cui posso dare la precedenza ai join, come se fossero operatori aritmetici. Non capisco se questo è implicito nella condizione di join o meno. – vulkanino

+0

Dai a noi un esempio di dati di ciò che speri di ottenere è diverso da un comune join e possiamo mostrarti meglio cosa fare. È possibile che una tabella derivata possa fare ciò che vuoi, ma non sono sicuro di quello che vuoi. – HLGEM

risposta

26

Tutti i tipi di join esterni e normali si trovano nella stessa classe di precedenza e gli operatori hanno effetto da sinistra a destra a un determinato livello di nidificazione della query. Puoi mettere l'espressione di join sul lato destro tra parentesi per far sì che abbia effetto prima; ricorda solo che devi spostare la clausola ON del join che ora si trova al di fuori del join su cui mettere i parens.

(PostgreSQL esempio)

In SELECT * FROM a LEFT JOIN b ON (a.id = b.id) JOIN c ON (b.ref = c.id);

l'ab unirsi avrà effetto prima, ma siamo in grado di forzare il bc join abbia effetto prima facendo:

SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);

Spesso si può esprimere la stessa cosa senza parentesi extra spostando i join e cambiando la direzione del join esterno, ad es

SELECT * FROM b JOIN c ON (b.ref = c.id) RIGHT JOIN a ON (a.id = b.id);

+1

Un chiarimento: tutti gli operatori di join hanno la stessa precedenza e tutti hanno associatività da sinistra a destra. Questo è il modo in cui gli operatori di sottrazione (-) e divisione (/) funzionano praticamente in tutti i linguaggi di programmazione. La modifica dell'ordine degli operandi non ha alcun effetto sulla sua "precedenza" (un aspetto della grammatica SQL e non dell'operando in ogni caso). Facendo ciò si utilizza l'associatività da sinistra a destra del join per ottenere una semantica desiderata dei join compositi. Ma non cambia né la precedenza né l'associatività di qualcosa nell'espressione - solo il suo contesto interpretativo. –

+0

Abbastanza giusto. Qual è una seconda parola che trasmette l'effetto di un operatore che precede l'effetto di un altro operatore, ma non la precedenza perché è già stata presa? – rakslice

+0

Riformato. Inoltre, per quanto odio fare un passo sul gergo di qualcuno usandolo per la sua definizione di dizionario (no, non lo faccio), ciò che veramente macina i miei ingranaggi è qualcosa come "associatività" dove la parola gergale è una terminologia matematica che è stata appropriata dal mondo informatico. – rakslice

1

La seconda join è legato a S, come si esplicitamente stato JOIN P ON (P.id = S.fkp) - nessuna colonna da R viene fatto riferimento nel join.

+0

ok, ma non c'è modo, in generale, di dare la precedenza ai join? – vulkanino

+0

Non penso che SQL funzioni nel modo in cui stai pensando. La risposta di Paul Spangle descrive come SQL "pensa" ai join. –

2

Quando si uniscono la terza tabella, la vostra prima query

SELECT 
     * 
    FROM 
     R 
    JOIN S ON (S.id = R.fks) 

è come una tabella derivata a cui ci si sta unendo la terza tabella. Pertanto, se R JOIN S non produce righe, l'unione di P non genererà mai righe (perché stai tentando di accedere a una tabella vuota).

Quindi, se stai cercando le regole di precedenza, in questo caso è impostato semplicemente utilizzando LEFT JOIN anziché JOIN.

Tuttavia, potrei essere frainteso la tua domanda, perché se stavo scrivendo la query, vorrei scambiare S e R in giro. per esempio.

SELECT 
     * 
    FROM 
     S 
    JOIN R ON (S.id = R.fks) 
+0

considera di dover unire 3 tabelle, non 2. – vulkanino

+1

Funziona solo da sinistra a destra. L'unico modo per aggirarlo è quello di inserire un'intera tabella derivata in alcune parentesi. –

1

Non c'è precedenza per join, è operazione associativa. La vecchia sintassi separata da virgole lo rendeva chiaro, il nuovo (che presumibilmente è cucinato per imitare l'algebra relazionale) è fonte di confusione. I join esterni (usati da soli o insieme a join regolari), tuttavia, non sono associativi.

+3

Considerando che OP chiede di LEFT JOINS l'affermazione che JOINS è associativo è semplicemente fuorviante. – Taemyr

0
with a as (select 1 as test union select 2) 
select * from a left join 
a as b on a.test=b.test and b.test=1 inner join 
a as c on b.test=c.test 
go 
with a as (select 1 as test union select 2) 
select * from a inner join 
a as b on a.test=b.test right join 
a as c on b.test=c.test and b.test=1 

Idealmente, ci auguriamo che queste due domande sono le stesse. Tuttavia, non lo sono, quindi chiunque affermi che un join destro può essere sostituito con un join sinistro in tutti i casi è sbagliato. Solo utilizzando il join giusto possiamo ottenere il risultato richiesto.

+1

i join giusti non hanno nulla a che fare con questa domanda e nessuno sta dicendo che sono uguali. – Hogan

Problemi correlati