Postgres错误:用作表达式的子查询返回多行

use*_*502 30 sql database postgresql dblink subquery

我有两个独立的数据库.我试图将一个数据库中的列更新为另一个数据库中的列的值:

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));
Run Code Online (Sandbox Code Playgroud)

这是我收到的错误:

ERROR:  more than one row returned by a subquery used as an expression
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Erw*_*ter 49

从技术上讲,要修复语句,可以添加LIMIT 1到子查询以确保最多返回1行.这将删除错误,您的代码仍然是无稽之谈.

... 'SELECT store_key FROM store LIMIT 1' ...
Run Code Online (Sandbox Code Playgroud)

实际上,您希望以某种方式匹配行,而不是从远程表中选择任意行store来更新本地表的每一行customer.
你的基本问题没有提供足够的细节,所以为了这个例子,我在两个表(和in)中假设一个文本列:match_nameUNIQUEstore

... 'SELECT store_key FROM store
     WHERE match_name = ' || quote_literal(customer.match_name)  ...
Run Code Online (Sandbox Code Playgroud)

但这是一种非常昂贵的做事方式.

理想情况下,您应该完全重写该语句.

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;
Run Code Online (Sandbox Code Playgroud)

这可以解决您原始声明中的许多问题.

  • 显然,导致错误的基本问题是固定的.

  • 在语句的FROM子句中UPDATE加入其他关系而不是为每个单独的行运行相关子查询几乎总是更好.

  • 使用dblink时,上面的重要性要高出千倍.你不想dblink()为每一行打电话,这是非常昂贵的.调用一次以检索所需的所有行.

  • 使用相关子查询,如果在子查询中找不到行,则列会更新为NULL,这几乎总是不是您想要的.
    在我更新的表单中,只有找到匹配的行才会更新行.否则,行不会被触及.

  • 通常,当没有任何实际更改时,您不希望更新行.那是昂贵的无所事事(但仍会产生死行).WHERE子句中的最后一个表达式可防止此类空更新:

     AND   c.customer_id IS DISTINCT FROM sub.store_key
    
    Run Code Online (Sandbox Code Playgroud)

  • 我没想到会在堆栈溢出时大声笑出来。“这会消除错误,你的代码仍然是无意义的。” (2认同)

rot*_*ial 13

在一对多关系的情况下,基本问题通常可以通过更改=to来简单解决IN。例如,如果您想更新或删除给定客户的一组帐户:

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 
);
Run Code Online (Sandbox Code Playgroud)


pet*_*rov 5

这意味着您的嵌套 SELECT 返回多行。

您需要为其添加适当的 WHERE 子句。