Изменить OWNER для всех таблиц одновременно в PostgreSQL

412

Как изменить владельца всех таблиц в базе данных PostgreSQL?

Я пытался, ALTER TABLE * OWNER TO new_ownerно он не поддерживает синтаксис звездочки.

Кай
источник

Ответы:

461

Смотрите REASSIGN OWNEDкоманду

Примечание. Как упоминает @trygvis в ответе ниже , эта REASSIGN OWNEDкоманда доступна по крайней мере начиная с версии 8.2 и является гораздо более простым методом.


Поскольку вы меняете владельца для всех таблиц, вам, вероятно, также нужны представления и последовательности. Вот что я сделал:

Таблицы:

for tbl in `psql -qAt -c "select tablename from pg_tables where schemaname = 'public';" YOUR_DB` ; do  psql -c "alter table \"$tbl\" owner to NEW_OWNER" YOUR_DB ; done

Последовательности:

for tbl in `psql -qAt -c "select sequence_name from information_schema.sequences where sequence_schema = 'public';" YOUR_DB` ; do  psql -c "alter sequence \"$tbl\" owner to NEW_OWNER" YOUR_DB ; done

Взгляды:

for tbl in `psql -qAt -c "select table_name from information_schema.views where table_schema = 'public';" YOUR_DB` ; do  psql -c "alter view \"$tbl\" owner to NEW_OWNER" YOUR_DB ; done

Вы, вероятно , можете немного высушить это, поскольку операторы alter идентичны для всех трех.


Алекс Сото
источник
10
+1 Спасибо, Алекс. На основании вашего ответа я создал небольшой скрипт bash, доступный по адресу gist.github.com/2482969
gingerlime
10
Смотрите недавний ответ @trygvis. Самый простой ответ на сегодняшний день:REASSIGN OWNED BY old_role [, ...] TO new_role
Дэвид
64
REASSIGN OWNED BY не работает для объектов, принадлежащих postgres.
BrunoJCM
19
Кроме того, REASSIGN OWNED фактически влияет на владение всеми базами данных, принадлежащими старой роли (см .: postgresql.org/docs/9.3/static/sql-reassign-owned.html ). Так что, если вы хотите изменить владельца одной базы данных, будьте осторожны!
Кицунэ
3
На основе скрипта @gingerlime bspkrs (не смог найти его имя) создал скрипт, который также меняет функции: https://gist.github.com/bspkrs/b997ed7f1eb1268f3403
elysch
538

Вы можете использовать REASSIGN OWNEDкоманду.

Сводка:

REASSIGN OWNED BY old_role [, ...] TO new_role

Это изменяет все объекты, принадлежащие old_roleновой роли. Вам не нужно думать о том, какие объекты у пользователя, они все будут изменены. Обратите внимание, что это относится только к объектам внутри одной базы данных. Это не меняет владельца самой базы данных.

Доступно как минимум до 8.2. Их онлайн-документация только заходит так далеко.

Trygve Laugstøl
источник
ERROR: unexpected classid 3079, Я думаю, что в настоящее время не работает, если есть какие-либо расширения.
Стив Йоргенсен
40
Похоже, что это не работает для пользователей postgres, хотя я подключен к созданной мной базе данных (то есть не к системной базе данных), он говорит следующее: ОШИБКА: не может переназначить владение объектами, принадлежащими роли postgres, поскольку они требуются для базы данных. система
thnee
13
Как сообщил @thnee, REASSIGN влияет на все объекты в базе данных и не делает различий между пользовательскими и системными объектами, поэтому он не работает для postgres, если есть какое-либо расширение, имеющее собственные таблицы. Тем не менее, я предпочитаю (+1) эту опцию для элегантности, хотя она мне не сильно помогла (моя база данных ранее принадлежала postgres).
Павел В.
6
Просто чтобы быть понятным, эта команда работает в базе данных, которую вы в настоящее время подключены ТОЛЬКО. Если old_role владеет объектами в нескольких базах данных, вы должны подключиться и выполнить эту команду в каждой из этих баз данных
mavroprovato
11
похоже, это не работает на postgres, размещенном через AWS RDS. Я получаю эту ошибку «Отказано в разрешении на переназначение объектов», и по этой ссылке объясняется, почему: «Похоже, что единственный способ« переназначить принадлежащий »- это использование прав суперпользователя (что противоречит документации), которое недоступно в RDS. ' postgresql-archive.org/…
typoerrpr
198

