Postgres डेटाबेस में सभी तालिकाओं को काट-छाँट करना


155

मुझे नियमित रूप से पुनर्निर्माण से पहले अपने PostgreSQL डेटाबेस से सभी डेटा को हटाने की आवश्यकता है। मैं इसे सीधे 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
थोड़ा रिजेक्ट होना था लेकिन उसके बाद यह एक आकर्षण की तरह काम करता था! मैंने इससे पहले कभी भी plpgsql का इस्तेमाल नहीं किया है, तो इससे मुझे उम्र लग जाएगी। धन्यवाद! जिस किसी को भी इसकी आवश्यकता है, मैंने इस कोड को इस पोस्ट के निचले हिस्से का उपयोग करके जोड़ा है।
सिग

क्षमा करें, मैं शायद Oracle PL / SQL में सोच रहा था :( मैंने अपने कोड में सिंटैक्स त्रुटि को ठीक कर दिया है।
हेनिंग

1
आप सीधे लूप के लिए SELECT स्टेटमेंट को भी स्थानांतरित कर सकते हैं। DECLARE r RECORD;फिर पाश के लिए: FOR r IN SELECT tablename FROM pg_tables LOOP
माइकल ब्यून

6
मैं CASCADE को TRUNCATE TABLE
Bogdan Gusiev

3
हे भगवान!! मैंने बस "सार्वजनिक" स्कीमा में अपनी सभी तालिकाओं को काट दिया .... pls "स्कीमा" का एक और पैरामीटर जोड़ें ताकि फ़ंक्शन केवल उस स्कीमा पर तालिकाओं को काट दे जो प्रदान की जाती है!
रोनो

95

प्लस्पगक्ल में स्पष्ट रूप से अभिशाप की आवश्यकता होती है। लूप के सरल और तेज़ निहित कर्सर का उपयोग करें FOR:

नोट: चूँकि तालिका के नाम प्रति डेटाबेस के लिए अद्वितीय नहीं हैं, इसलिए आपको सुनिश्चित करने के लिए स्कीमा-योग्यता तालिका नामों को रखना होगा। इसके अलावा, मैं फ़ंक्शन को डिफ़ॉल्ट स्कीमा 'सार्वजनिक' तक सीमित करता हूं। अपनी आवश्यकताओं के अनुकूल, लेकिन सिस्टम स्कीमा को बाहर करना सुनिश्चित करें pg_*और information_schema

Be बहुत सावधान इन कार्यों के साथ। वे आपके डेटाबेस को न्यूड करते हैं। मैंने एक बाल सुरक्षा उपकरण जोड़ा। बम को प्राइम करने के लिए 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()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');

परिष्कृत क्वेरी

तुम भी एक समारोह की जरूरत नहीं है। 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_tablesinformation_schema.tables

regclassतालिका नामों के बारे में और उद्धृत:

बार-बार उपयोग के लिए

अपनी वेनिला संरचना और सभी खाली तालिकाओं के साथ एक "टेम्पलेट" डेटाबेस (इसे नाम दें my_template) बनाएं । फिर एक के माध्यम से जाना DROP/CREATE DATABASE चक्र:

DROP DATABASE mydb;
CREATE DATABASE mydb TEMPLATE my_template;

यह बहुत तेज़ है , क्योंकि Postgres फ़ाइल स्तर पर संपूर्ण संरचना की प्रतिलिपि बनाता है। कोई समसामयिक समस्या या अन्य ओवरहेड आपको धीमा नहीं कर रहा है।

यदि समवर्ती कनेक्शन आपको DB छोड़ने से रोकते हैं, तो विचार करें:


1
यह ध्यान देने योग्य है कि इस अंतिम समारोह ने सभी डेटाबेस को मिटा दिया। वर्तमान में केवल एक ही जुड़ा हुआ नहीं है ... हाँ ... मुझे माफ़ कर दो लेकिन वास्तव में इस पोस्ट से स्पष्ट नहीं था।
अमलगोविनास

@ ऐमलगोविनस: कौन सा अंतिम कार्य? मेरे उत्तर में कोई भी कार्य वर्तमान डेटाबेस के बाहर ( DROP DATABASE mydbस्पष्ट रूप से छोड़कर ) कुछ भी नहीं छूता है । क्या आप डेटाबेस के साथ स्कीमा को भ्रमित कर रहे हैं , हो सकता है?
एरविन ब्रान्डसेट्टर

3
@ ऐमलगोविनस: नहीं, यह असंभव है। DOआदेश (किसी अन्य एसक्यूएल बयान की तरह) वर्तमान डेटाबेस में निष्पादित किया जाता है विशेष रूप से । पोस्टग्रेज के पास एक ही लेनदेन में अन्य डेटाबेस तक पहुंचने का कोई रास्ता नहीं है। ऐसा करने के लिए आपको dblink या FDW का उपयोग करना होगा। लेकिन यह वर्तमान डेटाबेस में सभी स्कीमाओं को प्रभावित करता है - जब तक कि आप WHERE t.schemaname = 'public'इस विशेष मामले में एक विशेष स्कीमा के प्रभाव को प्रतिबंधित नहीं करते।
एरविन ब्रान्डसेट्टर

1
उन टेम्पलेट्स के बारे में जानकर बहुत अच्छा लगा। यह स्वचालित परीक्षण परिदृश्यों में भी उपयोगी हो सकता है, जहाँ डेटाबेस रीसेट / तैयारी की आवश्यकता हो सकती है।
hbobenicio

3
महान उत्तर के लिए धन्यवाद, मैं "सिंगल कमांड, नो लूप" का उपयोग कर रहा हूं जो TRUNCATE कमांड देता है, मुझे इसे निष्पादित करने के बारे में कैसे जाना चाहिए?
महियार

40

अगर मुझे ऐसा करना है, तो मैं बस db का स्कीमा sql बनाऊँगा, फिर db को ड्रॉप और क्रिएट करेगा, फिर स्कीम 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

क्या आप बदले में प्रत्येक कथन को निष्पादित करने के लिए गतिशील एसक्यूएल का उपयोग कर सकते हैं? ऐसा करने के लिए आपको शायद PL / pgSQL स्क्रिप्ट लिखनी होगी।

http://www.postgresql.org/docs/8.3/static/plpgsql-statements.html (धारा 38.5.4। डायनामिक कमांड निष्पादित करना)।


3

आप इसे बैश के साथ भी कर सकते हैं:

#!/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) डेटाबेस का स्कीमा डंप बनाएं (--schema-only) pg_dump mydb -s> schema.sll

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 में तालिका संरचनाओं के संरक्षण के लिए:

  • डेटाबेस पर राइट-क्लिक करें -> बैकअप, "स्कीमा केवल" चुनें
  • डेटाबेस ड्रॉप करें
  • एक नया डेटाबेस बनाएं और इसे पूर्व की तरह नाम दें
  • नए डेटाबेस पर राइट-क्लिक करें -> पुनर्स्थापित करें -> बैकअप का चयन करें, "स्कीमा केवल" चुनें
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.