Modifique PROPIETARIO en todas las tablas simultáneamente en PostgreSQL


412

¿Cómo modifico el propietario de todas las tablas en una base de datos PostgreSQL?

Lo intenté ALTER TABLE * OWNER TO new_ownerpero no admite la sintaxis de asterisco.

Respuestas:


461

Ver REASSIGN OWNEDcomando

Nota: Como @trygvis menciona en la respuesta a continuación , el REASSIGN OWNEDcomando está disponible desde al menos la versión 8.2, y es un método mucho más fácil.


Como está cambiando la propiedad de todas las tablas, es probable que también desee vistas y secuencias. Esto es lo que hice:

Mesas:

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

Secuencias:

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

Puntos de vista:

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

Probablemente podría SECAR eso un poco ya que las declaraciones alter son idénticas para los tres.



10
+1 Gracias Alex. He creado un pequeño script bash basado en su respuesta, disponible en gist.github.com/2482969
gingerlime

10
Ver la respuesta reciente de @trygvis. Respuesta más sencilla, con mucho:REASSIGN OWNED BY old_role [, ...] TO new_role
David

64
REASSIGN OWNED BY no funciona para objetos propiedad de postgres.
BrunoJCM 01 de

19
Además, REASSIGN OWNED en realidad afecta la propiedad de todas las bases de datos propiedad de la función anterior (ver: postgresql.org/docs/9.3/static/sql-reassign-owned.html ). Entonces, si solo desea cambiar la propiedad de una sola base de datos, ¡tenga cuidado!
kitsune

3
Basado en el script @gingerlime, bspkrs (no pudo encontrar su nombre) creó uno que también cambia las funciones: https://gist.github.com/bspkrs/b997ed7f1eb1268f3403
elysch

538

Puedes usar el REASSIGN OWNEDcomando.

Sinopsis:

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

Esto cambia todos los objetos que pertenecen old_roleal nuevo rol. No tiene que pensar qué tipo de objetos tiene el usuario, todos se cambiarán. Tenga en cuenta que solo se aplica a objetos dentro de una única base de datos. Tampoco altera al propietario de la base de datos.

Está disponible de nuevo al menos a 8.2. Su documentación en línea solo va tan atrás.


ERROR: unexpected classid 3079. Supongo que actualmente no funciona si hay extensiones.
Steve Jorgensen

40
Esto no parece funcionar para los usuarios de postgres, aunque estoy conectado a una base de datos que he creado (es decir, no a una base de datos del sistema), dice esto: ERROR: no puede reasignar la propiedad de los objetos que son propiedad de postgres de roles porque son requeridos por la base de datos system
thnee

13
Como informó @thnee, REASSIGN afecta a todos los objetos en la base de datos y no discrimina entre objetos definidos por el usuario y del sistema, por lo que no funciona para postgres si hay alguna extensión que tenga sus propias tablas. Aún así, prefiero (+1) esta opción por elegancia, aunque no me ayudó mucho (mi base de datos era propiedad de postgres).
Pavel V.

66
Para que quede claro, este comando funciona SOLO en la base de datos a la que está conectado actualmente. Si old_role posee objetos en varias bases de datos, debe conectarse y ejecutar este comando en cada una de esas bases de datos
mavroprovato

11
Esto no parece funcionar en postgres alojados a través de AWS RDS. Recibo este error "permiso denegado para reasignar objetos" y este enlace sugiere por qué: "Parece que la única forma de 'reasignar propiedad' es como un superusuario (que está contradicho por la documentación), que no es accesible en RDS. postgresql-archive.org/…
typoerrpr

198

Esto: http://archives.postgresql.org/pgsql-bugs/2007-10/msg00234.php también es una solución agradable y rápida, y funciona para múltiples esquemas en una base de datos:

Mesas

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;

Secuencias

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;

Puntos de vista

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;

Vistas materializadas

Basado en esta respuesta

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

Esto genera todas las declaraciones / ALTER TABLE/ requeridas , cópielas y péguelas nuevamente en plsql para ejecutarlas.ALTER SEQUENCEALTER VIEW

Verifique su trabajo en psql haciendo:

\dt *.*
\ds *.*
\dv *.*

Gran solución Mi único problema fue que exporté los scripts y luego ejecuté los scripts exportados. Soy SQL Server Guru pero no estoy seguro de cuál es el acceso directo para ejecutar. Hice clic en ejecutar consulta y ejecutar pgScript. ¿Qué estaba haciendo mal?
Tyrone Moodley