Это: http://archives.postgresql.org/pgsql-bugs/2007-10/msg00234.php также является хорошим и быстрым решением и работает для нескольких схем в одной базе данных:

таблицы

SELECT 'ALTER TABLE '|| schemaname || '.' || tablename ||' OWNER TO my_new_owner;'
FROM pg_tables WHERE NOT schemaname IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename;

Последовательности

SELECT 'ALTER SEQUENCE '|| sequence_schema || '.' || sequence_name ||' OWNER TO my_new_owner;'
FROM information_schema.sequences WHERE NOT sequence_schema IN ('pg_catalog', 'information_schema')
ORDER BY sequence_schema, sequence_name;

Взгляды

SELECT 'ALTER VIEW '|| table_schema || '.' || table_name ||' OWNER TO my_new_owner;'
FROM information_schema.views WHERE NOT table_schema IN ('pg_catalog', 'information_schema')
ORDER BY table_schema, table_name;

Материализованные представления

На основании этого ответа

SELECT 'ALTER TABLE '|| oid::regclass::text ||' OWNER TO my_new_owner;'
FROM pg_class WHERE relkind = 'm'
ORDER BY oid;

Это генерирует все необходимые операторы ALTER TABLE/ ALTER SEQUENCE/ ALTER VIEW, копирует их и вставляет их обратно в plsql для их запуска.

Проверьте свою работу в psql, выполнив:

\dt *.*
\ds *.*
\dv *.*
Rkj
источник
Отличное решение. Моя единственная проблема заключалась в том, что я должен был экспортировать сценарии, а затем выполнить экспортированные сценарии. Я гуру SQL Server, но я не уверен, что ярлык для выполнения. Я нажал выполнить запрос и выполнить pgScript. Что я делал не так?
Тайрон Мудли
1
Я предпочел это, так как он работает изнутри plsql после входа в систему - для сценариев уровня unix (в настоящее время любимый ответ) требуется "-U postgres" и ввод пароля в моей среде.
Ошеломленный
2
Я предпочитаю этот ответ, потому что (1) это может быть сделано в psql или pgAdmin (2), это легко позволяет вам видеть объекты, которые вы будете изменять. Я также использовал stackoverflow.com/questions/22803096/… , что аналогично, но для функций.
AlannaRose
великолепная логика.
Emipro Technologies Pvt. ООО
42

Если вы хотите сделать это одним оператором sql, вам нужно определить функцию exec (), как указано в http://wiki.postgresql.org/wiki/Dynamic_DDL

CREATE FUNCTION exec(text) returns text language plpgsql volatile
  AS $f$
    BEGIN
      EXECUTE $1;
      RETURN $1;
    END;
$f$;

Затем вы можете выполнить этот запрос, он изменит владельца таблиц, последовательностей и представлений:

SELECT exec('ALTER TABLE ' || quote_ident(s.nspname) || '.' ||
            quote_ident(s.relname) || ' OWNER TO $NEWUSER')
  FROM (SELECT nspname, relname
          FROM pg_class c JOIN pg_namespace n ON (c.relnamespace = n.oid) 
         WHERE nspname NOT LIKE E'pg\\_%' AND 
               nspname <> 'information_schema' AND 
               relkind IN ('r','S','v') ORDER BY relkind = 'S') s;

$ NEWUSER - это новое имя postgresql для нового владельца.

В большинстве случаев вам нужно быть суперпользователем, чтобы выполнить это. Вы можете избежать этого, изменив владельца с вашего собственного пользователя на группу ролей, членом которой вы являетесь.

Спасибо RhodiumToad на #postgresql за помощь в этом.

Йохан Далин
источник
2
Это гораздо полезнее, поскольку оно меняет владельца всей схемы, включая функции, индексы, последовательности и т. Д. Спасибо!
liviucmg
Это не меняет владельцев схемы. Как изменить владельцев схемы?
Андрус
@Andrus Владелец базы данных $ DB Владелец $ OWNER;
Йохан Далин
Изменение базы данных меняет владельца базы данных. Я спросил, как изменить владельцев схемы.
Андрус
ALTER SCHEMA Фред ВЛАДЕЛЕЦ Бетти;
Эрик Алдингер,
21

Мне недавно пришлось сменить владельца всех объектов в базе данных. Хотя таблицы, представления, триггеры и последовательности были несколько легко изменены, вышеупомянутый подход не удался для функций, так как подпись является частью имени функции. Конечно, у меня есть опыт работы с MySQL, и я не очень знаком с Postgres.

