Errore PostgreSQL: more than one row returned by a subquery
ERROR: more than one row returned by a subquery used as an expression
Una subquery usata dove va un singolo valore — dopo =, in una SELECT list, in un'assegnazione — ha restituito più di una riga. Metà delle volte la query è sbagliata (intendevi un insieme, non un valore); l'altra metà la query è giusta e i dati hanno duplicati che nessuno conosceva.
Cosa significa questo errore
Un contesto di subquery scalare (WHERE x = (SELECT ...), SELECT (SELECT ...) AS y, SET col = (SELECT ...)) richiede zero righe (→ NULL) o una riga. Due o più è un errore in fase di esecuzione — il che significa che può annidarsi in produzione per mesi e scattare il primo giorno in cui i dati rendono la subquery multi-riga.
Cause comuni
- Intendevi un insieme: la lettura naturale era "uno qualsiasi di questi" — quello è
IN, non=. - Correlazione o filtro mancante: la subquery avrebbe dovuto essere legata alla riga esterna (
WHERE sub.user_id = outer.id) e non lo era. - Duplicati inattesi in dati assunti come unici — la subquery era giusta, l'invariante si è rotto.
Come diagnosticarlo
-- Esegui la subquery da sola: quante righe? quali?
SELECT id FROM payments WHERE order_id = 42;
-- Se "non dovrebbero esserci duplicati", trovali:
SELECT order_id, count(*)
FROM payments
GROUP BY order_id
HAVING count(*) > 1;
Come risolverlo
- Insieme voluto →
WHERE x IN (SELECT ...), oEXISTSper puri controlli di esistenza. - Una riga specifica voluta → rendi la scelta esplicita:
(SELECT ... ORDER BY created_at DESC LIMIT 1). Un semplice LIMIT 1 senza ORDER BY nasconde il bug invece di risolverlo. - Invariante rotto → pulisci i duplicati, poi aggiungi il vincolo di unicità che rende l'assunzione applicabile, così questa classe di errore non può tornare.
🔍
Il vincolo che tiene questo risolto: duplicate key value violates unique constraint.
