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

时间:2014-01-10 16:07:08

标签: sql database postgresql subquery dblink

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

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

有什么想法吗?

6 个答案:

答案 0 :(得分:42)

技术上 ,要修复您的对帐单,您可以将 LIMIT 1 添加到子查询中,以确保最多1行是回。这样就可以消除错误,你的代码仍然是无意义的。

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

实际 ,您希望以某种方式匹配行 ,而不是从远程表store中选择任意行来更新每一行本地表格的一行customer 您的基本问题没有提供足够的详细信息,因此我 假设 两个表中的文本列match_name(以及UNIQUE store为了这个例子:

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

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

理想情况下 ,您应该完全重写声明

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;

这可以解决您原始陈述中的许多问题。

  • 显然,导致错误的基本问题已修复。

  • 加入FROM clause of an UPDATE statement中的其他关系,而不是为每一行运行相关子查询,几乎总是更好。

  • 使用dblink时,上面的重要性要高出上千倍。您不希望为每一行调用dblink()非常昂贵。调用一次以检索所需的所有行。

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

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

     AND   c.customer_id IS DISTINCT FROM sub.store_key
    

答案 1 :(得分:3)

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

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

答案 2 :(得分:1)

如果你有一对多的关系,通常可以通过将=更改为 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 
);

答案 3 :(得分:1)

使用限制1-因此它将仅返回1行。 例子

客户ID -(从枚举中选择 id ,其中enumerations.name =“准备发票”限制1)

答案 4 :(得分:0)

此错误表示SELECT store_key FROM store查询已在SERVER1数据库中返回了两行或更多行。如果您想要更新所有客户,请使用联接而不是标量=运算符。你需要一个条件来连接"客户存储物品以便做到这一点。

如果您希望将所有customer_id更新为同一store_key,则需要向远程执行的WHERE提供SELECT子句,以便查询返回单行。

答案 5 :(得分:0)

Query产生的结果是没有需要正确处理的行如果你在查询中提供有效的处理程序就可以解决这个问题 1.限制查询返回一行 2.这也可以通过提供“select max(column)”来完成,它将返回单行