2015-03-31 35 views
1

我有這個表:PostgreSQL的多個元組選擇在WHERE子句

create table myTable (keyword text, category text, result text 
        , primary key (keyword,category)); 

insert into myTable values 
    ('foo',  'A', '10'), 
    ('bar',  'A', '200'), 
    ('baz',  'A', '10'), 
    ('Superman', 'B', '200'), 
    ('Yoda',  'B', '10'), 
    ('foo',  'C', '10'); 

我想根據元組(keyword,category)檢索結果。所以基本上,有一個簡單的元組我有以下查詢:

SELECT result FROM myTable WHERE keyword LIKE '%a%' AND category = 'A'; 
-- returns 10,200 as expected 

但我可以有很多的元組,因爲我想要的。將這個查詢擴展爲幾個元組將返回錯誤結果:

SELECT result FROM myTable 
    WHERE (keyword LIKE '%a%' AND category = 'A') 
    AND (keyword LIKE '%Superman%' AND category = 'B'); 
-- expected 200; but returned no rows... 

SELECT distinct result FROM myTable 
    WHERE (keyword LIKE '%a%' AND category = 'A') 
    OR (NOT(keyword LIKE '%Superman%') AND category = 'B'); 
-- expected 10; but returned 10,200... 

這非常合乎邏輯,因爲PostgreSQL不遵循操作符順序和括號。

只有OR子句正在工作。如果我只有OR條款,我會使用這樣的:

SELECT result FROM myTable 
    INNER JOIN (VALUES 
     ('foo','C'), 
     ('Superman', 'B') 
    ) t(keyword,category) USING (keyword,category); -- 10,200 as expected 

但它只適用於OR和嚴格的平等。在我的情況下,我想使用LIKE等式,我想在不同元組之間使用AND,ORAND NOTOR NOT

更確切地說,當我寫:

SELECT result FROM myTable 
    WHERE (keyword LIKE '%a%' AND category = 'A') 
    AND (keyword LIKE '%Superman%' AND category = 'B'); 
-- expected 200; but returned no row 

我的意思是我想通過這兩個子句得到的結果的交集。 第一個元組返回10,200,第二個返回200.在這種情況下,我只想返回200。

使用一個或作爲意見建議是這樣的:

SELECT distinct result FROM myTable 
    WHERE (keyword LIKE '%a%' AND category = 'A') 
    OR (keyword LIKE '%Superman%' AND category = 'B'); 

收益10200,但是這不是我想要......

+0

錯誤可能的代碼?也許你的意思是:'SELECT result FROM myTable WHERE(keyword LIKE'%a%'AND category ='A')OR(keyword LIKE'%Superman%'AND category ='B');'。如果你有類別A **和**類別B,結果顯然沒有。 – 2015-03-31 09:23:04

+0

對於'keyword LIKE'%a%'AND category ='A'' =>返回bar和baz,如同'NOT(關鍵字LIKE'%Superman%')AND category ='B'' =>返回yoda如預期的那樣 – 2015-03-31 09:27:46

+0

@SimoKivistö對於錯誤的第一個查詢,我不想要一個OR,因爲我不想爲第一個元組獲得每個結果,爲第二個元素獲得每個結果。事實上,這是我需要的INTERSECTION。 – pidupuis 2015-03-31 09:28:09

回答

1

你彷彿要尋找被稱爲關係部門。該任務可表述爲:

查找結果至少有一行符合這些條件:
keyword LIKE '%a%' AND category = 'A'
至少一行符合這些其他條件:
keyword LIKE '%Superman%' AND category = 'B'

返回條件的快速解決方案DISTINCT結果:

SELECT DISTINCT result 
FROM tbl t1 
JOIN tbl t2 USING (result) 
WHERE t1.keyword LIKE '%a%' AND t1.category = 'A' 
AND t2.keyword LIKE '%Superman%' AND t2.category = 'B'; 

但你的過濾器可以爲每個結果返回多行,其中之一將是更快

SELECT result 
FROM (
    SELECT DISTINCT result 
    FROM tbl 
    WHERE keyword LIKE '%a%' AND category = 'A' 
    ) t1 
JOIN (
    SELECT DISTINCT result 
    FROM tbl 
    WHERE keyword LIKE '%Superman%' AND category = 'B' 
    ) t2 USING (result); 

或者:

SELECT result 
FROM (
    SELECT DISTINCT result 
    FROM tbl 
    WHERE keyword LIKE '%a%' AND category = 'A' 
    ) t 
WHERE EXISTS (
    SELECT 1 
    FROM tbl 
    WHERE result = t.result 
    AND keyword LIKE '%Superman%' AND category = 'B' 
    ); 

SQL小提琴。

我們已經按照此相關的問題組裝的查詢技術的阿森納:

+0

使用'EXISTS'的解決方案似乎更好,因爲它允許我使用'NOT'。你如何建議我用更多的元組交替使用'AND'和'OR'? (我可以將幾個'EXISTS'和'UNION'組合成一個沒有深度的嵌入式選擇嗎?) – pidupuis 2015-03-31 12:37:37

+0

@pidupuis:您已經知道如何實現OR,在WHERE子句中添加'EXISTS' /'NOT EXISTS', AND' /'AND NOT' ... – 2015-03-31 17:31:43

0

你幾乎有:

SELECT distinct result FROM myTable 
WHERE (keyword LIKE '%a%' AND category = 'A') 
OR (keyword LIKE '%Superman%' AND category = 'B'); 

什麼這是:它返回行,如果關鍵字是'%a%'和category ='A'或者如果關鍵字是'%supaerman%'和category ='B'

您的查詢做了以下

SELECT result FROM myTable 
WHERE (keyword LIKE '%a%' AND category = 'A') 
AND (keyword LIKE '%Superman%' AND category = 'B'); -- expected 200; but returned no rows 

該行這裏返回一行(除其他事項外類別必須是「A」和「B」。由於它不能同時出現,所以沒有行被返回。

SELECT distinct result FROM myTable 
WHERE (keyword LIKE '%a%' AND category = 'A') 
OR (NOT(keyword LIKE '%Superman%') AND category = 'B'); -- expected 10; but returned 10,200.. 

在這種情況下,NOT(...)進行的查詢返回的所有行與類別等於「B」,其中的關鍵字不包含「超人」(加當然從條件的結果之前,他OR) 。;)

+0

謝謝,但這不是一個OR。我和我的意思是INTERSECTION。看我的編輯。 – pidupuis 2015-03-31 09:36:27

0

我想你也可以看看文檔SIMILAR TO

你可以做這樣的事情

SELECT * from myTable where keyword SIMILAR TO '%(oo|ba)%' and category SIMILAR TO '(A)';