2010-07-14 19 views
23

Ho un problema con ALTER TABLE in postgre. Voglio cambiare la dimensione della colonna varchar. Quando provo a farlo, dice che la vista dipende da quella colonna. Non riesco a rilasciare la vista perché comething altro dipende da esso. C'è un altro modo se non abbandonare tutto e ricrearlo di nuovo?Problema con Postgres ALTER TABLE

Ho appena trovato un'opzione, che è quella di rimuovere la tabella che unisce dalla vista, quando non cambierò le colonne restituite, posso farlo. Ma ancora, ci sono più punti di vista che ho bisogno di cambiare. Non c'è niente come posso dire che dovrebbe essere differito e controllato con commit?

+1

copia la query di visualizzazione e poi la elimina e apporta le modifiche alla tabella – TaherT

risposta

15

Ho incontrato questo problema e non ho potuto trovare alcun modo per aggirarlo. Sfortunatamente, come meglio posso dire, è necessario eliminare le viste, modificare il tipo di colonna nella tabella sottostante e quindi ricreare le viste. Questo può accadere interamente in una singola transazione.

Il differimento del vincolo non si applica a questo problema. In altre parole, anche SET CONSTRAINTS ALL DEFERRED non ha alcun impatto su questa limitazione. Per essere precisi, il differimento del vincolo non si applica al controllo di coerenza che stampa ERROR: cannot alter type of a column used by a view or rule quando si tenta di modificare il tipo di una colonna sottostante una vista.

4

Mi sono imbattuto in questo problema oggi e ho trovato un lavoro in giro per evitare di lasciar cadere e ricreare la VISTA. Non posso semplicemente abbandonare la VISUALIZZAZIONE perché è una VISUALIZZAZIONE principale che ha molti VIEW dipendenti costruiti su di essa. A meno di avere uno script di ricostruzione per DROP CASCADE e quindi ricreare TUTTE le mie VISUALIZZAZIONI, si tratta di una soluzione.

Ho cambiato la mia VISTA master per utilizzare un valore fittizio per la colonna offendente, ha modificato la colonna nella tabella e ho riportato la VIEW alla colonna. Utilizzando una configurazione come questa:

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; 

Cercando di modificare il tipo base_table_field1 come questo:

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

vi darà questo errore:

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" 

Se si cambia master_view di utilizzare un valore fittizio per la colonna come questa:

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

quindi eseguire il alter:

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

e passare il punto di vista posteriore:

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

Tutto dipende se il vostro master_view ha un tipo esplicito che non cambia. Dal momento che il mio VIEW usa '(base_table_field1 * .01) :: numerico AS campo1' funziona, ma 'base_table_field1 AS campo1' non lo farebbe perché il tipo di colonna cambia. Questo approccio potrebbe aiutare in alcuni casi come il mio.

+4

Come è meglio che eliminare la vista, alterare la tabella e creare nuovamente la visualizzazione? Trovo che ciò sia peggio, dovendo controllare il DDL della vista e trovare le istanze della colonna. Quando si rilascia, tutto ciò che serve è conservare una copia del DDL della vista originale, in modo da poterlo creare nuovamente. – ADTC

+3

Come è meglio che abbandonare la vista? La prima riga ... "è una VISTA master che ha molte VISTE dipendenti costruite su di essa." Cioè, la cascata si abbassa anche a quelle viste dipendenti. –

7

Se non è necessario cambiare il tipo del campo, ma solo le dimensioni di esso, questo approccio dovrebbe funzionare:

Partendo da queste tabelle:

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

\d foo e \d voo entrambi mostrano la lunghezza come 10:

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

Ora cambiare le lunghezze a 20 nel pg_attribute tavolo:

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

(nota: il 20 + 4 è un po 'pazzo PostgreSQL eredità cosa, il 4 è obbligatoria.)

Ora \d foo spettacoli:

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

Bonus: che era waaay più veloce di quello:

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

Tecnicamente è possibile modificare le dimensioni della tabella c olumn senza cambiare la dimensione della colonna della vista, ma nessuna garanzia su quali effetti collaterali avranno; probabilmente è meglio cambiarli entrambi contemporaneamente.

fonte e più piena spiegazione: http://sniptools.com/databases/resize-a-column-in-a-postgresql-table-without-changing-data

+7

Dovresti evitare di cambiare manualmente i cataloghi (come pg_attribute) quando possibile. Esiste il rischio reale di avere qualcosa di sbagliato e di causare errori, inclusi arresti anomali e danneggiamento dei dati, in seguito quando meno te lo aspetti. FARE SOLO come ultima risorsa, DOPO aver consultato il codice sorgente per assicurarti di non perdere nulla.Suggerire questo senza disclaimer è irresponsabile. – intgr

+0

È così che il motore di dati fa davvero dietro le quinte. Non stai modificando TYPE, ma la dimensione. Poiché è VARCHAR, non viene fatto alcun danno ai dati. +1 –

2

Sono un po 'in ritardo alla festa, ma anni dopo questa domanda è stata pubblicata, una soluzione brillante è stato inviato tramite un articolo si fa riferimento di seguito (non il mio - sono semplicemente un beneficiario grato del suo genio).

Ho appena eseguito il test su un oggetto a cui viene fatto riferimento (al primo livello) in 136 viste separate e ciascuna di queste viste viene referenziata in altre viste. La soluzione è durata in pochi secondi.

Quindi, leggere questo articolo e copiare e incollare il tavolo e due funzioni elencate: esempio

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

Implementazione:

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

E ora per 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

Sei una grande anima. – Vishnu

Problemi correlati