Reputation: 3
Normally converting a sub query to a join is relatively straightforward, but this case has been stumping me. Given
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');
I can query for
SELECT *
FROM pages
WHERE category_id not in (SELECT category_id FROM pages WHERE name = 'invalid' AND some_setting = 'true')
But due to the the fact that the page[name=special]
doesn't need to exist I can't easily convert this to a join. Anybody any idea? Here is a link to an SQLFiddle, but it refuses to save the query: http://sqlfiddle.com/#!15/c4ca7
Upvotes: 0
Views: 68
Reputation: 1623
You can try this having
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
;
Why you do not what use in
statement? I know that not in
not use index. But having not use it too.
Upvotes: 1