Ошибка 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.
результат запроса-это отсутствие строк, которые нуждаются в правильной обработке эта проблема может быть решена, если вы предоставляете действительный обработчик в запросе как 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
);