2010-07-14 25 views
23

Tengo un problema con ALTER TABLE en postgre. Quiero cambiar el tamaño de la columna varchar. Cuando trato de hacer esto, dice que la vista depende de esa columna. No puedo quitar la vista porque depende de otra cosa. ¿Hay alguna otra manera que dejar caer todo y volver a crearlo?Problema con Postgres ALTER TABLE

Acabo de encontrar una opción, que es eliminar la tabla que une desde la vista, cuando no voy a cambiar las columnas devueltas, puedo hacerlo. Pero aún así, hay más puntos de vista que necesitaré cambiar. ¿No hay nada? ¿Cómo puedo decir que debe diferirse y verificarse con commit?

+1

copie la consulta de la vista y luego elimínela y realice cambios en la Tabla – TaherT

Respuesta

15

Me encontré con este problema y no pude encontrar ninguna forma de evitarlo. Lamentablemente, lo mejor que puedo decir es que se deben eliminar las vistas, modificar el tipo de columna en la tabla subyacente y luego volver a crear las vistas. Esto puede suceder completamente en una sola transacción.

El aplazamiento de restricciones no se aplica a este problema. En otras palabras, incluso SET CONSTRAINTS ALL DEFERRED no tiene ningún impacto sobre esta limitación. Para ser específico, el aplazamiento de restricción no se aplica a la comprobación de coherencia que imprime ERROR: cannot alter type of a column used by a view or rule cuando se intenta alterar el tipo de una columna subyacente a una vista.

4

Me encontré con este problema hoy y encontré una solución alternativa para evitar caer y volver a crear el VIEW. No puedo simplemente dejar caer mi VISTA porque es una VISTA maestra que tiene muchas VISTAS dependientes construidas sobre ella. A falta de tener un script de reconstrucción para DROP CASCADE y luego recrear TODAS mis VISTAS, esto es una solución alternativa.

Cambio mi VISTA maestra para usar un valor ficticio para la columna ofensiva, alteré la columna en la tabla y cambié mi VISTA de nuevo a la columna. Utilizando una configuración como esta:

CREATE TABLE base_table 
(
    base_table_id integer, 
    base_table_field1 numeric(10,4) 
); 

CREATE OR REPLACE VIEW master_view AS 
    SELECT 
    base_table_id AS id, 
    (base_table_field1 * .01)::numeric AS field1 
    FROM base_table; 

CREATE OR REPLACE VIEW dependent_view AS 
    SELECT 
    id AS dependent_id, 
    field1 AS dependent_field1 
    FROM master_view; 

tratar de alterar el tipo base_table_field1 así:

ALTER TABLE base_table ALTER COLUMN base_table_field1 TYPE numeric(10,6); 

le dará este error:

ERROR: cannot alter type of a column used by a view or rule 
DETAIL: rule _RETURN on view master_view depends on column "base_table_field1" 

Si cambia master_view utilizar un valor ficticio para la columna como esta:

CREATE OR REPLACE VIEW master_view AS 
    SELECT 
    base_table_id AS id, 
    0.9999 AS field1 
    FROM base_table; 

A continuación, ejecute su alter:

ALTER TABLE base_table ALTER COLUMN base_table_field1 TYPE numeric(10,6); 

y el interruptor de su vista posterior:

CREATE OR REPLACE VIEW master_view AS 
    SELECT 
    base_table_id AS id, 
    (base_table_field1 * .01)::numeric AS field1 
    FROM base_table; 

Todo depende de si su master_view tiene un tipo explícito que no cambia. Como my VIEW usa '(base_table_field1 * .01) :: numeric AS field1', funciona, pero 'base_table_field1 AS field1' no porque el tipo de columna cambia. Este enfoque podría ayudar en algunos casos como el mío.

+4

¿Cómo es esto mejor que eliminar la vista, alterar la tabla y crear la vista nuevamente? Encuentro que esto es peor, al tener que mirar a través del DDL de la vista y encontrar instancias de la columna. Cuando está bajando, todo lo que necesita es conservar una copia del DDL de la vista original para que pueda volver a crearla. – ADTC

+3

¿Cómo es esto mejor que dejar caer la vista? La primera línea ... "es una VISTA maestra que tiene muchas VISTAS dependientes construidas sobre ella". Es decir, las cascadas descendientes de esas vistas dependientes también. –

7

Si no necesita cambiar el tipo del campo, pero sólo el tamaño de la misma, este enfoque debería funcionar:

A partir de estas tablas:

CREATE TABLE foo (id integer primary key, names varchar(10)); 
CREATE VIEW voo AS (SELECT id, names FROM foo); 

\d foo y \d voo ambas muestran la longitud como 10:

id  | integer    | not null 
names | character varying(10) | 

Ahora cambiar las longitudes a 20 en el pg_attribute tabla:

UPDATE pg_attribute SET atttypmod = 20+4 
WHERE attrelid IN ('foo'::regclass, 'voo'::regclass) 
AND attname = 'names'; 

(nota: el 20 + 4 es un poco loca cosa PostgreSQL legado, el 4 es obligatoria.)

Ahora \d foo espectáculos:

id  | integer    | not null 
names | character varying(10) | 

Bono: que era waaay más rápido que hacerlo:

ALTER TABLE foo ALTER COLUMN names TYPE varchar(20); 

Técnicamente puede cambiar el tamaño de la tabla c olumn sin cambiar el tamaño de la columna de vista, pero no hay garantías sobre qué efectos secundarios tendrá; probablemente sea mejor cambiarlos a la vez.

origen y explicación más completa: http://sniptools.com/databases/resize-a-column-in-a-postgresql-table-without-changing-data

+7

Debe evitar cambiar los catálogos (como pg_attribute) manualmente siempre que sea posible. Existe un riesgo real de que algo salga mal y de que se produzcan errores, incluidos fallos y daños en los datos, más adelante cuando menos lo esperas. SÓLO hazlo como último recurso, DESPUÉS de consultar el código fuente para asegurarte de que no te falta nada.Sugerir esto sin renuncias es irresponsable. – intgr

+0

Así es como el motor de datos realmente funciona detrás de escena. No estás cambiando TIPO, pero el tamaño. Como es VARCHAR, no se dañan los datos. +1 –

2

Estoy un poco tarde a la fiesta, pero años después de esta pregunta fue publicada, una solución brillante destinaron a través de un artículo hace referencia a continuación (no la mía - Soy simplemente un beneficiario agradecido de su brillantez).

Acabo de probar esto en un objeto al que se hace referencia (en el primer nivel) en 136 vistas distintas, y cada una de esas vistas se hace referencia en otras vistas. La solución se ejecutó en cuestión de segundos.

lo tanto, leer este artículo y copiar y pegar la mesa y dos funciones enumeradas: ejemplo

http://mwenus.blogspot.com/2014/04/postgresql-how-to-handle-table-and-view.html

Implementación:

alter table mdm.global_item_master_swap 
alter column prod_id type varchar(128), 
alter column prod_nme type varchar(512); 

ERROR: cannot alter type of a column used by a view or rule DETAIL: rule _RETURN on view toolbox_reporting."Average_setcost" depends on column "prod_id" ********** Error **********

ERROR: cannot alter type of a column used by a view or rule

Y ahora, por la magia del ninja PostgreSQL:

select util.deps_save_and_drop_dependencies('mdm', 'global_item_master_swap'); 


alter table mdm.global_item_master_swap 
alter column prod_id type varchar(128), 
alter column prod_nme type varchar(512); 


select util.deps_restore_dependencies('mdm', 'global_item_master_swap'); 
+0

Eres una gran alma. – Vishnu

Cuestiones relacionadas