Как я могу удалить все таблицы в PostgreSQL, работая из командной строки?
Я не хочу удалять саму базу данных, только все таблицы и все данные в них.
Как я могу удалить все таблицы в PostgreSQL, работая из командной строки?
Я не хочу удалять саму базу данных, только все таблицы и все данные в них.
Если все ваши таблицы находятся в одной схеме, этот подход может работать (ниже код предполагает, что имя вашей схемы public
)
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
Если вы используете PostgreSQL 9.3 или новее, вам также может понадобиться восстановить гранты по умолчанию.
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
Вы можете написать запрос для создания SQL script следующим образом:
select 'drop table "' || tablename || '" cascade;' from pg_tables;
Или:
select 'drop table if exists "' || tablename || '" cascade;' from pg_tables;
В случае, если некоторые таблицы автоматически удаляются из-за опции каскада в предыдущем предложении.
Кроме того, как указано в комментариях, вам может потребоваться отфильтровать таблицы, которые вы хотите удалить с помощью имени схемы:
select 'drop table if exists "' || tablename || '" cascade;'
from pg_tables
where schemaname = 'public'; -- or any other schema
И затем запустите его.
Также будет работать славная COPY + PASTE.
Наиболее приемлемый ответ на момент написания статьи (январь 2014 г.):
drop schema public cascade;
create schema public;
Это работает, однако если ваше намерение состоит в том, чтобы восстановить общедоступную схему в ее первоначальное состояние, это не полностью решит задачу. В pgAdmin III для PostgreSQL 9.3.1, если вы нажмете на "публичную" схему, созданную таким образом, и посмотрите на "панель SQL", вы увидите следующее:
-- Schema: public
-- DROP SCHEMA public;
CREATE SCHEMA public
AUTHORIZATION postgres;
Однако, напротив, новая база данных будет иметь следующее:
-- Schema: public
-- DROP SCHEMA public;
CREATE SCHEMA public
AUTHORIZATION postgres;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
COMMENT ON SCHEMA public
IS 'standard public schema';
Для меня я использую веб-фреймворк Python, который создает таблицы базы данных (web2py), используя ранее вызванные проблемы:
<class 'psycopg2.ProgrammingError'> no schema has been selected to create in
Поэтому, на мой взгляд, полностью правильный ответ:
DROP SCHEMA public CASCADE;
CREATE SCHEMA public;
GRANT ALL ON SCHEMA public TO postgres;
GRANT ALL ON SCHEMA public TO public;
COMMENT ON SCHEMA public IS 'standard public schema';
Также обратите внимание, что для выдачи этих команд в pgAdmin III я использовал инструмент Query (значок лупы "Выполнять произвольные запросы SQL") или вы можете использовать Plugins-> Консоль PSQL
Вы можете удалить все таблицы с помощью
DO $$ DECLARE
r RECORD;
BEGIN
-- if the schema you operate on is not "current", you will want to
-- replace current_schema() in query with 'schematodeletetablesfrom'
-- *and* update the generate 'DROP...' accordingly.
FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';
END LOOP;
END $$;
IMO это лучше, чем drop schema public
, потому что вам не нужно воссоздавать schema
и восстанавливать все гранты.
Дополнительный бонус, который не требует внешнего языка сценариев, а также копирование сгенерированного SQL обратно в интерпретатор.
Если все, что вы хотите удалить, принадлежит одному и тому же пользователю, то вы можете использовать:
drop owned by the_user;
Это отбросит все, что принадлежит пользователю.
Это включает в себя материализованные представления, представления, последовательности, триггеры, схемы, функции, типы, агрегаты, операторы, домены и т.д. (Так, действительно: все), которыми владеет the_user
(= созданный).
Вы должны заменить the_user
на фактическое имя пользователя, в настоящее время нет возможности отбросить все для "текущего пользователя". Следующая версия 9.5 будет иметь опцию drop owned by current_user
.
Более подробная информация в руководстве: http://www.postgresql.org/docs/current/static/sql-drop-owned.html
В соответствии с вышеизложенным Пабло, чтобы просто отказаться от конкретной схемы, в отношении случая:
select 'drop table "' || tablename || '" cascade;'
from pg_tables where schemaname = 'public';
drop schema public cascade;
должен сделать трюк.
Следуя Pablo и LenW, здесь один лайнер, который делает все это как подготовку, так и выполнение:
psql -U $PGUSER $PGDB -t -c "select 'drop table \"' || tablename || '\" cascade;' from pg_tables where schemaname = 'public'" | psql -U $PGUSER $PGDB
NB: установите или замените $PGUSER
и $PGDB
на нужные значения
Если у вас установлен процедурный язык PL/PGSQL вы можете использовать следующее, чтобы удалить все без оболочки/внешнего Perl script.
DROP FUNCTION IF EXISTS remove_all();
CREATE FUNCTION remove_all() RETURNS void AS $$
DECLARE
rec RECORD;
cmd text;
BEGIN
cmd := '';
FOR rec IN SELECT
'DROP SEQUENCE ' || quote_ident(n.nspname) || '.'
|| quote_ident(c.relname) || ' CASCADE;' AS name
FROM
pg_catalog.pg_class AS c
LEFT JOIN
pg_catalog.pg_namespace AS n
ON
n.oid = c.relnamespace
WHERE
relkind = 'S' AND
n.nspname NOT IN ('pg_catalog', 'pg_toast') AND
pg_catalog.pg_table_is_visible(c.oid)
LOOP
cmd := cmd || rec.name;
END LOOP;
FOR rec IN SELECT
'DROP TABLE ' || quote_ident(n.nspname) || '.'
|| quote_ident(c.relname) || ' CASCADE;' AS name
FROM
pg_catalog.pg_class AS c
LEFT JOIN
pg_catalog.pg_namespace AS n
ON
n.oid = c.relnamespace WHERE relkind = 'r' AND
n.nspname NOT IN ('pg_catalog', 'pg_toast') AND
pg_catalog.pg_table_is_visible(c.oid)
LOOP
cmd := cmd || rec.name;
END LOOP;
FOR rec IN SELECT
'DROP FUNCTION ' || quote_ident(ns.nspname) || '.'
|| quote_ident(proname) || '(' || oidvectortypes(proargtypes)
|| ');' AS name
FROM
pg_proc
INNER JOIN
pg_namespace ns
ON
(pg_proc.pronamespace = ns.oid)
WHERE
ns.nspname =
'public'
ORDER BY
proname
LOOP
cmd := cmd || rec.name;
END LOOP;
EXECUTE cmd;
RETURN;
END;
$$ LANGUAGE plpgsql;
SELECT remove_all();
Вместо того, чтобы вводить это в приглашении "psql", я предлагаю вам скопировать его в файл, а затем передать файл в качестве входа в psql, используя опции "-file" или "-f":
psql -f clean_all_pg.sql
Кредит, при котором должен быть кредит: я написал эту функцию, но думаю, что запросы (или, по крайней мере, первые) были получены от кого-то из одного из списков рассылки pgsql лет назад. Не помните точно, когда или какой.
Я немного изменил Pablo для удобства получения сгенерированных команд SQL в виде одной строки:
select string_agg('drop table "' || tablename || '" cascade', '; ')
from pg_tables where schemaname = 'public'
Используйте этот script в pgAdmin:
DO $$
DECLARE
brow record;
BEGIN
FOR brow IN (select 'drop table "' || tablename || '" cascade;' as table_name from pg_tables where schemaname = 'public') LOOP
EXECUTE brow.table_name;
END LOOP;
END; $$
Если вы все равно хотите обнулить все таблицы, вы можете обойтись без таких тонкостей, как CASCADE, поместив все таблицы в один оператор. Это также ускоряет выполнение.
SELECT 'TRUNCATE TABLE ' || string_agg('"' || tablename || '"', ', ') || ';'
FROM pg_tables WHERE schemaname = 'public';
Выполнение этого напрямую:
DO $$
DECLARE tablenames text;
BEGIN
tablenames := string_agg('"' || tablename || '"', ', ')
FROM pg_tables WHERE schemaname = 'public';
EXECUTE 'TRUNCATE TABLE ' || tablenames;
END; $$
Замените TRUNCATE
на DROP
, если применимо.
На всякий случай... Простой Python script, который очищает базу данных Postgresql
import psycopg2
import sys
# Drop all tables from a given database
try:
conn = psycopg2.connect("dbname='akcja_miasto' user='postgres' password='postgres'")
conn.set_isolation_level(0)
except:
print "Unable to connect to the database."
cur = conn.cursor()
try:
cur.execute("SELECT table_schema,table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_schema,table_name")
rows = cur.fetchall()
for row in rows:
print "dropping table: ", row[1]
cur.execute("drop table " + row[1] + " cascade")
cur.close()
conn.close()
except:
print "Error: ", sys.exc_info()[1]
Удостоверьтесь, что после копирования это отступ прав, поскольку Python полагается на него.
Вы можете использовать функцию string_agg, чтобы сделать список, разделенный запятыми, идеально подходящий для DROP TABLE. Из bash script:
#!/bin/bash
TABLES=`psql $PGDB -t --command "SELECT string_agg(table_name, ',') FROM information_schema.tables WHERE table_schema='public'"`
echo Dropping tables:${TABLES}
psql $PGDB --command "DROP TABLE IF EXISTS ${TABLES} CASCADE"
Если вы хотите удалить данные (не удалять таблицу):
-- Truncate tables and restart sequnces
SELECT 'TRUNCATE TABLE "' || table_schema || '"."' || table_name || '" RESTART IDENTITY CASCADE;'
FROM information_schema.tables
WHERE table_catalog = '<database>' AND table_schema = '<schema>';
Или, если вы хотите удалить таблицу, вы можете использовать этот sql:
-- For tables
SELECT 'DROP TABLE "' || table_schema || '"."' || table_name || '" CASCADE;'
FROM information_schema.tables
WHERE table_catalog = '<database>' AND table_schema = '<schema>';
-- For sequences
SELECT 'DROP SEQUENCE d_a_seq "' || sequence_schema || '"."' || sequence_name || '";'
FROM information_schema.sequences
WHERE sequence_catalog = '<database>' AND sequence_schema = '<schema>';
Вам нужно отбросить таблицы и последовательности, вот что сработало для меня
psql -qAtX -c "select 'DROP TABLE IF EXISTS ' || quote_ident(table_schema) || '.' || quote_ident(table_name) || ' CASCADE;' FROM information_schema.tables where table_type = 'BASE TABLE' and not table_schema ~ '^(information_schema|pg_.*)$'" | psql -qAtX
psql -qAtX -c "select 'DROP SEQUENCE IF EXISTS ' || quote_ident(relname) || ' CASCADE;' from pg_statio_user_sequences;" | psql -qAtX
перед запуском команды, которая может понадобиться пользователю sudo/su пользователю postgres
или (экспортировать сведения о подключении PGHOST
, PGPORT
, PGUSER
и PGPASSWORD
), а затем export PGDATABASE=yourdatabase
в пакетном файле Windows:
@echo off
FOR /f "tokens=2 delims=|" %%G IN ('psql --host localhost --username postgres --command="\dt" YOUR_TABLE_NAME') DO (
psql --host localhost --username postgres --command="DROP table if exists %%G cascade" sfkb
echo table %%G dropped
)
Задача Rake для Rails для уничтожения всех таблиц в текущей базе данных
namespace :db do
# rake db:drop_all_tables
task drop_all_tables: :environment do
query = <<-QUERY
SELECT
table_name
FROM
information_schema.tables
WHERE
table_type = 'BASE TABLE'
AND
table_schema NOT IN ('pg_catalog', 'information_schema');
QUERY
connection = ActiveRecord::Base.connection
results = connection.execute query
tables = results.map do |line|
table_name = line['table_name']
end.join ", "
connection.execute "DROP TABLE IF EXISTS #{ tables } CASCADE;"
end
end
Я улучшил метод bash от jamie, заботясь о просмотрах, потому что он только уважает таблицу типа "базовая таблица", которая по умолчанию.
после bash кода сначала удаляются представления, а затем все остальные
#!/usr/bin/env bash
PGDB="yourDB"
# By exporting user & pass your dont need to interactively type them on execution
export PGUSER="PGusername"
export PGPASSWORD="PGpassword"
VIEWS=`psql -d $PGDB -t --command "SELECT string_agg(table_name, ',') FROM information_schema.tables WHERE table_schema='public' AND table_type='VIEW'"`
BASETBLS=`psql -d $PGDB -t --command "SELECT string_agg(table_name, ',') FROM information_schema.tables WHERE table_schema='public' AND table_type='BASE TABLE'"`
echo Dropping views:${VIEWS}
psql $PGDB --command "DROP VIEW IF EXISTS ${VIEWS} CASCADE"
echo Dropping tables:${BASETBLS}
psql $PGDB --command "DROP TABLE IF EXISTS ${BASETBLS} CASCADE"
Примечание: мой ответ о действительно удалении таблиц и других объектов базы данных; для удаления всех данных в таблицах, т.е. усечения всех таблиц, Endre Both предоставил аналогично хорошо выполненный оператор (непосредственное выполнение) через месяц.
Для случаев, когда вы не можете просто DROP SCHEMA public CASCADE;
, DROP OWNED BY current_user;
или что-то еще, вот отдельный скрипт SQL, который я написал, который безопасен для транзакций (то есть вы можете поместить его между BEGIN;
и ROLLBACK;
, чтобы просто проверить это или COMMIT;
, чтобы фактически сделать дело) и очищает "все" объекты базы данных… хорошо, все те, которые используются в базе данных, используемой нашим приложением, или я мог бы разумно добавить, что:
CHECK
, UNIQUE
)VIEW
(обычный или материализованный)pg_proc.proisagg
вероятно, следует соблюдать, хотя)public
или DB-internal) "у нас": скрипт полезен, когда запускается как "не суперпользователь базы данных"; суперпользователь может отбросить все схемы (хотя действительно важные из них явно исключены)Не отброшены (некоторые умышленно; некоторые только потому, что у меня нет примера в нашей БД):
public
(например, для предоставляемых расширений в них)Это действительно полезно для случаев, когда дамп, который вы хотите восстановить, имеет другую версию схемы базы данных (например, с Debian dbconfig-common
, Flyway или Liquibase/DB-Manul), чем база данных, которую вы хотите восстановить это в.
У меня также есть версия, которая удаляет "все, кроме двух таблиц и того, что им принадлежит", если кому-то это интересно; разница маленькая. Свяжитесь со мной, если это необходимо.
-- Copyright © 2019
-- mirabilos <[email protected]>
--
-- Provided that these terms and disclaimer and all copyright notices
-- are retained or reproduced in an accompanying document, permission
-- is granted to deal in this work without restriction, including un‐
-- limited rights to use, publicly perform, distribute, sell, modify,
-- merge, give away, or sublicence.
--
-- This work is provided 'AS IS' and WITHOUT WARRANTY of any kind, to
-- the utmost extent permitted by applicable law, neither express nor
-- implied; without malicious intent or gross negligence. In no event
-- may a licensor, author or contributor be held liable for indirect,
-- direct, other damage, loss, or other issues arising in any way out
-- of dealing in the work, even if advised of the possibility of such
-- damage or existence of a defect, except proven that it results out
-- of said persons immediate fault when using the work as intended.
-- -
-- Drop everything from the PostgreSQL database.
DO $$
DECLARE
r RECORD;
BEGIN
-- triggers
FOR r IN (SELECT pns.nspname, pc.relname, pt.tgname
FROM pg_trigger pt, pg_class pc, pg_namespace pns
WHERE pns.oid=pc.relnamespace AND pc.oid=pt.tgrelid
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pt.tgisinternal=false
) LOOP
EXECUTE format('DROP TRIGGER %I ON %I.%I;',
r.tgname, r.nspname, r.relname);
END LOOP;
-- constraints #1: foreign key
FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
FROM pg_constraint pcon, pg_class pc, pg_namespace pns
WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pcon.contype='f'
) LOOP
EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
r.nspname, r.relname, r.conname);
END LOOP;
-- constraints #2: the rest
FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
FROM pg_constraint pcon, pg_class pc, pg_namespace pns
WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pcon.contype<>'f'
) LOOP
EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
r.nspname, r.relname, r.conname);
END LOOP;
-- indicēs
FOR r IN (SELECT pns.nspname, pc.relname
FROM pg_class pc, pg_namespace pns
WHERE pns.oid=pc.relnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pc.relkind='i'
) LOOP
EXECUTE format('DROP INDEX %I.%I;',
r.nspname, r.relname);
END LOOP;
-- normal and materialised views
FOR r IN (SELECT pns.nspname, pc.relname
FROM pg_class pc, pg_namespace pns
WHERE pns.oid=pc.relnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pc.relkind IN ('v', 'm')
) LOOP
EXECUTE format('DROP VIEW %I.%I;',
r.nspname, r.relname);
END LOOP;
-- tables
FOR r IN (SELECT pns.nspname, pc.relname
FROM pg_class pc, pg_namespace pns
WHERE pns.oid=pc.relnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pc.relkind='r'
) LOOP
EXECUTE format('DROP TABLE %I.%I;',
r.nspname, r.relname);
END LOOP;
-- sequences
FOR r IN (SELECT pns.nspname, pc.relname
FROM pg_class pc, pg_namespace pns
WHERE pns.oid=pc.relnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
AND pc.relkind='S'
) LOOP
EXECUTE format('DROP SEQUENCE %I.%I;',
r.nspname, r.relname);
END LOOP;
-- extensions (see below), only if necessary
FOR r IN (SELECT pns.nspname, pe.extname
FROM pg_extension pe, pg_namespace pns
WHERE pns.oid=pe.extnamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
) LOOP
EXECUTE format('DROP EXTENSION %I;', r.extname);
END LOOP;
-- functions / procedures
FOR r IN (SELECT pns.nspname, pp.proname, pp.oid
FROM pg_proc pp, pg_namespace pns
WHERE pns.oid=pp.pronamespace
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
) LOOP
EXECUTE format('DROP FUNCTION %I.%I(%s);',
r.nspname, r.proname,
pg_get_function_identity_arguments(r.oid));
END LOOP;
-- nōn-default schemata we own; assume to be run by a not-superuser
FOR r IN (SELECT pns.nspname
FROM pg_namespace pns, pg_roles pr
WHERE pr.oid=pns.nspowner
AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast', 'public')
AND pr.rolname=current_user
) LOOP
EXECUTE format('DROP SCHEMA %I;', r.nspname);
END LOOP;
-- voilà
RAISE NOTICE 'Database cleared!';
END; $$;
Протестировано, за исключением более поздних дополнений (extensions
, предоставленных Clément Prévost), в PostgreSQL 9.6 (jessie-backports
). Исправления и дальнейшие улучшения приветствуются!
ну, так как мне нравится работать из командной строки...
psql -U <user> -d <mydb> -c '\dt' | cut -d ' ' -f 4 | sed -e "s/^/drop table if exists/" | sed -e "s/$/;/"
-c '\dt'
вызовет команду списка таблиц.
List of relations Schema | Name | Type | Owner --------+-------------------+-------+---------- public | _d_psidxddlparm | table | djuser public | _d_psindexdefn | table | djuser
cut -d ' ' -f 4
сейчас, cut -d ' ' -f 4
вывод, чтобы захватить 4-е поле (при использовании пробела в качестве разделителя), которое является таблицей.
Затем sed
используется в качестве префикса для drop table
и суффикса к ;
разделитель команд.
| egrep '_d_'
| egrep '_d_'
- | egrep '_d_'
в grep
и вы сможете более | egrep '_d_'
какие таблицы вы отбрасываете.
drop table if exists _d_psidxddlparm; drop table if exists _d_psindexdefn;
Примечание: как написано, это сгенерирует фиктивные строки для вывода команд \dt
заголовков столбцов и итоговых строк в конце. Я избегаю этого путаницей, но вы можете использовать head
и tail
.
Самый простой способ - удалить общедоступную схему, как предлагали другие в предыдущих ответах. Однако это НЕ хороший способ. Вы никогда не знаете, что было сделано с публичной схемой, которая с тех пор была забыта и не была задокументирована. Вы также не знаете, будет ли это работать в будущем. В V9 это было бы нормально, но в V10 все ваши пользователи потеряли бы доступ к схеме, и им нужно было бы снова предоставить доступ, в противном случае ваше приложение сломается. Я не проверял V11, но дело в том, что вы никогда не знаете, что сломается при переходе с компьютера на компьютер, с сайта на сайт или с версии на версию. Этого также нельзя сделать, если вы являетесь пользователем, который имеет доступ к базе данных, но не к схеме.
Если вам нужно сделать это программно, то другие ответы выше покрывают это, но одна вещь, которую ответы выше не учитывают, - это заставить Postgres выполнить эту работу за вас. Если вы используете pg_dump с опцией -c, как показано ниже:
sudo su postgres -c "pg_dump -U postgres WhateverDB -c -f "/home/Anyone/DBBackupWhateverDB-ServerUnscheduled.sql""
Это создаст скрипт восстановления БД с инструкциями sql, который удалит все таблицы.
Если единственная цель при задании вопроса состояла в том, чтобы удалить таблицы перед восстановлением, то ваше восстановление сделает всю работу за вас.
Однако, если вам это нужно для чего-то другого, вы можете просто скопировать операторы drop из сценария sql.
Не знаю, почему люди усложняют себя, в CMD, это будет так же просто, как:
psql.exe -d [dbname] --username "postgres" -c "DROP SCHEMA IF EXISTS [schema_name] CASCADE;"
И попробуйте не использовать public в качестве вашей рабочей схемы.