기본 키를 기반으로 행을 삭제하는 (재귀) 함수를 작성했습니다. 캐스케이드를 삭제할 때 제약 조건을 만들고 싶지 않기 때문에 이것을 썼습니다. DBA로 복잡한 데이터 집합을 삭제하고 싶었지만 프로그래머가 모든 영향을 고려하지 않고 삭제를 계단식으로 만들 수는 없었습니다. 나는 여전히이 기능을 테스트 중이므로 버그가있을 수 있지만 DB에 다중 열 기본 (및 외래) 키가있는 경우 시도하지 마십시오. 또한 키는 모두 문자열 형식으로 표현할 수 있어야하지만 그러한 제한이없는 방식으로 작성 될 수 있습니다. 어쨌든이 기능을 아주 조금만 사용합니다. 모든 것에 대해 계단식 제약 조건을 사용하기에 너무 많은 데이터를 중요하게 생각합니다. 기본적으로이 함수는 스키마, 테이블 이름 및 기본 값 (문자열 형식)으로 전달됩니다. 그리고 해당 테이블에서 외래 키를 찾아 시작하여 데이터가 존재하지 않는지 확인합니다. 존재하는 경우 발견 된 데이터를 재귀 적으로 호출합니다. 무한 루프를 방지하기 위해 이미 삭제 표시된 데이터 배열을 사용합니다. 그것을 테스트하고 그것이 당신을 위해 어떻게 작동하는지 알려주십시오. 참고 : 조금 느립니다. 나는 그렇게 그렇게 부른다.
select delete_cascade('public','my_table','1');
create or replace function delete_cascade(p_schema varchar, p_table varchar, p_key varchar, p_recursion varchar[] default null)
returns integer as $$
declare
rx record;
rd record;
v_sql varchar;
v_recursion_key varchar;
recnum integer;
v_primary_key varchar;
v_rows integer;
begin
recnum := 0;
select ccu.column_name into v_primary_key
from
information_schema.table_constraints tc
join information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name and ccu.constraint_schema=tc.constraint_schema
and tc.constraint_type='PRIMARY KEY'
and tc.table_name=p_table
and tc.table_schema=p_schema;
for rx in (
select kcu.table_name as foreign_table_name,
kcu.column_name as foreign_column_name,
kcu.table_schema foreign_table_schema,
kcu2.column_name as foreign_table_primary_key
from information_schema.constraint_column_usage ccu
join information_schema.table_constraints tc on tc.constraint_name=ccu.constraint_name and tc.constraint_catalog=ccu.constraint_catalog and ccu.constraint_schema=ccu.constraint_schema
join information_schema.key_column_usage kcu on kcu.constraint_name=ccu.constraint_name and kcu.constraint_catalog=ccu.constraint_catalog and kcu.constraint_schema=ccu.constraint_schema
join information_schema.table_constraints tc2 on tc2.table_name=kcu.table_name and tc2.table_schema=kcu.table_schema
join information_schema.key_column_usage kcu2 on kcu2.constraint_name=tc2.constraint_name and kcu2.constraint_catalog=tc2.constraint_catalog and kcu2.constraint_schema=tc2.constraint_schema
where ccu.table_name=p_table and ccu.table_schema=p_schema
and TC.CONSTRAINT_TYPE='FOREIGN KEY'
and tc2.constraint_type='PRIMARY KEY'
)
loop
v_sql := 'select '||rx.foreign_table_primary_key||' as key from '||rx.foreign_table_schema||'.'||rx.foreign_table_name||'
where '||rx.foreign_column_name||'='||quote_literal(p_key)||' for update';
--raise notice '%',v_sql;
--found a foreign key, now find the primary keys for any data that exists in any of those tables.
for rd in execute v_sql
loop
v_recursion_key=rx.foreign_table_schema||'.'||rx.foreign_table_name||'.'||rx.foreign_column_name||'='||rd.key;
if (v_recursion_key = any (p_recursion)) then
--raise notice 'Avoiding infinite loop';
else
--raise notice 'Recursing to %,%',rx.foreign_table_name, rd.key;
recnum:= recnum +delete_cascade(rx.foreign_table_schema::varchar, rx.foreign_table_name::varchar, rd.key::varchar, p_recursion||v_recursion_key);
end if;
end loop;
end loop;
begin
--actually delete original record.
v_sql := 'delete from '||p_schema||'.'||p_table||' where '||v_primary_key||'='||quote_literal(p_key);
execute v_sql;
get diagnostics v_rows= row_count;
--raise notice 'Deleting %.% %=%',p_schema,p_table,v_primary_key,p_key;
recnum:= recnum +v_rows;
exception when others then recnum=0;
end;
return recnum;
end;
$$
language PLPGSQL;