Postgres 데이터베이스에서 모든 테이블 자르기


155

재 구축하기 전에 PostgreSQL 데이터베이스에서 모든 데이터를 정기적으로 삭제해야합니다. SQL에서 직접 어떻게합니까?

현재 나는 실행 해야하는 모든 명령을 반환하는 SQL 문을 생각해 냈습니다.

SELECT 'TRUNCATE TABLE ' ||  tablename || ';' FROM pg_tables WHERE tableowner='MYUSER';

그러나 일단 프로그래밍 방식으로 실행하는 방법을 알 수 없습니다.

답변:


226

FrustratedWithFormsDesigner가 정확하면 PL / pgSQL이이를 수행 할 수 있습니다. 스크립트는 다음과 같습니다.

CREATE OR REPLACE FUNCTION truncate_tables(username IN VARCHAR) RETURNS void AS $$
DECLARE
    statements CURSOR FOR
        SELECT tablename FROM pg_tables
        WHERE tableowner = username AND schemaname = 'public';
BEGIN
    FOR stmt IN statements LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' CASCADE;';
    END LOOP;
END;
$$ LANGUAGE plpgsql;

그러면 저장된 함수 (한 번만 수행하면 됨)가 생성되어 나중에 다음과 같이 사용할 수 있습니다.

SELECT truncate_tables('MYUSER');

1
조금 rejig해야했지만 그 후 그것은 매력처럼 작동했습니다! 나는 전에 plpgsql을 사용한 적이 없기 때문에 나이가 들었습니다. 감사! 그것을 필요로하는 사람이라면 누구나이 게시물의 맨 아래에 사용한 코드를 추가했습니다.
Sig

