PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Erreur Postgres :plusieurs lignes renvoyées par une sous-requête utilisée comme expression

Techniquement , pour réparer votre relevé, vous pouvez ajouter LIMIT 1 à la sous-requête pour s'assurer qu'au plus 1 ligne est renvoyée. Cela supprimerait l'erreur, votre code serait toujours un non-sens.

... 'SELECT store_key FROM store LIMIT 1' ...

Pratiquement , vous voulez faire correspondre les lignes d'une manière ou d'une autre au lieu de choisir une ligne arbitraire dans la table distante store pour mettre à jour chaque ligne de votre table locale customer .
Votre question rudimentaire ne fournit pas suffisamment de détails, donc je suppose une colonne de texte match_name dans les deux tables (et UNIQUE en store ) pour les besoins de cet exemple :

... 'SELECT store_key FROM store
     WHERE match_name = ' || quote_literal(customer.match_name)  ...

Mais c'est une façon extrêmement coûteuse de faire les choses.

Idéalement , vous réécrivez complètement l'instruction.

UPDATE customer c
SET    customer_id = s.store_key
FROM   dblink('port=5432, dbname=SERVER1 user=postgres password=309245'
            , 'SELECT match_name, store_key FROM store')
       AS s(match_name text, store_key integer)
WHERE c.match_name = s.match_name
AND   c.customer_id IS DISTINCT FROM s.store_key;

Cela résout un certain nombre de problèmes dans votre déclaration d'origine.

Évidemment, le problème de base menant à votre erreur est corrigé.

Il est généralement préférable de joindre des relations supplémentaires dans le FROM clause d'un UPDATE plutôt que d'exécuter des sous-requêtes corrélées pour chaque ligne individuelle.

Lorsque vous utilisez dblink, ce qui précède devient mille fois plus important. Vous ne voulez pas appeler dblink() pour chaque ligne, c'est extrêmement cher . Appelez-le une fois pour récupérer toutes les lignes dont vous avez besoin.

Avec des sous-requêtes corrélées, si aucune ligne n'est trouvée dans la sous-requête, la colonne est mise à jour sur NULL, ce qui n'est presque toujours pas ce que vous voulez. Dans ma requête mise à jour, la ligne n'est mise à jour que si une ligne correspondante est trouvée. Sinon, la ligne n'est pas touchée.

Normalement, vous ne voudriez pas mettre à jour les lignes, alors que rien ne change réellement. Cela coûte cher de ne rien faire (mais produit toujours des lignes mortes). La dernière expression dans WHERE la clause empêche de telles mises à jour vides :

     AND   c.customer_id IS DISTINCT FROM sub.store_key

Connexe :

  • Comment puis-je (ou puis-je) SELECT DISTINCT sur plusieurs colonnes ?