J'ai deux bases de données distinctes. J'essaie de mettre à jour une colonne d'une base de données avec les valeurs d'une colonne de l'autre base de données:
UPDATE customer
SET customer_id=
(SELECT t1 FROM dblink('port=5432, dbname=SERVER1 user=postgres password=309245',
'SELECT store_key FROM store') AS (t1 integer));
C'est l'erreur que je reçois:
ERROR: more than one row returned by a subquery used as an expression
Des idées?
Techniquement, pour réparer votre relevé, vous pouvez ajouter LIMIT 1
à la sous-requête pour garantir qu’au plus 1 ligne est renvoyée. Cela éliminerait l'erreur, votre code serait toujours un non-sens.
... 'SELECT store_key FROM store LIMIT 1' ...
pratiquement, vous souhaitez faire correspondre les lignes d'une certaine manière au lieu de choisir une ligne arbitraire depuis la table distante store
pour mettre à jour chaque ligne de votre table locale customer
.
Votre question rudimentaire ne fournit pas assez de détails, alors je suis en supposant une colonne de texte match_name
Dans les deux tables (et UNIQUE
dans store
) pour 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 devriez réécrire complètement la déclaration .
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 initiale.
Évidemment, le problème de base qui a entraîné votre erreur est corrigé.
Il est presque toujours préférable de joindre des relations supplémentaires dans la FROM
clause d’une instruction 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 coûteux . Appelez-le une fois pour récupérer toutes les lignes dont vous avez besoin.
Avec les sous-requêtes corrélées, si aucune ligne n'est trouvée dans la sous-requête, la colonne est mise à jour en NULL, ce qui n'est presque toujours pas ce que vous voulez.
Dans mon formulaire mis à 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, quand rien ne change réellement. Cela ne coûte rien (mais produit toujours des lignes mortes). La dernière expression de la clause WHERE
empêche de telles mises à jour vides :
AND c.customer_id IS DISTINCT FROM sub.store_key
Cela signifie que votre SELECT imbriqué retourne plus d'une ligne.
Vous devez ajouter une clause WHERE appropriée.
Le problème fondamental peut souvent être simplement résolu en changeant un =
à IN
, dans les cas où vous avez une relation un à plusieurs. Par exemple, si vous souhaitez mettre à jour ou supprimer un groupe de comptes pour un client donné:
WITH accounts_to_delete AS
(
SELECT account_id
FROM accounts a
INNER JOIN customers c
ON a.customer_id = c.id
WHERE c.customer_name='Some Customer'
)
-- this fails if "Some Customer" has multiple accounts, but works if there's 1:
DELETE FROM accounts
WHERE accounts.guid =
(
SELECT account_id
FROM accounts_to_delete
);
-- this succeeds with any number of accounts:
DELETE FROM accounts
WHERE accounts.guid IN
(
SELECT account_id
FROM accounts_to_delete
);
Cette erreur signifie que le SELECT store_key FROM store
La requête a renvoyé deux lignes ou plus dans la SERVER1
base de données. Si vous souhaitez mettre à jour tous les clients, utilisez une jointure au lieu d'un scalaire =
opérateur. Vous avez besoin d'une condition pour "connecter" les clients afin de stocker des éléments afin de le faire.
Si vous souhaitez mettre à jour tous les customer_id
s au même store_key
, vous devez fournir une clause WHERE
à SELECT
exécuté à distance afin que la requête renvoie une seule ligne.
Le résultat généré par la requête ne contient pas de lignes nécessitant une gestion appropriée. Ce problème peut être résolu si vous indiquez le gestionnaire valide dans la requête, tel que 1. Limiter la requête pour renvoyer une seule ligne 2. Pour cela, vous pouvez également " select max (column) "qui retournera la seule ligne