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