Если бы у меня была таблица с 3 столбцами - скажем, A, B и D - и мне пришлось бы ввести новую - скажем, C, чтобы заменить текущую позицию D. Я бы использовал следующий метод:
- Введите 2 новых столбца как C и D2.
- Скопируйте содержимое D в D2.
- Удалить D.
- Переименуйте D2 в D.
Новый порядок будет A, B, C и D.
Я думал, что это была законная практика, поскольку (до сих пор) она не вызывала никаких проблем.
Однако сегодня я столкнулся с проблемой, когда функция, выполняющая оператор в той же таблице, возвратила следующую ошибку:
table row type and query-specified row type do not match
И следующая деталь:
Query provides a value for a dropped column at ordinal position 13
Я попытался перезапустить PostgreSQL, сделать VACUUM FULL
и, наконец, удалить и заново создать функцию, как предлагалось здесь и здесь, но эти решения не сработали (за исключением того, что они пытаются решить ситуацию, когда системная таблица была изменена).
Имея возможность работать с очень маленькой базой данных, я экспортировал ее, удалил, а затем повторно импортировал, и это устранило проблему с моей функцией.
Я знал о том факте, что не следует возиться с естественным порядком столбцов , изменяя системные таблицы (пачкать руки pg_attribute
и т. Д.), Как показано здесь:
Можно ли изменить естественный порядок столбцов в Postgres?
Судя по ошибке, сгенерированной моей функцией, я теперь понимаю, что смещение порядка столбцов с помощью моего метода также является нет-нет. Может ли кто-нибудь пролить свет на то, почему то, что я делаю, тоже неправильно?
Версия Postgres - 9.6.0.
Вот функция:
CREATE OR REPLACE FUNCTION "public"."__post_users" ("facebookid" text, "useremail" text, "username" text) RETURNS TABLE (authentication_code text, id integer, key text, stripe_id text) AS '
-- First, select the user:
WITH select_user AS
(SELECT
users.id
FROM
users
WHERE
useremail = users.email),
-- Second, update the user (if user exists):
update_user AS
(UPDATE
users
SET
authentication_code = GEN_RANDOM_UUID(),
authentication_date = current_timestamp,
facebook_id = facebookid
WHERE EXISTS (SELECT * FROM select_user)
AND
useremail = users.email
RETURNING
users.authentication_code,
users.id,
users.key,
users.stripe_id),
-- Third, insert the user (if user does not exist):
insert_user AS
(INSERT INTO
users (authentication_code, authentication_date, email, key, name, facebook_id)
SELECT
GEN_RANDOM_UUID(),
current_timestamp,
useremail,
GEN_RANDOM_UUID(),
COALESCE(username, SUBSTRING(useremail FROM ''([^@]+)'')),
facebookid
WHERE NOT EXISTS (SELECT * FROM select_user)
RETURNING
users.authentication_code,
users.id,
users.key,
users.stripe_id)
-- Finally, select the authentication code, ID, key and Stripe ID:
SELECT
*
FROM
update_user
UNION ALL
SELECT
*
FROM
insert_user' LANGUAGE "sql" COST 100 ROWS 1
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
Я выполнил переименование / переупорядочение для обоих столбцов facebook_id
и stripe_id
(перед ними был добавлен новый столбец, что является причиной переименования, но этот запрос не затрагивает).
Наличие столбцов в определенном порядке просто не представляет интереса для заказа. Однако причина для того, чтобы задать этот вопрос, состоит в том, что простое переименование и удаление столбца может вызвать реальные проблемы для кого-то, использующего функции в производственном режиме (как это случилось со мной).
Ответы:
Вероятная ошибка на 9.6 и 9.6.1
Это полностью похоже на ошибку для меня ...
Я не знаю, почему это происходит, но я могу подтвердить, что это происходит. Это самая простая найденная установка, которая воспроизводит проблему (в версиях 9.6.0 и 9.6.1).
После этой настройки следующий оператор просто работает
На данный момент мы отбрасываем один столбец:
Это изменение делает следующий оператор для генерации ошибки
что так же, как упомянуто @Andy:
Удаление и воссоздание функции НЕ решает проблему.
VACUUM FULL (таблица или вся база данных) не решает проблему.
Сообщение об ошибке было передано в соответствующий список рассылки PostgreSQL, и мы получили очень быстрый ответ :
Версия 9.6.2
На 2017-03-06 я могу подтвердить, что не могу воспроизвести это поведение в версии 9.6.2. То есть ошибка, кажется, была исправлена в этом выпуске.
ОБНОВИТЬ
Согласно комментарию @Jana: «Я могу подтвердить, что ошибка присутствует в 9.6.1 и была исправлена в 9.6.2. Это исправление также перечислено на веб-сайте постгрес-релиза : Исправление ложного запроса« предоставляет значение для отброшенного столбца »во время ошибок INSERT или UPDATE для таблицы с пропущенным столбцом
источник
Я знаю, что вы, наверное, слышали это раньше, но это ужасная идея.
SELECT *
Так что, если ничто не имеет значения, не отговорит вас, и мы признаем, что мы просто играем в Photoshop со структурой строк и зацикливаемся на отображении, давайте объясним еще кое-что.
CREATE TABLE
(хотя это будет гораздо более высоким приоритетом)Так что PostgreSQL - плохой слой отображения. Вдобавок ко всему, хотя и
ALTER
работает нормально, вы не должны испытывать дракона. ОбаALTER TABLE
, и раздел CAVEAT упоминают об этом,И, если всего этого недостаточно, и вы все еще хотите сделать вид, что это хорошая идея, а не ужасная идея. Тогда попробуй это,
pg_dump -t
BEGIN
сделкаDROP
старый стол целиком,RENAME
временная таблица для таблицы продуктов.COMMIT
Если все это звучит чрезмерно, имейте в виду, что для обновления строк в базе данных требуется переписать строки (при условии, что они не TOAST . Вам необходимо проанализировать данные и перестроить схему таблицы, но в любом случае вам придется переписать строка. Если бы мне пришлось выполнить эту задачу, я бы так и сделал.
Но все это говорит в общем. Никто не воспроизвел ваши результаты.
Вы дали тест-кейс, который мы не можем запустить
И вы не сказали нам точную версию, на которой вы находитесь.
источник
Я справился с этой ошибкой, создав резервную копию и восстановив базу данных.
Шаги для Heroku
heroku maintenance:on
heroku pg:backups:capture
heroku pg:backups:restore
heroku restart
heroku maintenance:off
источник
Я столкнулся с этой ошибкой тоже. Для тех, кто не хочет полностью резервировать / восстанавливать свои БД. Знайте, что простое копирование таблицы работает. Там нет "волшебный" способ скопировать таблицу, хотя. Я сделал это с помощью:
После этого вам все равно нужно будет вручную воссоздать ваши индексы, внешние ключи и значения по умолчанию. При таком воссоздании таблицы ошибка исчезла.
источник