Тем не менее, pg_dump позволяет вывести только схему, и она содержит ALTER xxx OWNER TO yyy; заявления вам нужны. Вот мой кусочек магии на тему

pg_dump -s YOUR_DB | grep -i 'owner to' | sed -e 's/OWNER TO .*;/OWNER TO NEW_OWNER;/i' | psqL YOUR_DB
magiconair
источник
Я не уверен, почему вы используете grepкоманду. Я сам новичок в Linux, но, насколько я понимаю, кажется, что sedэто нормально, особенно если вы в любом случае указываете регистр без учета регистра.
Боборт
19

очень просто, попробуйте ...

 select 'ALTER TABLE ' || table_name || ' OWNER TO myuser;' from information_schema.tables where table_schema = 'public';
mwendamseke
источник
4
Вы можете добавить примечание, что соответствующие строки должны быть скопированы и выполнены. Не то чтобы это не очевидно: p
Nightscape
Который включает в себя удаление всех кавычек вокруг операторов alter .. мульти-курсоры или замена помогают в этом случае.
известноасиля
19

очень просто

  1. су - постгрес
  2. PSQL
  3. ПЕРЕПИСКА, СОБСТВЕННАЯ [old_user] TO [new_user];
  4. \ c [ваша база данных]
  5. ПЕРЕПИСКА, СОБСТВЕННАЯ [old_user] TO [new_user];

сделанный.

durenzo
источник
1
Это, вероятно, делает то, что хотел кверент. Безусловно самый простой.
Geof Sawaya
1
Вы только на 4 года опоздали на вечеринку; прокрутите вверх: stackoverflow.com/a/13535184/1772379
Бен Джонсон
16

Мне нравится этот, так как он изменяет таблицы , представления , последовательности и функции- владельца определенной схемы за один раз (в одном выражении sql), не создавая функцию, и вы можете использовать ее непосредственно в PgAdmin III и psql :

(Проверено в PostgreSql v9.2)

DO $$DECLARE r record;
DECLARE
    v_schema varchar := 'public';
    v_new_owner varchar := '<NEW_OWNER>';
BEGIN
    FOR r IN 
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.tables where table_schema = v_schema
        union all
        select 'ALTER TABLE "' || sequence_schema || '"."' || sequence_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.sequences where sequence_schema = v_schema
        union all
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.views where table_schema = v_schema
        union all
        select 'ALTER FUNCTION "'||nsp.nspname||'"."'||p.proname||'"('||pg_get_function_identity_arguments(p.oid)||') OWNER TO ' || v_new_owner || ';' as a from pg_proc p join pg_namespace nsp ON p.pronamespace = nsp.oid where nsp.nspname = v_schema
    LOOP
        EXECUTE r.a;
    END LOOP;
END$$;

На основании ответов, предоставленных @rkj, @AlannaRose, @SharoonThomas, @ user3560574 и этого ответа @a_horse_with_no_name

Большое спасибо.


Еще лучше: также измените владельца базы данных и схемы .

DO $$DECLARE r record;
DECLARE
    v_schema varchar := 'public';
    v_new_owner varchar := 'admin_ctes';
BEGIN
    FOR r IN 
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.tables where table_schema = v_schema
        union all
        select 'ALTER TABLE "' || sequence_schema || '"."' || sequence_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.sequences where sequence_schema = v_schema
        union all
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.views where table_schema = v_schema
        union all
        select 'ALTER FUNCTION "'||nsp.nspname||'"."'||p.proname||'"('||pg_get_function_identity_arguments(p.oid)||') OWNER TO ' || v_new_owner || ';' as a from pg_proc p join pg_namespace nsp ON p.pronamespace = nsp.oid where nsp.nspname = v_schema
        union all
        select 'ALTER SCHEMA "' || v_schema || '" OWNER TO ' || v_new_owner 
        union all
        select 'ALTER DATABASE "' || current_database() || '" OWNER TO ' || v_new_owner 
    LOOP
        EXECUTE r.a;
    END LOOP;
END$$;
elysch
источник
УДИВИТЕЛЬНО! Почему Postgres не добавляет это, я не знаю!
пип
Два вопроса: 1) Похоже, что первая и третья строки «ALTER TABLE» являются обманщиками. Это намеренно (например, вам нужно сделать два прохода по столам, чтобы сменить владельца?). 2) Мы находим, что information_schema.sequencesпусто, хотя SELECT c.* FROM pg_class c WHERE c.relkind = 'S';перечисляет последовательности. Почему они могут не совпадать?
GuyPaddock
Кроме того, не должен ли второй ALTERзапрос быть ALTER SEQUENCE?
GuyPaddock
12

