将`not in`子查询转换为`join`

时间:2016-08-19 06:36:00

标签: postgresql join

通常将子查询转换为连接是相对简单的,但是这种情况一直困扰着我。给定

CREATE TABLE pages(
   id serial PRIMARY KEY     NOT NULL,
   name           TEXT    NOT NULL,
   category_id            INT     NOT NULL,
   some_setting        CHAR(50)
);

INSERT INTO pages (name, category_id, some_setting) VALUES ('a', 10, 'lorem');
INSERT INTO pages (name, category_id, some_setting) VALUES ('b', 10, 'lorem');
INSERT INTO pages (name, category_id, some_setting) VALUES ('invalid', 10, 'true');


INSERT INTO pages (name, category_id, some_setting) VALUES ('a', 20, 'lorem');
INSERT INTO pages (name, category_id, some_setting) VALUES ('b', 20, 'lorem');
INSERT INTO pages (name, category_id, some_setting) VALUES ('invalid', 20, 'false');


INSERT INTO pages (name, category_id, some_setting) VALUES ('a', 30, 'lorem');
INSERT INTO pages (name, category_id, some_setting) VALUES ('b', 30, 'lorem');

我可以查询

SELECT * 
FROM pages 
WHERE category_id not in (SELECT category_id FROM pages WHERE name = 'invalid' AND some_setting = 'true')

但是由于page[name=special]不需要存在,我无法轻易将其转换为联接。有人有什么想法吗?这是一个指向SQLFiddle的链接,但它拒绝保存查询:http://sqlfiddle.com/#!15/c4ca7

1 个答案:

答案 0 :(得分:1)

您可以尝试使用

select pg1.*
from pages pg1 
      left join pages pg2 on pg1.category_id = pg2.category_id
group by pg1.id
having
    ARRAY['invalid', 'true']::text != ALL (ARRAY_AGG(array[pg2.name, pg2.some_setting]::text))
order by pg1.id  
;

为什么不使用in语句?我知道not in不使用索引。但是也没有使用它。