Ошибка Postgres: несколько строк, возвращаемых вложенным запросом, используемым в качестве выражения

у меня две отдельные базы данных. Я пытаюсь обновить столбец в одной базе данных до значений столбца из другой базы данных:

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

какие идеи?

5 ответов


технически, чтобы отремонтировать ваше заявление, вы можете добавить 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 пункта UPDATE сообщении чем бегать коррелированные подзапросы для каждой отдельной строки.

  • при использовании dblink, выше становится в тысячу раз больше важный. Вы не хотите звонить dblink() для каждой строки, это очень дорого. Вызовите его один раз, чтобы получить все строки, которые вам нужны.

  • С коррелированными подзапросами, если строка не нашел в подзапросе столбец обновляется до NULL, что почти всегда не то, что вы хотите.
    В моей обновленной форме строка обновляется только в том случае, если найдена соответствующая строка. Еще, строка не тронутый.

  • обычно вы не хотите обновлять строки, когда на самом деле ничего не меняется. Это дорого ничего не делает (но все равно производит мертвые строки). Последнее выражение в WHERE статья запрещает такие пустые обновления:

     AND   c.customer_id IS DISTINCT FROM sub.store_key
    

Это означает, что вложенный SELECT возвращает более одной строки.

вам нужно добавить к нему правильное предложение WHERE.


эта ошибка означает, что SELECT store_key FROM store запрос вернул две или более строк


результат запроса-это отсутствие строк, которые нуждаются в правильной обработке эта проблема может быть решена, если вы предоставляете действительный обработчик в запросе как 1. ограничение запроса на возврат одной строки 2. это также можно сделать, предоставив " select max (column)", который вернет одну строку


фундаментальная проблема часто может быть просто решена путем изменения = 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 
);