Berikut ini versi singkat dan manis menggunakan pernyataan "DO":
DO $$
BEGIN
BEGIN
ALTER TABLE <table_name> ADD COLUMN <column_name> <column_type>;
EXCEPTION
WHEN duplicate_column THEN RAISE NOTICE 'column <column_name> already exists in <table_name>.';
END;
END;
$$
Anda tidak dapat melewatkan ini sebagai parameter, Anda harus melakukan substitusi variabel dalam string di sisi klien, tetapi ini adalah kueri mandiri yang hanya memancarkan pesan jika kolom sudah ada, menambahkan jika tidak dan akan terus gagal pada kesalahan lain (seperti tipe data yang tidak valid).
Saya tidak menyarankan melakukan salah satu dari metode ini jika ini adalah string acak yang berasal dari sumber eksternal. Tidak peduli metode apa yang Anda gunakan (string dinamis sisi-sisi atau sisi-server dieksekusi sebagai kueri), itu akan menjadi resep untuk bencana karena membuka Anda terhadap serangan injeksi SQL.
DO $$ BEGIN BEGIN CREATE INDEX type_idx ON table1 USING btree (type); EXCEPTION WHEN duplicate_table THEN RAISE NOTICE 'Index exists.'; END; END;$$;
pendekatan yang sama diCREATE INDEX
;) Terima kasih atas jawaban Anda,DO $$
gagal. Saya mencobaDO $$;
yang gagal juga, sampai saya baru memulai blok denganDO $$DECLARE r record;
yang diberikan dalam contoh di doc postgres dev .END; $$
adalah kesalahan sintaks (Postgres 9.3), saya harus menggunakanEND $$;
sebagai gantinyaEXCEPTION
) sedikit lebih umum, dan dapat digunakan untuk tugas-tugas yang tidak memilikiIF NOT EXISTS
sintaksis - misalnyaALTER TABLE ... ADD CONSTRAINT
.Dengan Postgres 9.6 ini dapat dilakukan menggunakan opsi
if not exists
sumber
ADD CONSTRAINT IF NOT EXISTS
belum ada .Panggilan:
Pengembalian
TRUE
sukses, kalau tidakFALSE
(kolom sudah ada).Menimbulkan pengecualian untuk tabel atau nama jenis tidak valid.
Mengapa versi lain?
Ini bisa dilakukan dengan
DO
pernyataan, tetapiDO
pernyataan tidak bisa mengembalikan apa pun. Dan jika itu untuk penggunaan berulang, saya akan membuat fungsi.Saya menggunakan jenis pengidentifikasi objek
regclass
danregtype
untuk_tbl
dan_type
yang) mencegah injeksi SQL dan b) memeriksa validitas keduanya segera (cara termurah yang mungkin). Nama kolom_col
masih harus dibersihkan untukEXECUTE
denganquote_ident()
. Penjelasan lebih lanjut dalam jawaban terkait ini:format()
membutuhkan Postgres 9.1+. Untuk versi lama digabungkan secara manual:Anda dapat memenuhi kualifikasi skema nama tabel Anda, tetapi Anda tidak harus melakukannya.
Anda dapat mengutip dua kali pengidentifikasi dalam pemanggilan fungsi untuk menjaga kasing dan unta kata-kata yang dilindungi (tapi toh Anda tidak boleh menggunakan semua ini).
Saya meminta
pg_catalog
bukaninformation_schema
. Penjelasan detail:Blok yang mengandung
EXCEPTION
klausa seperti jawaban yang saat ini diterima jauh lebih lambat. Ini umumnya lebih sederhana dan lebih cepat. Dokumentasi:sumber
DO
pernyataan, sedikit modifikasi untuk menerimaDEFAULT
dan ini bekerja dengan sempurna!Permintaan pilih berikut akan kembali
true/false
, menggunakanEXISTS()
fungsi.dan gunakan pernyataan SQL dinamis berikut untuk mengubah tabel Anda
sumber
Bagi mereka yang menggunakan Postgre 9.5+ (saya percaya sebagian besar dari Anda melakukannya), ada solusi yang cukup sederhana dan bersih
sumber
fungsi di bawah ini akan memeriksa kolom jika ada mengembalikan pesan yang sesuai lain itu akan menambahkan kolom ke tabel.
sumber
Ini pada dasarnya adalah solusi dari sola, tetapi baru dibersihkan sedikit. Cukup berbeda sehingga saya tidak hanya ingin "meningkatkan" solusinya (ditambah, saya kira itu tidak sopan).
Perbedaan utama adalah bahwa ia menggunakan format EXECUTE. Yang menurut saya sedikit lebih bersih, tapi saya percaya berarti Anda harus menggunakan PostgresSQL 9.1 atau yang lebih baru.
Ini telah diuji pada 9.1 dan berfungsi. Catatan: Ini akan memunculkan kesalahan jika skema / table_name / atau data_type tidak valid. Itu bisa "diperbaiki", tetapi mungkin perilaku yang benar dalam banyak kasus.
pemakaian:
sumber
Dapat ditambahkan ke fungsi memanggil skrip migrasi dan drop ketika selesai.
sumber
Dalam kasus saya, untuk alasan pembuatannya, agak sulit bagi skrip migrasi kami untuk memotong skema yang berbeda.
Untuk mengatasi ini, kami menggunakan pengecualian yang hanya menangkap dan mengabaikan kesalahan. Ini juga memiliki efek samping yang bagus karena jauh lebih mudah dilihat.
Namun, berhati-hatilah karena solusi lain memiliki kelebihan sendiri yang mungkin lebih penting daripada solusi ini:
sumber
Anda bisa melakukannya dengan cara berikut.
Jadi itu akan menjatuhkan kolom jika sudah ada. Dan kemudian tambahkan kolom ke tabel tertentu.
sumber
Cukup periksa apakah kueri mengembalikan nama_kolom.
Jika tidak, jalankan sesuatu seperti ini:
Di mana Anda meletakkan sesuatu yang berguna untuk 'x' dan 'y' dan tentu saja tipe data yang cocok di mana saya menggunakan int.
sumber