죄송합니다, Oracle PL / SQL에서 생각하고 있었을 것입니다 :( 위 코드에서 구문 오류를 수정했습니다.
Henning

1
SELECT 문을 FOR 루프로 직접 이동할 수도 있습니다. DECLARE r RECORD;그때 for 루프 : FOR r IN SELECT tablename FROM pg_tables LOOP
Michael Buen

6
TRUNCATE TABLE에 CASCADE를 추가하겠습니다
Bogdan Gusiev

3
세상에! 방금 "공개"스키마에서 모든 테이블을 자릅니다. pls는 "스키마"의 다른 매개 변수를 추가하여 함수가 제공된 스키마에서만 테이블을 자릅니다!
roneo

95

plpgsql에서는 명시 적 커서가 거의 필요하지 않습니다. 루프 의 더 간단하고 빠른 암시 적 커서 를 사용하십시오 FOR.

참고 : 테이블 이름은 데이터베이스마다 고유하지 않으므로 테이블 이름을 스키마로 한정해야합니다. 또한 함수를 기본 스키마 'public'으로 제한합니다. 여러분의 필요에 적응하지만, 시스템 스키마를 제외해야 pg_*하고 information_schema.

이 기능에 매우주의 하십시오 . 그들은 당신의 데이터베이스를 핵화합니다. 어린이 안전 장치를 추가했습니다. 폭탄을 프라이밍하기 위해 RAISE NOTICE줄을 주석 처리하고 주석 EXECUTE을 제거하십시오 ...

CREATE OR REPLACE FUNCTION f_truncate_tables(_username text)
  RETURNS void AS
$func$
DECLARE
   _tbl text;
   _sch text;
BEGIN
   FOR _sch, _tbl IN 
      SELECT schemaname, tablename
      FROM   pg_tables
      WHERE  tableowner = _username
      AND    schemaname = 'public'
   LOOP
      RAISE NOTICE '%',
      -- EXECUTE  -- dangerous, test before you execute!
         format('TRUNCATE TABLE %I.%I CASCADE', _sch, _tbl);
   END LOOP;
END
$func$ LANGUAGE plpgsql;

format()Postgres 9.1 이상이 필요합니다. 이전 버전에서는 다음과 같이 쿼리 문자열을 연결합니다.

'TRUNCATE TABLE ' || quote_ident(_sch) || '.' || quote_ident(_tbl)  || ' CASCADE';

단일 명령, 루프 없음

TRUNCATE한 번에 여러 테이블을 사용할 수 있으므로 커서 나 루프가 전혀 필요하지 않습니다.

모든 테이블 이름을 집계하고 단일 명령문을 실행하십시오. 더 간단하고 빠르게 :

CREATE OR REPLACE FUNCTION f_truncate_tables(_username text)
  RETURNS void AS
$func$
BEGIN
   RAISE NOTICE '%', 
   -- EXECUTE  -- dangerous, test before you execute!
  (SELECT 'TRUNCATE TABLE '
       || string_agg(format('%I.%I', schemaname, tablename), ', ')
       || ' CASCADE'
   FROM   pg_tables
   WHERE  tableowner = _username
   AND    schemaname = 'public'
   );
END
$func$ LANGUAGE plpgsql;

요구:

SELECT truncate_tables('postgres');

정제 된 쿼리

기능이 필요하지 않습니다. Postgres 9.0 이상에서는 DO명령문 에서 동적 명령을 실행할 수 있습니다 . 그리고 Postgres 9.5 이상에서는 구문이 더 간단 할 수 있습니다.

DO
$func$
BEGIN
   RAISE NOTICE '%', 
   -- EXECUTE
   (SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' CASCADE'
    FROM   pg_class
    WHERE  relkind = 'r'  -- only tables
    AND    relnamespace = 'public'::regnamespace
   );
END
$func$;

사이의 차이에 대해 pg_class, pg_tables그리고 information_schema.tables:

정보 regclass및 인용 테이블 이름 :

반복 사용

바닐라 구조와 모든 빈 테이블을 사용 하여 "템플릿"데이터베이스 (이름을 지정 my_template)를 작성하십시오. 그런 다음 DROP/CREATE DATABASE 주기를 수행하십시오.

DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;

이다 매우 빠른 , 파일 수준에서 포스트 그레스 복사 전체 구조 때문이다. 동시성 문제 또는 기타 오버 헤드가 느려지지 않습니다.

동시 연결로 인해 DB가 삭제되지 않으면 다음을 고려하십시오.


1
이 마지막 함수가 모든 데이터베이스를 삭제했음을 주목할 가치가 있습니다. 현재 연결된 사람뿐만 아니라 .... 그렇습니다 ... 나이브라고 불러주지 만 실제로는이 게시물에서 명확하지 않았습니다.
Amalgovinus

@Amalgovinus : 마지막 기능은 무엇입니까? 내 대답의 함수 중 현재 데이터베이스 외부의 항목을 만지지 마십시오 ( DROP DATABASE mydb확실히 제외하십시오 ). 스키마 와 데이터베이스 를 혼동 하고 있습니까?
Erwin Brandstetter 1

3
@Amalgovinus : 아니요, 불가능합니다. DO명령 (다른 SQL 문 같은) 현재 데이터베이스에서 실행되는 독점적으로 . Postgres는 동일한 트랜잭션에서 다른 데이터베이스에 액세스 할 수있는 방법이 없습니다. 그렇게하려면 dblink 또는 FDW를 사용해야합니다. 그러나 않습니다 추가하지 않는 - 현재 데이터베이스의 모든 스키마에 영향을주는 WHERE t.schemaname = 'public'이 특별한 경우에 하나의 특정 스키마에 대한 효과를 제한 할 수 있습니다.
Erwin Brandstetter

1
그 템플릿에 대해 알고 정말 반갑습니다. 데이터베이스 재설정 / 준비가 필요한 자동화 된 테스트 시나리오에서도 유용 할 수 있습니다.
hbobenicio

3
훌륭한 답변에 감사드립니다. TRUNCATE 명령을 반환하는 "Single command, no loop"를 사용하고 있습니다. 어떻게 실행해야합니까?
Mahyar

40

이 작업을 수행 해야하는 경우 단순히 현재 db의 스키마 sql을 만든 다음 삭제 및 db를 생성 한 다음 schema sql로 db를로드합니다.

다음은 관련 단계입니다.

1) 데이터베이스의 스키마 덤프 생성 ( --schema-only)

