Erreur PostgreSQL : more than one row returned by a subquery
ERROR: more than one row returned by a subquery used as an expression
Une sous-requête utilisée là où une valeur unique est attendue — après =, dans une liste SELECT, dans une affectation — a renvoyé plus d'une ligne. La moitié du temps la requête est fausse (vous vouliez un ensemble, pas une valeur) ; l'autre moitié la requête est juste et les données ont des doublons que personne ne connaissait.
Ce que signifie cette erreur
Un contexte de sous-requête scalaire (WHERE x = (SELECT ...), SELECT (SELECT ...) AS y, SET col = (SELECT ...)) exige zéro ligne (→ NULL) ou une ligne. Deux ou plus est une erreur au moment de l'exécution — ce qui signifie qu'elle peut se tapir en production pendant des mois et se déclencher le premier jour où les données rendent la sous-requête multi-lignes.
Causes fréquentes
- Vous vouliez un ensemble : la lecture naturelle était « n'importe lequel de ceux-ci » — c'est
IN, pas=. - Corrélation ou filtre manquant : la sous-requête aurait dû être liée à la ligne externe (
WHERE sub.user_id = outer.id) et ne l'était pas. - Doublons inattendus dans des données supposées uniques — la sous-requête était juste, l'invariant a cassé.
Comment la diagnostiquer
-- Exécutez la sous-requête seule : combien de lignes ? lesquelles ?
SELECT id FROM payments WHERE order_id = 42;
-- Si « il ne devrait pas y avoir de doublons », trouvez-les :
SELECT order_id, count(*)
FROM payments
GROUP BY order_id
HAVING count(*) > 1;
Comment la corriger
- Ensemble voulu →
WHERE x IN (SELECT ...), ouEXISTSpour de pures vérifications d'existence. - Une ligne spécifique voulue → rendez le choix explicite :
(SELECT ... ORDER BY created_at DESC LIMIT 1). Un simple LIMIT 1 sans ORDER BY masque le bug au lieu de le corriger. - Invariant cassé → nettoyez les doublons, puis ajoutez la contrainte d'unicité qui rend l'hypothèse applicable, afin que cette classe d'erreur ne puisse pas revenir.
🔍
La contrainte qui garde ceci corrigé : duplicate key value violates unique constraint.
