Jika saya memiliki tabel dengan 3 kolom - katakan A, B dan D - dan saya harus memperkenalkan yang baru - katakan C untuk menggantikan posisi D. Saat ini saya akan menggunakan metode berikut:
- Perkenalkan 2 kolom baru sebagai C dan D2.
- Salin konten D ke D2.
- Hapus D.
- Ganti nama D2 menjadi D.
Pesanan baru adalah A, B, C dan D.
Saya pikir ini adalah praktik yang sah karena (sejauh ini) tidak menghasilkan masalah.
Namun, hari ini saya menemukan masalah ketika fungsi yang menjalankan pernyataan pada tabel yang sama mengembalikan kesalahan berikut:
table row type and query-specified row type do not match
Dan detail berikut:
Query provides a value for a dropped column at ordinal position 13
Saya mencoba me-restart PostgreSQL, melakukan VACUUM FULL
dan akhirnya menghapus dan menciptakan kembali fungsi seperti yang disarankan di sini dan di sini tetapi solusi ini tidak bekerja (selain dari fakta bahwa mereka mencoba menangani situasi di mana tabel sistem telah diubah).
Memiliki kemewahan bekerja dengan basis data yang sangat kecil saya mengekspornya, menghapusnya dan kemudian mengimpornya kembali dan itu memperbaiki masalah dengan fungsi saya.
Saya menyadari fakta bahwa seseorang tidak boleh dipusingkan dengan urutan kolom alami dengan memodifikasi tabel sistem (menjadi kotor dengan pg_attribute
, dll.) Seperti terlihat di sini:
Apakah mungkin mengubah urutan alami kolom di Postgres?
Menilai oleh kesalahan yang dilemparkan oleh fungsi saya, saya sekarang menyadari bahwa mengubah urutan kolom dengan metode saya juga tidak-tidak. Adakah yang bisa menjelaskan mengapa apa yang saya lakukan juga salah?
Versi Postgres adalah 9.6.0.
Inilah fungsinya:
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
Saya melakukan penggantian nama / pemesanan ulang pada kedua kolom facebook_id
dan stripe_id
(kolom baru ditambahkan sebelum ini, yang merupakan alasan untuk penggantian nama, tetapi tidak tersentuh oleh permintaan ini).
Memiliki kolom dalam urutan tertentu murni tidak menarik untuk pesanan. Namun, alasan untuk mengajukan pertanyaan ini adalah karena kekhawatiran bahwa penggantian nama sederhana dan penghapusan kolom dapat memicu masalah nyata bagi seseorang yang menggunakan fungsi dalam mode produksi (seperti yang terjadi pada diri saya).