1
Preferí esto, ya que funciona desde plsql una vez que inicié sesión: los scripts de nivel Unix (respuesta favorita actualmente) requieren una entrada de "-U postgres" y contraseña en mi entorno.
Aturdido el

2
Prefiero esta respuesta porque (1) se puede hacer en psql o pgAdmin (2) le permite ver fácilmente los objetos que alterará. También utilicé stackoverflow.com/questions/22803096/… , que es similar, pero para funciones.
AlannaRose

espléndida lógica
Emipro Technologies Pvt. Ltd.

42

Si desea hacerlo en una instrucción sql, debe definir una función exec () como se menciona en 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$;

Luego puede ejecutar esta consulta, cambiará el propietario de las tablas, secuencias y vistas:

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 es el nuevo nombre postgresql del nuevo propietario.

En la mayoría de los casos, debe ser un superusuario para ejecutar esto. Puede evitar eso cambiando el propietario de su propio usuario a un grupo de roles del que sea miembro.

Gracias a RhodiumToad en #postgresql por ayudar con esto.


2
Esto es mucho más útil ya que cambia la propiedad de todo el esquema, incluidas funciones, índices, secuencias, etc. ¡Gracias!
liviucmg

No cambia los propietarios del esquema. ¿Cómo cambiar los propietarios del esquema también?
Andrus

@Andrus ALTER DATABASE $ DB PROPIETARIO A $ PROPIETARIO;
Johan Dahlin

alter database cambia el propietario de la base de datos completa. Pregunté cómo cambiar los propietarios del esquema.
Andrus

ALTERAR EL ESQUEMA fred PROPIETARIO A Betty;
Eric Aldinger

21

Recientemente tuve que cambiar la propiedad de todos los objetos en una base de datos. Aunque las tablas, las vistas, los desencadenantes y las secuencias se cambiaron fácilmente, el enfoque anterior falló para las funciones, ya que la firma es parte del nombre de la función. Por supuesto, tengo experiencia en MySQL y no estoy tan familiarizado con Postgres.

Sin embargo, pg_dump le permite volcar solo el esquema y este contiene ALTER xxx OWNER TO yyy; declaraciones que necesitas. Aquí está mi poco de magia de concha sobre el tema

pg_dump -s YOUR_DB | grep -i 'owner to' | sed -e 's/OWNER TO .*;/OWNER TO NEW_OWNER;/i' | psqL YOUR_DB

No estoy seguro de por qué estás usando el grepcomando. Soy nuevo en Linux, pero, según tengo entendido, parece que sedestá bien usarlo, especialmente porque de todos modos estás especificando una coincidencia entre mayúsculas y minúsculas.
Bobort

19

muy simple, pruébalo ...

 select 'ALTER TABLE ' || table_name || ' OWNER TO myuser;' from information_schema.tables where table_schema = 'public';

44
Puede agregar una nota de que las cadenas correspondientes deben copiarse y ejecutarse. No es que no sea obvio: p
Nightscape

Lo que incluye la eliminación de todas las comillas alrededor de las declaraciones de alteración ... varios cursores o reemplazar ayuda en este caso.
conocidoasilya

19

es muy simple

  1. su - postgres
  2. psql
  3. REASIGNAR PROPIETARIO DE [old_user] TO [new_user];
  4. \ c [su base de datos]
  5. REASIGNAR PROPIETARIO DE [old_user] TO [new_user];

hecho.


1
Esto probablemente hace lo que el consultante quería. De lejos, el más fácil.
Geof Sawaya

1
Llegas solo 4 años tarde a la fiesta; desplazarse hacia arriba: stackoverflow.com/a/13535184/1772379
Ben Johnson

16

Me gusta este, ya que modifica las tablas , vistas , secuencias y funciones del propietario de un determinado esquema de una vez (en una instrucción sql), sin crear una función y puede usarlo directamente en PgAdmin III y psql :

(Probado en 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$$;

Basado en las respuestas proporcionadas por @rkj, @AlannaRose, @SharoonThomas, @ user3560574 y esta respuesta por @a_horse_with_no_name

Muchas gracias.


Mejor aún: también cambie la base de datos y el propietario del esquema .

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$$;

¡ASOMBROSO! ¿Por qué Postgres no agrega esto? ¡No lo sé!
pip

Dos preguntas: 1) Parece que las líneas primera y tercera "ALTER TABLE" son engañosas. ¿Es intencional? 2) Estamos descubriendo que information_schema.sequencesestá vacío a pesar de que SELECT c.* FROM pg_class c WHERE c.relkind = 'S';enumera secuencias. ¿Por qué podrían no coincidir?
GuyPaddock

