2017-05-04 105 views
4

這個查詢:BigQuery的標準SQL查詢返回一個錯誤的答案

SELECT x 
FROM dataset.table_a 
WHERE x NOT IN (SELECT x FROM dataset.table_b) 

返回零記錄,即使:

  • xtable_a包含1326932不同的字符串值

  • xtable_b中包含18,885個不同的字符串值

我不明白爲什麼。而且,在BigQuery遺留SQL中,此查詢返回正確的答案。

+0

你可以給數據的例子嗎?它是否填充?如果您將NOT IN更改爲IN,您會得到什麼結果? –

+0

遷移指南現在已更新爲[記錄傳統和標準SQL之間的區別](https://cloud.google.com/bigquery/docs/reference/standard-sql/migrating-from-legacy-sql#not_in_conditions_and_null) 。 –

回答

3

我懷疑我知道答案 - 這是由於NOT IN在使用傳統SQL時與NULL相關的錯誤處理,而標準SQL的行爲與SQL標準一致。有一個documentation bug open for this to add it to the migration guide,但它尚未解決。

在文檔(https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#in-operators)規定:

與在IN-list中的NULL只能返回TRUE或NULL,決不會爲假

可以實現與期望的行爲此查詢使用NOT EXISTS代替:

SELECT x 
FROM dataset.table_a AS t 
WHERE NOT EXISTS (
    SELECT 1 FROM dataset.table_b 
    WHERE t.x = x 
); 
+0

謝謝你的回答。在我看來,這條規則似乎是這樣的: 「IN與NULL在IN列表中只能返回TRUE或NULL,從不FALSE」 是邏輯錯誤,是不是?例如,'aa'IN ['bb',NULL]在邏輯上應該返回FALSE? – gus87

+0

它等同於'aa'='bb'或'aa'= NULL,這會導致NULL。試試這個:'SELECT'aa'='bb'或'aa'=(SELECT CAST(NULL as STRING))'。 –

3

要最小化原始查詢中的更改,您可以只添加WHERE NOT x IS NULL如下

#standardSQL 
SELECT x 
FROM `dataset.table_a` 
WHERE x NOT IN (SELECT x FROM `dataset.table_b` WHERE NOT x IS NULL) 

另外,我建議增加DISTINCT如下優化了一點

#standardSQL 
SELECT x 
FROM `dataset.table_a` 
WHERE x NOT IN (SELECT DISTINCT x FROM `dataset.table_b` WHERE NOT x IS NULL)