Why this matters
`NOT IN` against a subquery returns **no rows** if the subquery yields a single NULL. Semantically correct under three-valued logic, virtually never what application code wants. Use `NOT EXISTS (...)` instead. `NOT IN (1, 2, 3)` with a literal list is unaffected.
Examples
Incorrect
SELECT id FROM users WHERE id NOT IN (SELECT user_id FROM blocks);Correct
SELECT id FROM users u
WHERE NOT EXISTS (SELECT 1 FROM blocks b WHERE b.user_id = u.id);SELECT 1 FROM users WHERE id NOT IN (1, 2, 3); -- literal list is fineConfigure it
// eslint.config.js
import postgresql from "eslint-plugin-postgresql";
export default [
{
files: ["**/*.sql"],
languageOptions: {
parser: postgresql.configs.recommended.languageOptions.parser,
},
plugins: { postgresql },
rules: {
"postgresql/no-not-in-subquery": "error",
},
},
]; Options
Edit the SQL — only no-not-in-subquery is enabled.
Pre-filled with the first incorrect example. Toggle off in the rule shelf to see how the diagnostic disappears.
Diagnostics
No issues found.
2 rules enabled.
Rule under test
no-not-in-subquery — plus no-syntax-error as a safety net.