D, A, B ve D - 3 sütun içeren bir tablo vardı ve yeni bir tanıtmak zorunda - D D mevcut konumunu değiştirmek için C demek: Ben aşağıdaki yöntemi kullanırdım:
- C ve D2 olarak 2 yeni sütun girin.
- D'nin içeriğini D2'ye kopyalayın.
- Silindi.
- D2'yi D olarak yeniden adlandırın.
Yeni sipariş A, B, C ve D olacaktır.
Bunun şimdiye kadar hiçbir sorun üretmediği için meşru bir uygulama olduğunu düşündüm.
Ancak, bugün aynı tabloda bir ifade yürüten bir işlev aşağıdaki hatayı döndürdüğünde bir sorunla karşılaştım:
table row type and query-specified row type do not match
Ve aşağıdaki detay:
Query provides a value for a dropped column at ordinal position 13
PostgreSQL'i yeniden başlatmayı denedim VACUUM FULL
ve sonunda burada ve burada önerilen şekilde silme ve yeniden oluşturma işlevini denedim, ancak bu çözümler işe yaramadı (bir sistem tablosunun değiştirildiği bir durumla uğraşmaya çalıştıklarından başka).
Çok küçük bir veritabanı ile çalışma lüksüne sahip olarak onu dışa aktardım, sildim ve daha sonra tekrar içe aktardım ve bu benim fonksiyonumla ilgili sorunu düzeltti .
Burada görüldüğü gibi sistem tablolarını değiştirerek (elleri kirleten pg_attribute
vb.) Sütunların doğal düzeniyle uğraşmaması gerektiğinin farkındaydım :
Postgres'deki sütunların doğal sırasını değiştirmek mümkün müdür?
İşlevim tarafından atılan hataya bakılırsa, yöntemimle sütunların sırasını değiştirmenin de hayır-hayır olduğunu anlıyorum. Yaptığım şeyin neden yanlış olduğuna kim ışık tutabilir?
Postgres sürümü 9.6.0'dır.
İşte işlevi:
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
Her iki sütunda yeniden adlandırma / yeniden sıralama gerçekleştirdim facebook_id
ve stripe_id
(bunlardan önce yeni bir sütun eklendi, bu yeniden adlandırma nedeni, ancak bu sorgu tarafından dokunulmamış).
Sütunların belirli bir sırada olması tamamen sipariş için ilgi odağı değildir. Bununla birlikte, bu soruyu sormanın nedeni, bir sütunun basit bir şekilde yeniden adlandırılması ve silinmesinin üretim modunda (kendime olduğu gibi) işlevleri kullanan biri için gerçek sorunları tetikleyebileceğinden endişe etmemektedir.