Let's start with the following two tables:
CREATE TABLE people AS ( SELECT * FROM VALUES ('david', 10), ('george', 20) AS tmp(name, age) ); CREATE TABLE position AS ( SELECT * FROM VALUES ('george', 'c++'), ('george', 'frontend') AS tmp(name, job) ); Is the following two equivalent ways to write the SEMI JOIN or ANTI JOIN pattern? If not, what is missing?
[SEMI-JOIN == WHERE EXISTS] SELECT * FROM people SEMI JOIN position ON (people.name=position.name) SELECT * FROM people WHERE EXISTS (SELECT * FROM position WHERE people.name=position.name) // or like this? SELECT * FROM people WHERE name IN (SELECT name FROM position) [ANTI-JOIN == WHERE NOT EXISTS] SELECT * FROM people ANTI JOIN position ON (people.name=position.name) SELECT * FROM people WHERE NOT EXISTS (SELECT * FROM position WHERE people.name=position.name) // or like this? SELECT * FROM people WHERE name NOT IN (SELECT name FROM position)
NOT IN, it has weird and unexpected semantics when nulls are involved.