2015-07-10 9 views
6

Mi sono imbattuto in qualcosa di strano con join esterni a sinistra su più chiavi in ​​BigQuery. Se una delle chiavi è null nella tabella di destra, non corrisponde e pertanto inserisce null in tutti i valori per la tabella corretta.Un join esterno a sinistra in BigQuery su più chiavi non avviene se uno di questi è nullo

Se ho 2 tabelle

Table1    Table2 
------------  ---------------- 
k1 |k2 |v3  k1 |k2 | v4 
------------  ---------------- 
foo|boo |hey  foo|NULL| you 
bar|test|yo  bar|test| hi 
foo|NULL|hey 

e mi unisco il seguente

SELECT t1.k1, t1.k2, t1.v3, t2.v4 FROM [Table1] t1 
LEFT OUTER JOIN EACH [Table2] t2 
ON t1.k1=t2.k1 AND t1.k2=t2.k2 

ottengo un risultato come questo

t1_k1|t1_k2|t1_v3|t2_v4 
----------------------- 
foo |boo |hey |NULL --No match here so NULL in t2_v4 it's ok 
bar |test |hey |hi --It matches here on bar and test 
foo |NULL |hey |NULL --It doesn't match on foo NULL. 

mi aspetterei che l'ultima riga era

foo |NULL |hey |you 

È questo il comportamento previsto? Con questo intendo non ci sono corrispondenze su NULL.

C'è qualche altro modo di produrre il risultato che voglio?

+0

Alcuni altri SQL hanno "NON È DISTINTIVO DA", ma BigQuery non ce l'ha. Vedi di più su "Come riscrivere IS DISTINCT FROM e NON DISTINTIVO DA?" http://stackoverflow.com/questions/10416789/how-to-rewrite-is-distinct-from-and-is-not-distinct-from –

risposta

6

In SQL, NULL non è uguale a niente, nemmeno a se stesso.

Gordon's answer ha alcuni suggerimenti ragionevoli, ma si noti che BigQuery supporta solo aderire a condizioni che sono congiunzioni di uguaglianze, che esclude l'uso di OR o IS NULL.

È possibile utilizzare un valore sentinella diverso da null? Ad esempio, se si sostituisce NULL con la stringa vuota (o la stringa "null" o qualcos'altro che non si verifica altrove nei dati), il join funzionerà come previsto. Puoi persino farlo al volo usando una subquery, a un costo di prestazioni minimo.

SELECT t1.k1, t1.k2, t1.v3, t2.v4 
FROM 
    (SELECT IFNULL(k1, "null") k1, IFNULL(k2, "null") k2 FROM [Table1]) t1 
LEFT OUTER JOIN EACH 
    (SELECT IFNULL(v3, "null") v3, IFNULL(v4, "null") v4 FROM [Table2]) t2 
ON t1.k1 = t2.k1 AND t1.k2 = t2.k2 

è possibile aggiungere un esterno di selezione per trasformare la stringa "null" di nuovo in un vero e proprio NULL.

Ovviamente questo funziona solo se la stringa "null" non si verifica altrove nei dati.

1

Questo è un comportamento standard. Un metodo per risolvere il problema è quello di rendere la clausola join più complicato:

SELECT t1.k1, t1.k2, t1.v3, t2.v4 
FROM [Table1] t1 LEFT OUTER JOIN EACH 
    [Table2] t2 
    ON (t1.k1 = t2.k1 OR (t1.k1 is null and t2.k1 is null)) AND 
     (t1.k2 = t2.k2 OR (t1.k2 is null and t2.k2 is null)) 

questo potrebbe avere un impatto negativo sulle prestazioni. Alcuni database hanno un'operazione di uguaglianza nulla sicura che può essere utilizzata, ma non credo che BigQuery supporti questo.

Quindi, il miglior consiglio è quello di correggere i dati in modo che NULL non sia un valore di chiave valido. Altrimenti, puoi utilizzare più join. Se tu avessi un solo join chiave, sarebbe simile

SELECT t1.k1, t1.k2, t1.v3, coalesce(t2.v4, t2null.v4) 
FROM [Table1] t1 LEFT OUTER JOIN EACH 
    [Table2] t2 
    ON t1.k1 = t2.k1 LEFT OUTER JOIN EACH 
    [Table2] t2null 
    ON (t1.k1 is null and t2.k1 is null) ; 

Tuttavia, questo è più difficile da mettere insieme per compositi join chiavi.