Tengo una tabla que se completa durante una rutina ETL, una columna a la vez. Las columnas obligatorias (que son claves foráneas) se configuran primero y de una vez, por lo que el estado inicial de la tabla es:
key | fkey | a -------|--------|------- 1 | 1 | nullDespués de procesar los valores A, los inserto usando SQL Alchemy con el dialecto de PostgreSQL para un upsert simple:
upsert = sqlalchemy.sql.text(""" INSERT INTO table (key, a) VALUES (:key, :a) ON CONFLICT (key) DO UPDATE SET a = EXCLUDED.a """) Pero esto falla porque aparentemente intentó insertar el valor fkey como null .
psycopg2.IntegrityError: null value in column "fkey" violates not-null constraint DETAIL: Failing row contains (1, null, 0).¿La sintaxis es realmente correcta? ¿Por qué está fallando? ¿SQLAlchemy tiene alguna participación en este error o está traduciendo PLSQL correctamente?
Mi sospecha es que las comprobaciones de restricciones ocurren antes de que se active la resolución de CONFLICTO, por lo que, aunque en realidad funcionaría porque se garantiza que fkey no será nulo antes y no se sobrescribirá, la verificación de restricciones solo analiza la inserción tentativa y las restricciones de la tabla.
Esta es una limitación documentada actual de PostgreSQL, un área donde rompe la especificación.
Actualmente, solo las restricciones ÚNICA, CLAVE PRIMARIA, REFERENCIAS (clave externa) y EXCLUDE se ven afectadas por esta configuración. Las restricciones NOT NULL y CHECK siempre se verifican inmediatamente cuando se inserta o modifica una fila (no al final de la instrucción). Las restricciones de unicidad y exclusión que no se han declarado DEFERRABLE también se comprueban inmediatamente.
No puede aplazar la restricción NOT NULL , y parece que comprende el comportamiento predeterminado, que se ve aquí.
CREATE TABLE foo ( a int NOT NULL, b int UNIQUE, c int ); INSERT INTO foo (a,b,c) VALUES (1,2,3); INSERT INTO foo (b,c) VALUES (2,3); ERROR: null value in column "a" violates not-null constraint DETAIL: Failing row contains (null, 2, 3).