Yanıtlar:
İşte "DO" ifadesini kullanan kısa ve tatlı bir sürüm:
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;
$$
Bunları parametre olarak aktaramazsınız, istemci tarafındaki dizede değişken ikame yapmanız gerekir, ancak bu yalnızca sütun zaten varsa bir mesaj yayınlayan bağımsız bir sorgudur. diğer hatalarda (geçersiz veri türü gibi) başarısız olmaya devam eder.
Dış kaynaklardan gelen rastgele dizeler ise bu yöntemlerden HERHANGİ BİRİNİ yapmayı önermiyorum. Hangi yöntemi kullanırsanız kullanın (sorgu olarak yürütülen cleint tarafı veya sunucu tarafı dinamik dizeler), sizi SQL enjeksiyon saldırılarına açtığı için felaket için bir reçete olacaktır.
DO $$
başarısız olduğundan emin değilim . Dev postgres belgelerinde bir örnekte verilen DO $$;
bloğa başlayana kadar hangisinin başarısız olduğunu da denedim . DO $$DECLARE r record;
END; $$
END $$;
EXCEPTION
) biraz daha geneldir ve IF NOT EXISTS
sözdizimi olmayan görevler için kullanılabilir - örneğin ALTER TABLE ... ADD CONSTRAINT
.
İle Postgres 9.6 Bu seçeneği kullanılarak yapılabilirif not exists
ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;
ADD CONSTRAINT IF NOT EXISTS
yok.
CREATE OR REPLACE function f_add_col(_tbl regclass, _col text, _type regtype)
RETURNS bool AS
$func$
BEGIN
IF EXISTS (SELECT 1 FROM pg_attribute
WHERE attrelid = _tbl
AND attname = _col
AND NOT attisdropped) THEN
RETURN FALSE;
ELSE
EXECUTE format('ALTER TABLE %s ADD COLUMN %I %s', _tbl, _col, _type);
RETURN TRUE;
END IF;
END
$func$ LANGUAGE plpgsql;
Aramak:
SELECT f_add_col('public.kat', 'pfad1', 'int');
TRUE
Başarıyı döndürür , aksi takdirde FALSE
(sütun zaten var).
Geçersiz tablo veya tür adı için bir istisna oluşturur.
Bu bir deyimle yapılabilir DO
, ancak DO
deyimler hiçbir şey döndüremez. Ve tekrarlanan kullanım içinse, bir işlev yaratacağım.
Kullandığım nesne tanımlayıcısı tipi regclass
ve regtype
için _tbl
ve _type
: a) SQL enjeksiyon ve b) hemen her iki kontrol geçerliliği (mümkün olan en ucuz şekilde) engeller. Sütun adı _col
hala dezenfekte edilmesi için gelmiştir EXECUTE
ile quote_ident()
. Bu cevapta daha fazla açıklama:
format()
Postgres 9.1+ sürümünü gerektirir. Eski sürümler için el ile birleştirme:
EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type;
Tablo adınızı şema niteleyebilir, ancak zorunda değilsiniz.
Deve durumunu ve ayrılmış sözcükleri korumak için işlev çağrısındaki tanımlayıcıları iki kez tırnak içine alabilirsiniz (ancak bunların hiçbirini yine de kullanmamalısınız).
Ben pg_catalog
yerine sorgu information_schema
. Detaylı açıklama:
Şu anda kabul edilen cevapEXCEPTION
gibi bir madde içeren bloklar oldukça yavaştır. Bu genellikle daha basit ve daha hızlıdır. Dökümantasyon:
İpucu: Bir
EXCEPTION
cümle içeren bir bloğun girilmesi ve çıkması, bir blok olmayan bir bloktan önemli ölçüde daha pahalıdır. Bu nedenle,EXCEPTION
ihtiyaç duymadan kullanmayın .
DO
kabul etmek için hafif bir modifikasyona sahip değil DEFAULT
ve bu mükemmel çalıştı!
Aşağıdaki seçme sorgusu işlevi true/false
kullanarak dönecektir EXISTS()
.
EXISTS () :
EXISTS argümanı isteğe bağlı bir SELECT deyimi veya alt sorgusudur. Alt sorgu, satır döndürüp döndürmediğini belirlemek için değerlendirilir. En az bir satır döndürürse, EXISTS sonucu "true" olur; alt sorgu satır döndürmezse, EXISTS sonucu "false" olur
SELECT EXISTS(SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'x'
AND column_name = 'y');
ve tablonuzu değiştirmek için aşağıdaki dinamik SQL deyimini kullanın
DO
$$
BEGIN
IF NOT EXISTS (SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'x'
AND column_name = 'y') THEN
ALTER TABLE x ADD COLUMN y int DEFAULT NULL;
ELSE
RAISE NOTICE 'Already exists';
END IF;
END
$$
Aşağıdaki fonksiyon varsa sütunu kontrol eder, uygun mesajı döndürürse sütunu tabloya ekler.
create or replace function addcol(schemaname varchar, tablename varchar, colname varchar, coltype varchar)
returns varchar
language 'plpgsql'
as
$$
declare
col_name varchar ;
begin
execute 'select column_name from information_schema.columns where table_schema = ' ||
quote_literal(schemaname)||' and table_name='|| quote_literal(tablename) || ' and column_name= '|| quote_literal(colname)
into col_name ;
raise info ' the val : % ', col_name;
if(col_name is null ) then
col_name := colname;
execute 'alter table ' ||schemaname|| '.'|| tablename || ' add column '|| colname || ' ' || coltype;
else
col_name := colname ||' Already exist';
end if;
return col_name;
end;
$$
Bu temelde sola'nın çözümü, ancak sadece biraz temizlendi. Sadece onun çözümünü "geliştirmek" istemediğim kadar farklı (artı, bu kaba olduğunu düşünüyorum).
Temel fark EXECUTE biçimini kullanmasıdır. Hangi biraz daha temiz olduğunu düşünüyorum, ama inanıyorum ki PostgresSQL 9.1 veya daha yeni olması gerekir.
Bu 9.1 üzerinde test edildi ve çalışıyor. Not: Şema / tablo_adı / veya veri_türü geçersizse bir hata oluşturur. Bu "düzeltilebilir", ancak birçok durumda doğru davranış olabilir.
CREATE OR REPLACE FUNCTION add_column(schema_name TEXT, table_name TEXT,
column_name TEXT, data_type TEXT)
RETURNS BOOLEAN
AS
$BODY$
DECLARE
_tmp text;
BEGIN
EXECUTE format('SELECT COLUMN_NAME FROM information_schema.columns WHERE
table_schema=%L
AND table_name=%L
AND column_name=%L', schema_name, table_name, column_name)
INTO _tmp;
IF _tmp IS NOT NULL THEN
RAISE NOTICE 'Column % already exists in %.%', column_name, schema_name, table_name;
RETURN FALSE;
END IF;
EXECUTE format('ALTER TABLE %I.%I ADD COLUMN %I %s;', schema_name, table_name, column_name, data_type);
RAISE NOTICE 'Column % added to %.%', column_name, schema_name, table_name;
RETURN TRUE;
END;
$BODY$
LANGUAGE 'plpgsql';
kullanımı:
select add_column('public', 'foo', 'bar', 'varchar(30)');
Geçiş komut dosyalarına eklenebilir işlevi çağırır ve bittiğinde bırak.
create or replace function patch_column() returns void as
$$
begin
if exists (
select * from information_schema.columns
where table_name='my_table'
and column_name='missing_col'
)
then
raise notice 'missing_col already exists';
else
alter table my_table
add column missing_col varchar;
end if;
end;
$$ language plpgsql;
select patch_column();
drop function if exists patch_column();
Benim durumumda, nasıl yaratıldığı için, göç senaryolarımızın farklı şemalarda kesilmesi biraz zor.
Bu sorunu gidermek için, hatayı yakalayıp görmezden gelen bir istisna kullandık. Bu ayrıca bakılması çok daha kolay olmanın güzel bir yan etkisi oldu.
Bununla birlikte, diğer çözümlerin muhtemelen bu çözümden daha ağır olan kendi avantajlarına sahip olduğuna dikkat edin:
DO $$
BEGIN
BEGIN
ALTER TABLE IF EXISTS bobby_tables RENAME COLUMN "dckx" TO "xkcd";
EXCEPTION
WHEN undefined_column THEN RAISE NOTICE 'Column was already renamed';
END;
END $$;
Bunu takip ederek yapabilirsiniz.
ALTER TABLE tableName drop column if exists columnName;
ALTER TABLE tableName ADD COLUMN columnName character varying(8);
Dolayısıyla, zaten varsa sütunu düşürür. Ve sonra sütunu belirli bir tabloya ekleyin.
Sorgunun bir sütun_adı döndürüp döndürmediğini kontrol etmeniz yeterlidir.
Değilse, böyle bir şey yürütün:
ALTER TABLE x ADD COLUMN y int;
'X' ve 'y' için yararlı bir şey koyduğunuz ve tabii ki int kullandığım yerde uygun bir veri türü.
DO $$ BEGIN BEGIN CREATE INDEX type_idx ON table1 USING btree (type); EXCEPTION WHEN duplicate_table THEN RAISE NOTICE 'Index exists.'; END; END;$$;
Aynı yaklaşımCREATE INDEX
;) Cevabınız için teşekkürler,