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