Мне пришлось изменить владельца таблиц, представлений и последовательностей, и я обнаружил, что отличное решение, опубликованное @rjk, работает нормально, несмотря на одну деталь: если имена объектов имеют смешанный регистр (например, «TableName»), это не удастся с « не найдена "- ошибка.
Чтобы обойти это, оберните имена объектов символом "" "следующим образом:

таблицы

SELECT 'ALTER TABLE \"'|| schemaname || '.' || tablename ||'\" OWNER TO my_new_owner;'
FROM pg_tables WHERE NOT schemaname IN ('pg_catalog', 'information_schema')
ORDER BY schemaname, tablename;

Последовательности

SELECT 'ALTER SEQUENCE \"'|| sequence_schema || '.' || sequence_name ||'\" OWNER TO my_new_owner;'
FROM information_schema.sequences WHERE NOT sequence_schema IN ('pg_catalog', 'information_schema')
ORDER BY sequence_schema, sequence_name;

Взгляды

SELECT 'ALTER VIEW \"'|| table_schema || '.' || table_name ||'\" OWNER TO my_new_owner;'
FROM information_schema.views WHERE NOT table_schema IN ('pg_catalog', 'information_schema')
ORDER BY table_schema, table_name;
судья
источник
10

Вы можете попробовать следующее в PostgreSQL 9

DO $$DECLARE r record;
BEGIN
    FOR r IN SELECT tablename FROM pg_tables WHERE schemaname = 'public'
    LOOP
        EXECUTE 'alter table '|| r.tablename ||' owner to newowner;';
    END LOOP;
END$$;
user3560574
источник
6

В PostgreSQL такой команды нет. Но вы можете обойти это, используя метод, который я описал некоторое время назад для GRANT.


источник
Спасибо, очень хорошая статья. Я сохраню это в будущем. Используя pgAdmin, я закончил резервное копирование БД, удалив / удалив БД, временно предоставив new_owner необходимые права, а затем заново создав и восстановив БД как new_owner, с опцией «no owner», отмеченной в окне восстановления. Это дало результаты, которые я искал с new_owner как владельцем всего.
Кай
Postgres 9.3 ввел команду REASSIGN OWNED. postgresql.org/docs/9.3/sql-reassign-owned.html
Георг Циммер,
3

Основываясь на ответе elysch , вот решение для нескольких схем:

DO $$
DECLARE 
  r record;
  i int;
  v_schema text[] := '{public,schema1,schema2,schema3}';
  v_new_owner varchar := 'my_new_owner';
BEGIN
    FOR r IN 
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.tables where table_schema = ANY (v_schema)
        union all
        select 'ALTER TABLE "' || sequence_schema || '"."' || sequence_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.sequences where sequence_schema = ANY (v_schema)
        union all
        select 'ALTER TABLE "' || table_schema || '"."' || table_name || '" OWNER TO ' || v_new_owner || ';' as a from information_schema.views where table_schema = ANY (v_schema)
        union all
        select 'ALTER FUNCTION "'||nsp.nspname||'"."'||p.proname||'"('||pg_get_function_identity_arguments(p.oid)||') OWNER TO ' || v_new_owner || ';' as a from pg_proc p join pg_namespace nsp ON p.pronamespace = nsp.oid where nsp.nspname = ANY (v_schema)
        union all
        select 'ALTER DATABASE "' || current_database() || '" OWNER TO ' || v_new_owner 
    LOOP
        EXECUTE r.a;
    END LOOP;
    FOR i IN array_lower(v_schema,1) .. array_upper(v_schema,1)
    LOOP
        EXECUTE 'ALTER SCHEMA "' || v_schema[i] || '" OWNER TO ' || v_new_owner ;
    END LOOP;
END
$$;
JC Boggio
источник
2

Ответ @Alex Soto является правильным, и суть, загруженная @Yoav Aner, также работает при условии, что в именах таблиц / представлений нет специальных символов (которые допустимы в postgres).

Вам нужно избежать их на работу, и я загрузил суть для этого: https://gist.github.com/2911117

Шарун Томас
источник
2
pg_dump as insert statements 
pg_dump -d -O database filename
-d ( data as inserts ) -O ( capital O is no owner )

