WHERE 子句中的 PostgreSQL 多元组选择

PostgreSQL multiple tuples selection in WHERE clause

我有这个 table:

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

但我可以拥有任意数量的元组。为几个元组扩展此查询 returns 错误结果:

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 相等性,我想在不同的元组之间使用 ANDORAND 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

我的意思是我想要两个子句得到的结果的INTERSECTION。 第一个元组 return 10,200,第二个元组 200。在这种情况下,我只想 return 200。

在这样的评论中使用 OR 作为建议:

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

returns 10,200,但这不是我想要的...

你快到了:

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

它的作用是:如果关键字像“%a%”和类别 = 'A',或者如果关键字像“%supaerman%”和类别 =,它 return 是行'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

到 return 一行(除其他事项外,该行中的类别必须是 'A' 和 'B'。由于它们不能同时存在,因此没有行returned.

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(...) 查询 return 所有类别等于 'B' 的行,其中关键字不包含 'Superman'(当然还有来自他 OR 之前的情况)。 ;)

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

你可以这样做

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

您似乎要找的东西叫做关系划分。该任务可以表述为:

查找至少有一行符合这些条件的结果:
keyword LIKE '%a%' AND category = 'A'
至少一行符合这些其他条件:
keyword LIKE '%Superman%' AND category = 'B'

条件的快速解决方案 returning 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';

但是由于您的过滤器可以为每个结果 return 多行,因此其中之一将 更快:

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 Fiddle.

我们在这个相关问题下汇集了一系列查询技术:

  • How to filter SQL results in a has-many-through relation