답변:
"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
.
로 포스트 그레스 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
명령문은 아무것도 리턴 할 수 없습니다. 그리고 반복적으로 사용한다면 함수를 만들 것입니다.
I는 사용 객체 식별자 유형 regclass
과 regtype
대 _tbl
하고 _type
있는 a) 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
완벽하게 작동했습니다!
다음의 select 쿼리는 함수를 true/false
사용하여 를 반환 EXISTS()
합니다.
EXISTS () : EXISTS
의 인수는 임의의 SELECT 문 또는 하위 쿼리입니다. 부속 조회는 행을 리턴하는지 판별하기 위해 평가됩니다. 하나 이상의 행을 반환하면 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;
$$
이것은 기본적으로 솔라의 해결책이지만 조금만 정리했습니다. 내가 그의 해결책을 "개선"하고 싶지 않다는 것은 충분히 다르다.
주요 차이점은 EXECUTE 형식을 사용한다는 것입니다. 좀 더 깨끗하다고 생각하지만 PostgresSQL 9.1 이상을 사용해야한다는 것을 의미합니다.
이것은 9.1에서 테스트되었으며 작동합니다. 참고 : schema / table_name / or 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
) 귀하의 답변을 주셔서 감사합니다,