Cuando uso una regla de reescritura que divide una inserción en una tabla en inserciones en otras dos tablas donde uno de los valores insertados tiene como valor predeterminado nextval ('some_sequence ') con la misma secuencia para ambas tablas, los valores predeterminados insertados son diferentes en las dos tablas. Esto es probablemente debido a la sustitución de texto simple por la regla de reescritura. En cambio, esperaba que el valor predeterminado se resolviera primero y luego se escribiera el mismo valor en ambas tablas.Reglas de PostgreSQL y nextval()/problema de serie (muy específico de PostgreSQL)
Aquí un ejemplo (como probablemente adivinar, estoy tratando de poner en práctica la especialización/generalización usando reglas):
-- first and third commands can be skipped if id is defined as serial
create sequence parents_id_seq;
create table Parents(
id integer default(nextval('parents_id_seq')) primary key,
type varchar(50) not null check(type in ('Child1', 'Child2')),
unique (id, type),
attribute1 varchar(50) not null unique check(length(attribute1) > 0)
);
alter sequence parents_id_seq owned by parents.id;
Los datos específicos para los niños de la primera clase se mantiene en
create table Partial_Children1(
id integer default(nextval('parents_id_seq')) primary key,
type varchar(50) not null check(type = 'Child1'),
foreign key (id, type) references Parents(id, type),
attribute2 varchar(50) not null check(length(attribute2) > 0)
);
Siguiente He definido una vista Children1 que une las dos tablas anteriores (reescribí la vista indicando explícitamente lo que PostgreSQL hace para definir las vistas según la documentación)
create table Children1(
id int default(nextval('parents_id_seq')),
type varchar(50) not null check(type in ('Child1')),
attribute1 varchar(50) not null check(length(attribute1) > 0),
attribute2 varchar(50) not null check(length(attribute2) > 0)
);
create rule "_RETURN" as on select to Children1 do instead
select p.*, c.attribute2
from Parents p
join Partial_Children1 c
on p.id = c.id;
Finalmente la regla de reescritura que estoy teniendo problemas con:
create rule ct_i_children1 as
on insert to Children1
do instead (
insert into Parents(attribute1, type)
values(new.attribute1, 'Child1');
insert into Partial_Children1(attribute2, type)
values(new.attribute2, 'Child1');
);
Tratando de insertar datos con
insert into Children1 (attribute1, attribute2)
values ('a1', 'a2'),
('b1', 'b2');
produce el mensaje de error
ERROR: insert or update on table "partial_children1" violates foreign key constraint "partial_children1_id_fkey"
DETAIL: Key (id,type)=(3,Child1) is not present in table "parents".
Una manera de resolver este está reemplazando la segunda inserción de la regla de reescritura por
insert into Partial_Children1(id, attribute2, type)
select p.id, new.attribute2, p.type
from Parents p
where p.attribute1 = new.attribute1
pero esto se basa en la exclusividad de attribute1, que no quiero imponer. Otra solución sería insertar los valores primero en una tabla temporal, y luego seleccionar dos veces desde allí para las inserciones en las dos tablas. Pero no me gusta por motivos de rendimiento.
¿Alguien tiene otra idea de cómo obtener los mismos valores predeterminados en ambas tablas (simplemente usando reglas y no activadores)?
Gracias por los enlaces. No resuelven el problema, pero al menos ya no me siento solo ;-). La herencia incorporada no ofrecía exactamente lo que yo quería. –