回答:
これは、「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;
$$
これらをパラメーターとして渡すことはできません。クライアント側で文字列の変数置換を行う必要がありますが、これは自己完結型のクエリであり、列が既に存在する場合にのみメッセージを発行し、存在しない場合は追加します。他のエラー(無効なデータ型など)で失敗し続けます。
これらが外部ソースからのランダムな文字列である場合、これらのメソッドのいずれかを実行することはお勧めしません。どの方法(クエリとして実行されるクレインサイドまたはサーバーサイドの動的文字列)を使用する場合でも、SQLインジェクション攻撃にさらされるため、これは災害のレシピになります。
DO $$
失敗する理由がわかりません。私もdev postgres docsの例で示されているDO $$;
ブロックを開始するまで失敗しDO $$DECLARE r record;
ました。
END; $$
構文エラーが発生し(Postgres 9.3)、END $$;
代わりに使用しなければなり
EXCEPTION
)は少し一般的で、IF NOT EXISTS
構文のないタスク(たとえば)に使用できますALTER TABLE ... ADD CONSTRAINT
。
Postgres 9.6このオプションを使用して行うことができますif not exists
ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name INTEGER;
ADD CONSTRAINT IF NOT EXISTS
まだありません。
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;
コール:
SELECT f_add_col('public.kat', 'pfad1', 'int');
TRUE
成功した場合は戻りますFALSE
(それ以外の場合は列が既に存在します)。
無効なテーブルまたは型名の例外を発生させます。
これはDO
ステートメントで実行できますが、DO
ステートメントは何も返すことができません。そしてそれが繰り返し使用される場合は、関数を作成します。
私は、使用オブジェクト識別子タイプ regclass
とregtype
するため_tbl
と_type
)は直ちに(安い可能な方法)の両方のSQLインジェクションおよびb)のチェックの有効性を防止します。列名_col
は、で引き続き無害化する必要EXECUTE
がありquote_ident()
ます。この関連する回答の詳細説明:
format()
Postgres 9.1以降が必要です。古いバージョンでは手動で連結します:
EXECUTE 'ALTER TABLE ' || _tbl || ' ADD COLUMN ' || quote_ident(_col) || ' ' || _type;
テーブル名をスキーマで修飾できますが、必須ではありません。
関数呼び出しで識別子を二重引用符で囲んで、キャメルケースと予約語を保持することができます(ただし、このいずれも使用しないでください)。
のpg_catalog
代わりにクエリを実行しますinformation_schema
。詳細な説明:
現在受け入れられている回答のEXCEPTION
ような句を含むブロックは、かなり低速です。これは通常、より単純で高速です。ドキュメント:
ヒント:
EXCEPTION
句を含むブロックは、句を含まないブロックよりも、出入りするのに非常にコストがかかります。したがって、必要がない場合は使用しないでくださいEXCEPTION
。
DO
ステートメントがありません。受け入れるためのわずかな変更でDEFAULT
、これは完全に機能しました!
次の選択クエリはtrue/false
、EXISTS()
関数を使用してを返します。
EXISTS():EXISTS
の引数は、任意のSELECTステートメントまたはサブクエリです。サブクエリは、行を返すかどうかを判断するために評価されます。少なくとも1つの行を返す場合、EXISTSの結果は「true」です。サブクエリが行を返さない場合、EXISTSの結果は "false"です。
SELECT EXISTS(SELECT column_name
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'x'
AND column_name = 'y');
次の動的SQLステートメントを使用してテーブルを変更します
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
$$
以下の関数は、存在する場合は列をチェックして適切なメッセージを返し、そうでない場合は列をテーブルに追加します。
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;
$$
これは基本的にsolaからのソリューションですが、少しクリーンアップされています。それは、私が彼の解決策を単に「改善」したくなかっただけでなく十分に異なっています(それに、私は一種の失礼だと思います)。
主な違いは、EXECUTE形式を使用することです。少しすっきりしていると思いますが、PostgresSQL 9.1以降を使用している必要があります。
これは9.1でテストされ、動作します。注:schema / table_name / data_typeが無効な場合、エラーが発生します。これは「修正」できますが、多くの場合は正しい動作である可能性があります。
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';
使用法:
select add_column('public', 'foo', 'bar', 'varchar(30)');
移行スクリプトに追加して関数を呼び出し、完了したらドロップできます。
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();
私の場合、それが作成された理由により、移行スクリプトが異なるスキーマにまたがることは少し難しいです。
これを回避するために、エラーをキャッチして無視した例外を使用しました。これには、見やすくなるという良い副作用もありました。
ただし、他のソリューションには、おそらくこのソリューションを上回る独自の利点があることに注意してください。
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 $$;
あなたは以下の方法でそれを行うことができます。
ALTER TABLE tableName drop column if exists columnName;
ALTER TABLE tableName ADD COLUMN columnName character varying(8);
そのため、列がすでに存在する場合は削除されます。次に、特定のテーブルに列を追加します。
クエリがcolumn_nameを返したかどうかを確認するだけです。
そうでない場合は、次のように実行します。
ALTER TABLE x ADD COLUMN y int;
'x'と 'y'に役立つものを配置した場所と、もちろんintを使用した適切なデータ型。
DO $$ BEGIN BEGIN CREATE INDEX type_idx ON table1 USING btree (type); EXCEPTION WHEN duplicate_table THEN RAISE NOTICE 'Index exists.'; END; END;$$;
同じ方法でCREATE INDEX
;)ありがとうございます