Затем передайте файл резервной копии обратно в PostgreSQL, используя:

psql -d database -U username -h hostname < filename

Поскольку владелец не включен, все созданные таблица, схема и т. Д. Создаются под указанным пользователем для входа.

Я читал, что это может быть хорошим подходом для миграции между версиями PostgreSQL.

atwsKris
источник
2

Я создал удобный сценарий для этого; pg_change_db_owner.sh . Этот сценарий меняет владельца для всех таблиц, представлений, последовательностей и функций в схеме базы данных, а также для владельца самой схемы.

Обратите внимание, что если вы хотите просто изменить владельца всех объектов в конкретной базе данных, принадлежащих определенной роли базы данных, тогда вы можете просто использовать команду REASSIGN OWNEDвместо этого.

Якуб Джирутка
источник
1

Начиная с PostgreSQL 9.0, у вас есть способность , GRANT [priv name] ON ALL [object type] IN SCHEMAгде [priv name]является типичным SELECT, INSERT, UPDATE, DELETE, etcи [object type]может быть одним из:

  • TABLES
  • SEQUENCES
  • FUNCTIONS

Документы PostgreSQL GRANTи REVOKEболее подробно об этом. В некоторых ситуациях все еще требуется использовать трюки с системными каталогами ( pg_catalog.pg_*), но это не так часто. Я часто делаю следующее:

  1. BEGIN транзакция для изменения привилегий
  2. Смена владельца DATABASESна "роль DBA"
  3. Смена владельца SCHEMASна "роль DBA"
  4. REVOKE ALLprivs на всех TABLES, SEQUENCESи FUNCTIONSот всех ролей
  5. GRANT SELECT, INSERT, UPDATE, DELETE на соответствующие / соответствующие таблицы для соответствующих ролей
  6. COMMIT транзакция DCL.
Шон
источник
1

Принятое решение не заботится о владении функциями. Следующее решение заботится обо всем (при рассмотрении я заметил, что оно похоже на @magiconair выше)

echo "Database: ${DB_NAME}"
echo "Schema: ${SCHEMA}"
echo "User: ${NEW_OWNER}"

pg_dump -s -c -U postgres ${DB_NAME} | egrep "${SCHEMA}\..*OWNER TO"| sed -e "s/OWNER TO.*;$/OWNER TO ${NEW_OWNER};/" | psql -U postgres -d ${DB_NAME}
# do following as last step to allow recovery
psql -U postgres -d postgres -c "ALTER DATABASE ${DB_NAME} OWNER TO ${NEW_OWNER};"
JSH
источник
1

Следующий более простой сценарий оболочки работал для меня.

#!/bin/bash
for i in  `psql -U $1  -qt -c  "select tablename from pg_tables where schemaname='$2'"`
do
psql -U $1 -c  "alter table $2.$i set schema $3"
done

Где ввод $ 1 - имя пользователя (база данных) $ 2 = существующая схема $ 3 = в новую схему.

sramay
источник
1

То же, что и подход @ AlexSoto для функций:

IFS=$'\n'  
for fnc in `psql -qAt -c "SELECT  '\"' || p.proname||'\"' || '(' || pg_catalog.pg_get_function_identity_arguments(p.oid) || ')' FROM pg_catalog.pg_namespace n JOIN pg_catalog.pg_proc p ON p.pronamespace = n.oid WHERE n.nspname = 'public';" YOUR_DB` ; do  psql -c "alter function $fnc owner to NEW_OWNER" YOUR_DB; done
Антон Смольков
источник
0

Докер: Изменить владельца всех таблиц + последовательности

export user="your_new_owner"
export dbname="your_db_name"

cat <<EOF | docker run -i --rm --link postgres:postgres postgres sh -c "psql -h \$POSTGRES_PORT_5432_TCP_ADDR -p \$POSTGRES_PORT_5432_TCP_PORT -U postgres -d $dbname" | grep ALTER | docker run -i --rm --link postgres:postgres postgres sh -c "psql -h \$POSTGRES_PORT_5432_TCP_ADDR -p \$POSTGRES_PORT_5432_TCP_PORT -U postgres -d $dbname"
SELECT 'ALTER TABLE '||schemaname||'.'||tablename||' OWNER TO $user;' FROM pg_tables WHERE schemaname = 'public';
SELECT 'ALTER SEQUENCE '||relname||' OWNER TO $user;' FROM pg_class WHERE relkind = 'S';
EOF
Войтех Витек
источник