2014-03-27 20 views
0

我有一個包含生產數據的表Prod。在Prod,A和B中有兩個字段用作鍵(這兩個字段都是VARCHAR)。我有另一張桌子,Stage,我想導入到Prod中。但是,在導入Stage之前,我想檢查Stage是否有已經在Prod中的行。任何重複的行都將從導入中排除。Postgres SQL在使用並置(||)運算符時不返回預期的行

我的問題是:

當我運行一個查詢,如

SELECT A, B 
FROM Stage 
WHERE A || B NOT IN (
    SELECT A || B 
    FROM Prod 
) 

我期望我會接受所有非重複的(新)項的列表。但是,我沒有收到任何結果。

而且,當我運行

SELECT A, B 
FROM Stage 
WHERE A || B IN (
    SELECT A || B 
    FROM Prod 
) 

其中唯一的區別是變化NOT ININ,我只接收表的子集返回什麼,我會希望是整個表來代替。

我知道這個問題有什麼做的級聯(||)運算符,因爲當我運行返回

SELECT A 
FROM Stage 
WHERE A NOT IN (
    SELECT A FROM Prod 
) 

行和IN版本的查詢返回剩餘行。

有沒有人有任何想法?

+0

「Stage」和「Prod」中的'A'和'B'類型是什麼? –

+2

你應該使用'where(a,b)not in(select a,b ...)'。級聯會導致錯誤,因爲'abc'可能意味着'a,bc'或'ab,c'。如果'a'或'b'可以爲null,那麼'not in'不會返回任何東西,如果至少有一行其中一個是'null' –

+0

@ClodoaldoNeto A和B在生產中也是VARCHAR – zgall1

回答

1

你的說法有兩個問題:

第一:使用字符串連接不會像您期望的,因爲比較不能元組('a','bc')('ab','c')之間的區別(因爲兩者都會導致相同的級聯值繼續工作。

使用真正的元組進行比較是正確的做法:

where (a,b) not in (select a,b ...) 

現在到了第二個問題:

A NOT IN比較其中「比較列表」包含NULL將始終返回空結果,因爲與null的任何比較產生「未知」,因此數據庫無法可靠地確定「左手邊」的值是否在該列表中或不。

你寫使用:SELECT A FROM Stage WHERE A NOT IN (SELECT A FROM Prod)回報的東西,這意味着在prod.a但顯然在prod.b沒有null值。

如果你想忽略null值,您可以使用這樣的事情:

select a,b 
from stage 
where (a,b) not in (select a,b 
        from prod 
        where b is not null); 

另一種選擇是治療null有別的事情,例如一個空字符串:

select a,b 
from stage 
where (a,coalesce(b, '')) not in (select a, coalesce(b, '') 
            from prod); 

當使用in操作,所以

select a,b 
from stage 
where (a,b) in (select a,b 
       from prod); 

使用安全,即使null值不會發生此問題。

但是,如果您將這兩列用作「鍵」,則首先不應允許其中的null值。

順便說一句:這不是特定於Postgres的東西,這是一般SQL工作的方式。