Además, ¿no debería ser la segunda ALTERconsulta un ALTER SEQUENCE?
GuyPaddock

12

Tuve que cambiar la propiedad de tablas, vistas y secuencias y descubrí que la excelente solución publicada por @rjk funciona bien, a pesar de un detalle: si los nombres de los objetos son de mayúsculas y minúsculas (por ejemplo, "TableName"), esto fallará con un " error no encontrado.
Para evitar esto, envuelva los nombres de los objetos con '"' así:

Mesas

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;

Secuencias

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;

Puntos de vista

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

Puede probar lo siguiente en 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$$;

6

No existe dicho comando en PostgreSQL. Pero puede solucionarlo utilizando el método que describí hace algún tiempo para GRANT.


Gracias, muy buen artículo. Mantendré esto como referencia futura. Usando pgAdmin, terminé haciendo una copia de seguridad de la base de datos, descartando / eliminando la base de datos, otorgando temporalmente a new_owner los derechos necesarios y luego volviendo a crear y restaurando la base de datos como new_owner, con la opción "sin propietario" marcada en la ventana de restauración. Esto produjo los resultados que estaba buscando con new_owner como propietario de todo.
Kai

Postgres 9.3 introdujo el comando REASSIGN OWNED. postgresql.org/docs/9.3/sql-reassign-owned.html
Georg Zimmer

3

Basado en la respuesta de elysch , aquí hay una solución para múltiples esquemas:

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
$$;

2

La respuesta de @Alex Soto es la correcta y la esencia cargada por @Yoav Aner también funciona siempre que no haya caracteres especiales en los nombres de tabla / vista (que son legales en postgres).

Necesitas escapar de ellos para trabajar y he subido una esencia para eso: 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 )

Luego canalice el archivo de copia de seguridad nuevamente a PostgreSQL usando:

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

Como no se incluye ningún propietario, todas las tablas, esquemas, etc. creados se crean con el usuario de inicio de sesión que especifique.

He leído que esto también podría ser un buen enfoque para migrar entre versiones de PostgreSQL.


2

He creado un script conveniente para eso; pg_change_db_owner.sh . Este script cambia la propiedad de todas las tablas, vistas, secuencias y funciones en un esquema de base de datos y también propietario del esquema en sí.

Tenga en cuenta que si solo desea cambiar la propiedad de todos los objetos, en una base de datos particular, propiedad de un rol de base de datos particular, simplemente puede usar el comando en su REASSIGN OWNEDlugar.


1

A partir de PostgreSQL 9.0, tiene la capacidad de GRANT [priv name] ON ALL [object type] IN SCHEMAdónde [priv name]es lo típico SELECT, INSERT, UPDATE, DELETE, etcy [object type]puede ser uno de:

  • TABLES
  • SEQUENCES
  • FUNCTIONS

Los documentos de PostgreSQL se activan GRANTy REVOKEentran en más detalles sobre esto. En algunas situaciones, todavía es necesario usar trucos que involucren los catálogos del sistema ( pg_catalog.pg_*), pero no es tan común. Con frecuencia hago lo siguiente:

  1. BEGIN una transacción para modificar los privs
  2. Cambiar la propiedad de DATABASESa un "rol de DBA"
  3. Cambiar la propiedad del SCHEMAS"rol DBA"
  4. REVOKE ALLPrivs en todos TABLES, SEQUENCESy FUNCTIONSde todos los roles
  5. GRANT SELECT, INSERT, UPDATE, DELETE en tablas relevantes / apropiadas para los roles apropiados
  6. COMMIT La transacción DCL.

1

La solución aceptada no se ocupa de la propiedad de la función. La siguiente solución se encarga de todo (mientras revisaba me di cuenta de que es similar a @magiconair arriba)

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};"

1

El siguiente script de shell más simple funcionó para mí.

#!/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

Donde ingrese $ 1 - nombre de usuario (base de datos) $ 2 = esquema existente $ 3 = al nuevo esquema.


1

Igual que el enfoque de @ AlexSoto para las funciones:

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

Docker: Modificar propietario de todas las tablas + secuencias

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.