Un'opzione è quella di utilizzare un JOU COMPLETO ESTERNO tra le due tabelle nel seguente formato:
SELECT count (1)
FROM table_a a
FULL OUTER JOIN table_b b
USING (<list of columns to compare>)
WHERE a.id IS NULL
OR b.id IS NULL ;
Per esempio:
CREATE TABLE a (id int, val text);
INSERT INTO a VALUES (1, 'foo'), (2, 'bar');
CREATE TABLE b (id int, val text);
INSERT INTO b VALUES (1, 'foo'), (3, 'bar');
SELECT count (1)
FROM a
FULL OUTER JOIN b
USING (id, val)
WHERE a.id IS NULL
OR b.id IS NULL ;
Restituirà un conteggio di 2, mentre:
CREATE TABLE a (id int, val text);
INSERT INTO a VALUES (1, 'foo'), (2, 'bar');
CREATE TABLE b (id int, val text);
INSERT INTO b VALUES (1, 'foo'), (2, 'bar');
SELECT count (1)
FROM a
FULL OUTER JOIN b
USING (id, val)
WHERE a.id IS NULL
OR b.id IS NULL ;
restituisce il conteggio sperato di 0.
La cosa che mi piace di questo metodo è che deve solo leggere ogni tabella una volta rispetto a ogni tabella due volte quando si utilizza EXISTS. Inoltre, questo dovrebbe funzionare per qualsiasi database che supporti i join esterni completi (non solo Postgresql).
In genere scoraggio l'uso della clausola USING ma qui c'è una situazione in cui credo che sia l'approccio migliore.
Addendum 2019-05-03:
Se si verifica un problema con possibili dati null, (ovvero la colonna id non è nulla ma il valore val è), è possibile provare quanto segue:
SELECT count (1)
FROM a
FULL OUTER JOIN b
ON ( a.id = b.id
AND a.val IS NOT DISTINCT FROM b.val )
WHERE a.id IS NULL
OR b.id IS NULL ;
EXCEPT
, controlla questa domanda: Un modo efficace per confrontare due grandi set di dati in SQL