Nếu tôi có một bảng có 3 cột - nói A, B và D - và tôi phải giới thiệu một bảng mới - nói C để thay thế vị trí hiện tại của D. Tôi sẽ sử dụng phương pháp sau:
- Giới thiệu 2 cột mới là C và D2.
- Sao chép nội dung của D sang D2.
- Xóa D.
- Đổi tên thành D.
Thứ tự mới sẽ là A, B, C và D.
Tôi nghĩ rằng đây là một thực tiễn hợp pháp vì (cho đến nay) nó không tạo ra vấn đề gì.
Tuy nhiên, hôm nay tôi đã gặp một vấn đề khi một hàm thực hiện một câu lệnh trên cùng một bảng trả về lỗi sau:
table row type and query-specified row type do not match
Và các chi tiết sau:
Query provides a value for a dropped column at ordinal position 13
Tôi đã thử khởi động lại PostgreSQL, thực hiện VACUUM FULL
và cuối cùng xóa và tạo lại chức năng như được đề xuất ở đây và ở đây nhưng các giải pháp này không hoạt động (ngoài thực tế là họ đã cố gắng giải quyết tình huống trong đó bảng hệ thống đã bị thay đổi).
Có được sự sang trọng khi làm việc với một cơ sở dữ liệu rất nhỏ, tôi đã xuất nó, xóa nó và sau đó nhập lại nó và điều đó đã khắc phục vấn đề với chức năng của tôi.
Tôi đã nhận thức được thực tế rằng người ta không nên loay hoay với thứ tự tự nhiên của các cột bằng cách sửa đổi các bảng hệ thống (bị bẩn tay pg_attribute
, v.v.) như đã thấy ở đây:
Có thể thay đổi thứ tự tự nhiên của các cột trong Postgres không?
Đánh giá lỗi do chức năng của tôi bây giờ tôi nhận ra rằng việc thay đổi thứ tự các cột bằng phương thức của tôi cũng là không. Bất cứ ai cũng có thể tỏa sáng như tại sao những gì tôi đang làm cũng sai?
Phiên bản Postgres là 9.6.0.
Đây là chức năng:
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
Tôi đã thực hiện đổi tên / sắp xếp lại trên cả hai cột facebook_id
và stripe_id
(một cột mới đã được thêm vào trước đó, đó là lý do cho việc đổi tên, nhưng không bị truy vấn này chạm vào).
Có các cột theo một thứ tự nhất định hoàn toàn không được quan tâm cho đơn hàng. Tuy nhiên, lý do để đặt câu hỏi này là do lo ngại rằng việc đổi tên và xóa một cột đơn giản có thể gây ra vấn đề thực sự cho ai đó sử dụng các chức năng trong chế độ sản xuất (như đã xảy ra với chính tôi).