pg_dump mydb -s > schema.sql

2) 데이터베이스 삭제

drop database mydb;

3) 데이터베이스 생성

create database mydb;

4) 가져 오기 스키마

psql mydb < schema.sql


9

이 경우 템플릿으로 사용하는 빈 데이터베이스 만 있으면되고 새로 고쳐야 할 때 기존 데이터베이스를 삭제하고 템플릿에서 새 데이터베이스를 작성하는 것이 좋습니다.



3

bash를 사용 하여이 작업을 수행 할 수도 있습니다.

#!/bin/bash
PGPASSWORD='' psql -h 127.0.0.1 -Upostgres sng --tuples-only --command "SELECT 'TRUNCATE TABLE ' || schemaname || '.' ||  tablename || ';' FROM pg_tables WHERE schemaname in ('cms_test', 'ids_test', 'logs_test', 'sps_test');" | 
tr "\\n" " " | 
xargs -I{} psql -h 127.0.0.1 -Upostgres sng --command "{}"

스키마와 일치하도록 스키마 이름, 비밀번호 및 사용자 이름을 조정해야합니다.


3

청소 AUTO_INCREMENT버전 :

CREATE OR REPLACE FUNCTION truncate_tables(username IN VARCHAR) RETURNS void AS $$
DECLARE
    statements CURSOR FOR
        SELECT tablename FROM pg_tables
        WHERE tableowner = username AND schemaname = 'public';
BEGIN
    FOR stmt IN statements LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(stmt.tablename) || ' CASCADE;';

        IF EXISTS (
            SELECT column_name 
            FROM information_schema.columns 
            WHERE table_name=quote_ident(stmt.tablename) and column_name='id'
        ) THEN
           EXECUTE 'ALTER SEQUENCE ' || quote_ident(stmt.tablename) || '_id_seq RESTART WITH 1';
        END IF;

    END LOOP;
END;
$$ LANGUAGE plpgsql;

3

더 좋고 깨끗한 방법은 다음과 같습니다.

1) 데이터베이스의 스키마 덤프 생성 (-스키마 전용) pg_dump mydb -s> schema.sql

2) 데이터베이스 삭제 데이터베이스 mydb를 삭제하십시오.

3) 데이터베이스 작성 데이터베이스 mydb를 작성하십시오.

4) 스키마 psql mydb <schema.sql 가져 오기

그것은 나를 위해 일한다!

좋은 하루 보내세요 히람 워커


2

당신이 사용할 수있는 경우 psql 프로그램을 당신이 사용할 수있는 \gexec쿼리 출력을 실행하기 위해 메타 명령을;

SELECT
    format('TRUNCATE TABLE %I.%I', ns.nspname, c.relname)
  FROM pg_namespace ns 
  JOIN pg_class c ON ns.oid = c.relnamespace
  JOIN pg_roles r ON r.oid = c.relowner
  WHERE
    ns.nspname = 'table schema' AND                               -- add table schema criteria 
    r.rolname = 'table owner' AND                                 -- add table owner criteria
    ns.nspname NOT IN ('pg_catalog', 'information_schema') AND    -- exclude system schemas
    c.relkind = 'r' AND                                           -- tables only
    has_table_privilege(c.oid, 'TRUNCATE')                        -- check current user has truncate privilege
  \gexec 

참고 \gexec버전 9.6에 도입


1

pgAdmin 에서 데이터를 제거하고 테이블 구조를 보존하려면 다음을 수행하십시오.

  • 데이터베이스-> 백업을 마우스 오른쪽 단추로 클릭하고 "스키마 만"을 선택하십시오.
  • 데이터베이스를 삭제
  • 새 데이터베이스를 작성하고 이전과 같이 이름을 지정하십시오.
  • 새 데이터베이스를 마우스 오른쪽 단추로 클릭-> 복원-> 백업을 선택하고 "스키마 만"을 선택하십시오.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.