2015-03-31 132 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)';