¿Cómo puedo agregar una columna a una base de datos Postgresql que no permita nulos?

243

Estoy agregando una nueva columna "NOT NULL" a mi base de datos Postgresql usando la siguiente consulta (desinfectada para Internet):

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) NOT NULL;

Cada vez que ejecuto esta consulta, recibo el siguiente mensaje de error:

ERROR:  column "mycolumn" contains null values

Estoy perplejo. ¿A dónde me estoy yendo mal?

NOTA: Estoy usando pgAdmin III (1.8.4) principalmente, pero recibí el mismo error cuando ejecuté el SQL desde la Terminal.

Huuuze
fuente

Respuestas:

400

Tienes que establecer un valor predeterminado.

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) NOT NULL DEFAULT 'foo';

... some work (set real values as you want)...

ALTER TABLE mytable ALTER COLUMN mycolumn DROP DEFAULT;
Luc M
fuente
1
Buena solución No pude acceder a los documentos de postgres en línea por alguna razón para ver cuál sería la sintaxis para esto.
Sean Bright
44
@SeanBright, puedes acceder al documento de Postgres sin conexión haciendo man ALTER_TABLE :)
allan.simon
@ allan.simon Nunca he usado PostgreSQL antes y no lo tengo instalado en ningún lado.
Sean Bright
2
Para aclarar: el valor predeterminado solo es necesario para actualizar las filas existentes, por lo que se puede eliminar inmediatamente después. Todas las filas existentes se actualizaron cuando se modificó la tabla (lo que puede llevar algo de tiempo, obviamente)
MSalters
2
Esto no funcionará si desea utilizar otra columna para calcular el valor inicial de las filas existentes. La respuesta de j_random_hacker lo permite, haciéndolo más robusto.
jpmc26
82

Como otros han observado, debe crear una columna anulable o proporcionar un valor POR DEFECTO. Si eso no es lo suficientemente flexible (por ejemplo, si necesita que el nuevo valor se calcule para cada fila individualmente de alguna manera), puede usar el hecho de que en PostgreSQL, todos los comandos DDL se pueden ejecutar dentro de una transacción:

BEGIN;
ALTER TABLE mytable ADD COLUMN mycolumn character varying(50);
UPDATE mytable SET mycolumn = timeofday();    -- Just a silly example
ALTER TABLE mytable ALTER COLUMN mycolumn SET NOT NULL;
COMMIT;
j_random_hacker
fuente
77
incluso en una transacción, NOT NULL se aplica inmediatamente, por lo que primero debe agregar una columna, completar valores, luego agregar NOT NULL, como lo hace esta respuesta. (probado en postgres 9.6)
Beni Cherniavsky-Paskin
48

Como las filas ya existen en la tabla, la ALTERinstrucción intenta insertar NULLen la columna recién creada para todas las filas existentes. Tendría que agregar la columna según lo permita NULL, luego llenar la columna con los valores que desee y luego configurarla como NOT NULLdespués.

Sean Bright
fuente
77
Ejemplo de cómo hacerlo hubiera sido realmente agradable. De lo contrario, la solución de Luc parece ser más completa y lista para usar.
Victor Farazdagi
5

Debe definir un valor predeterminado o hacer lo que dice Sean y agregarlo sin la restricción nula hasta que lo haya completado en las filas existentes.

Paul Tomblin
fuente
2

Especificar un valor predeterminado también funcionaría, suponiendo que un valor predeterminado sea apropiado.

Ryan Graham
fuente
2
Mejoraría la respuesta para dar la sintaxis modificada para crear la columna con un valor predeterminado (para ilustración).
hardmath
1

O cree una nueva tabla como temporal con la columna adicional, copie los datos en esta nueva tabla mientras la manipula según sea necesario para llenar la nueva columna no anulable, y luego cambie la tabla mediante un cambio de nombre de dos pasos.

Sí, es más complicado, pero es posible que deba hacerlo de esta manera si no desea una gran ACTUALIZACIÓN en una mesa en vivo.

alphadogg
fuente
3
No te -1, pero creo que puede haber dificultades sutiles con esto, por ejemplo, apuesto a que los índices, desencadenantes y vistas existentes continuarán refiriéndose a la tabla original incluso después del cambio de nombre, ya que creo que almacenan el Relid de la tabla (que no cambia) en lugar de su nombre.
j_random_hacker 05 de
1
Sí, debería haber declarado que la nueva tabla debería ser una copia exacta del original, incluida la adición de índices y demás. Mi mal por ser demasiado breve. La razón de esto es que también hay sutiles dificultades para realizar un ALTER en una mesa que puede estar en vivo, y a veces es necesario organizarlo.
alphadogg
Por ejemplo, utilizando el enfoque POR DEFECTO, agregará ese valor predeterminado a cada fila. No estoy seguro de cómo Postgres bloquea una tabla al hacer esto. O, si el orden de las columnas es importante, no puede simplemente agregar una columna con el comando ALTER.
alphadogg 05 de
Es justo que ALTER TABLE bloquee la tabla de acuerdo con los documentos de PostgreSQL, sin embargo, su enfoque no transaccional corre el riesgo de perder cambios si la tabla está realmente activa. También sugeriría que cualquier código que se base en el orden de las columnas esté roto (eso puede estar fuera de su control, por supuesto).
j_random_hacker
2
Este enfoque también es particularmente problemático si la tabla está referenciada por índices de clave externa, ya que todos ellos también tendrían que recrearse.
Aryeh Leib Taurog
0

esta consulta actualizará automáticamente los valores nulos

ALTER TABLE mytable ADD COLUMN mycolumn character varying(50) DEFAULT 'whatever' NOT NULL;
Jacktrade
fuente
-6

Esto funcionó para mí: :)

ALTER TABLE your_table_name ADD COLUMN new_column_name int;
Timxor
fuente
2
No hay NOT NULLrestricción en su consulta. Por supuesto que está funcionando.
Sylvain