Postgres: vista actualizable (con cláusula “where in”) con opción de verificación.
Intento crear vistas actualizables con la opción “check option”. Cuando tengo uniones en los criterios de filtrado, utilizo una cláusula “where in” para simplificar las consultas. Sin embargo, si declaro la vista con ambas opciones “check option” y “where in”, la validación de datos no parece confiable. No veo esta restricción en el documento: https://www.postgresql.org/docs/current/sql-createview.html
¿Es un error? ¿Hay alguna solución alternativa?
create table tableA (
db_record_id serial NOT null PRIMARY KEY,
"name" varchar(60) NOT null UNIQUE
);
create or replace view viewSimpleA
as select * from tableA where name like 'a%'
with check option;
create or replace view viewA
as select * from tableA
where db_record_id in (
select db_record_id from tableA
where name like 'a%'
) with check option;
insert into viewSimpleA(name) values('abc'); -- OK
delete from tableA;
insert into viewA(name) values('abc'); -- KO, Error de SQL [44000]: ERROR: nueva fila viola la opción de verificación de la vista "viewa"
delete from tableA;
insert into viewSimpleA(name) values('abc');
update viewSimpleA set name = 'fine'; -- OK: la actualización es evitada por la opción de verificación
delete from tableA;
insert into viewA(name) values('abc');
update viewA set name = 'fine'; -- KO: la actualización se ejecuta, la vista está ahora vacía
delete from tableA;
select version(); -- PostgreSQL 13.5 (Debian 13.5-1.pgdg110+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 10.2.1-6) 10.2.1 20210110, 64-bit
EDITAR: He creado un informe de error aquí: enlace al informe de error
davy.ai
Después de probar tu código y leer la documentación, parece que este comportamiento no es un error, sino más bien una limitación de la opción
check
. La cláusulawhere in
en tu consultaviewA
está causando que la opcióncheck
falle al insertar nuevas filas que no cumplen con los criterios de filtro. La opcióncheck
está diseñada para evitar que se inserten, actualicen o eliminen filas que no coincidan con los criterios de filtro en la vista.Una solución alternativa para esta limitación es crear un disparador en la tabla base
tableA
que aplique la misma condición de filtrado que la opcióncheck
en tu consultaviewA
. De esta manera, cualquier inserción, actualización o eliminación en la tabla base también se evitará si no cumple la condición de filtro.A continuación se muestra un ejemplo de un disparador que aplica esta condición de filtro:
Este disparador verificará si una nueva fila que se inserte, actualice o elimine de
tableA
cumple la misma condición de filtro que tu consultaviewA
. Si no la cumple, se generará una excepción y se abortará la operación.Otra solución alternativa es evitar el uso de la opción
check
con una cláusulawhere in
, y en su lugar usar una subconsulta en la cláusulaselect
de tu vista. Esto hará que la vista devuelva solo filas que cumplan con los criterios de filtro, pero no evitará las inserciones, actualizaciones o eliminaciones en la vista o en la tabla base.Ten en cuenta que este enfoque no proporcionará el mismo nivel de protección que la opción
check
, ya que las actualizaciones, inserciones o eliminaciones en la tabla base o en la vista directamente no se filtrarán.