web-dev-qa-db-ja.com

Postgresエラー:式として使用されるサブクエリによって複数の行が返されました

2つの個別のデータベースがあります。 1つのデータベースの列を他のデータベースの列の値に更新しようとしています。

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));

これは私が受け取っているエラーです:

ERROR:  more than one row returned by a subquery used as an expression

何か案は?

27
user3182502

Technically、ステートメントを修復するには、サブクエリに_LIMIT 1_を追加できます最大で1行が返されるようにします。それはエラーを取り除くでしょう、あなたのコードはまだナンセンスです。

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

Practically、行を一致させたいsomehow任意のピッキングの代わりにリモートテーブルstoreの行を使用して、ローカルテーブルcustomerのすべての行を更新します。
初歩的な質問では十分な詳細情報が得られないため、assumingテキスト列_match_name_この例のために、両方のテーブル(およびUNIQUEstore)で:

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

しかし、それは物事を行う非常に高価な方法です。

Ideallyステートメントを完全に書き換える必要があります

_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;
_

これにより、元のステートメントの多くの問題が改善されます。

  • 明らかに、エラーにつながるbasic problemは修正されています。

  • ほとんどの場合、FROMステートメントの UPDATE で追加の関係に参加する方が、個々の行ごとにcorrelated subqueriesを実行するよりも優れています。

  • Dblinkを使用する場合、上記は1000倍重要になります。 1行ごとにdblink()を呼び出したくありません。つまり、非常に高価ですです。一度呼び出して、必要なすべての行を取得します。

  • 相関サブクエリでは、サブクエリで行が見つからないの場合、列はNULLに更新されますが、これはほとんどの場合、希望どおりではありません。
    更新されたフォームでは、一致する行が見つかった場合にのみ行が更新されます。それ以外の場合、行は触れられません。

  • 通常、実際に何も変更されていない場合、行を更新することは望ましくありません。それは何もしませんが、それでも無駄な行を生成します。 WHERE句の最後の式は、そのようなempty updatesを防ぎます。

    _ AND   c.customer_id IS DISTINCT FROM sub.store_key
    _
44

これは、ネストされたSELECTが複数の行を返すことを意味します。

適切なWHERE句を追加する必要があります。

3
peter.petrov

基本的な問題は、多くの場合、=からIN、1対多の関係がある場合。たとえば、特定の顧客の一連のアカウントを更新または削除する場合:

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 
);
1
rotarydial

このエラーは、SELECT store_key FROM storeクエリがSERVER1データベースに2つ以上の行を返したことを意味します。すべての顧客を更新する場合は、スカラー=演算子の代わりに結合を使用します。そのためには、顧客を「接続」してアイテムを保存する条件が必要です。

すべてのcustomer_idsを同じstore_keyに更新する場合は、クエリが単一の行を返すように、リモートで実行されるWHERESELECT句を指定する必要があります。

1
dasblinkenlight

クエリによって生成された結果には、適切な処理を必要とする行がありません。1のようなクエリで有効なハンドラを指定すると、この問題を解決できます。単一の行を返す「max(column)」を選択します

0
user10101