簡體   English   中英

截斷 Postgres 數據庫中的所有表

[英]Truncating all tables in a Postgres database

在重建之前,我經常需要從我的 PostgreSQL 數據庫中刪除所有數據。 我將如何直接在 SQL 中執行此操作?

目前我已經想出了一個 SQL 語句,它返回我需要執行的所有命令:

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

但是一旦擁有它們,我就看不到以編程方式執行它們的方法。

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');

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  
      -- dangerous, test before you execute!
      RAISE NOTICE '%',  -- once confident, comment this line ...
      -- EXECUTE         -- ... and uncomment this one
         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
   -- dangerous, test before you execute!
   RAISE NOTICE '%',  -- once confident, comment this line ...
   -- EXECUTE         -- ... and uncomment this one
  (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
   -- dangerous, test before you execute!
   RAISE NOTICE '%',  -- once confident, comment this line ...
   -- EXECUTE         -- ... and uncomment this one
   (SELECT 'TRUNCATE TABLE ' || string_agg(oid::regclass::text, ', ') || ' CASCADE'
    FROM   pg_class
    WHERE  relkind = 'r'  -- only tables
    AND    relnamespace = 'public'::regnamespace
   );
END
$func$;

關於pg_classpg_tablesinformation_schema.tables的區別:

關於regclass和引用的表名:

重復使用

使用您的vanilla 結構和所有空表創建一個“模板”數據庫(讓我們將其命名為my_template )。 然后通過DROP /CREATE DATABASE循環:

DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;

非常,因為 Postgres 在文件級別復制整個結構。 沒有並發問題或其他開銷會減慢您的速度。

如果並發連接阻止您刪除數據庫,請考慮:

如果我必須這樣做,我將簡單地創建當前數據庫的模式 sql,然后刪除並創建數據庫,然后使用模式 sql 加載數據庫。

以下是涉及的步驟:

1)創建數據庫的模式轉儲( --schema-only

pg_dump mydb -s > schema.sql

2) 刪除數據庫

drop database mydb;

3) 創建數據庫

create database mydb;

4) 導入架構

psql mydb < schema.sql

在這種情況下,最好只使用一個空數據庫作為模板,當您需要刷新時,刪除現有數據庫並從模板創建一個新數據庫。

只需執行下面的查詢:

DO $$ DECLARE
    r RECORD;
BEGIN
    FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.tablename) || '';
    END LOOP;
END $$;

伙計們,更好、更干凈的方法是:

1)創建數據庫的模式轉儲(--schema-only)pg_dump mydb -s > schema.sql

2) drop database drop database mydb;

3)創建數據庫create database mydb;

4) 導入 Schema psql mydb < schema.sql

這對我有用!

祝你今天過得愉快。 海拉姆·沃克

能不能用動態SQL依次執行每條語句? 您可能必須編寫一個 PL/pgSQL 腳本來執行此操作。

http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html (第 38.5.4 節。執行動態命令)

清理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;

你也可以用 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 "{}"

您將需要調整架構名稱、密碼和用戶名以匹配您的架構。

如果你可以使用psql你可以使用\\gexec meta 命令來執行查詢輸出;

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 版本中引入的

很簡單,你可以運行這段SQL:

DO $$ DECLARE
  r RECORD;
BEGIN
  FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname =current_schema()) LOOP
    EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.tablename) || ' CASCADE';
  END LOOP;
END $$;

要在pgAdmin 中刪除數據並保留表結構,您可以執行以下操作:

  • 右鍵數據庫->備份,選擇“Schema only”
  • 刪除數據庫
  • 創建一個新的數據庫並像前者一樣命名
  • 右鍵新建數據庫->恢復->選擇備份,選擇“Schema only”

您可以使用類似的方法來獲取所有截斷查詢。

SELECT 'TRUNCATE TABLE ' ||  table_name || ';' 
  FROM information_schema.tables
 WHERE table_schema='schema_name'
   AND table_type='BASE TABLE';

我在這里看不到的一件事是截斷然后重置序列。 請注意,像此處給出的所有內容一樣的簡單截斷只會截斷表,但會將序列保留為其截斷前的值。 要在截斷時將序列重置為其起始值,請執行以下操作:

TRUNCATE TABLE table_name RESTART IDENTITY CASCADE;

您可以將該 RESTART IDENTITY 添加到您喜歡的任何答案中,無需在此處重復。 CASCADE 適用於您可能面臨的任何外鍵約束。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM