2009-08-24 13 views
10

Kiedy używam reguły przepisywania, która dzieli wstawkę do jednej tabeli na wstawki do dwóch innych tabel, gdzie jedna z wstawionych wartości ma domyślnie nextval ('some_sequence ') z tą samą sekwencją dla obu tabel, wtedy wstawione wartości domyślne różnią się w dwóch tabelach. Jest to prawdopodobnie spowodowane prostą zamianą tekstu przez regułę przepisywania. Zamiast tego miałem nadzieję, że wartość domyślna zostanie najpierw rozwiązana, a następnie ta sama wartość zostanie zapisana w obu tabelach.Reguły PostgreSQL i nextval()/problem szeregowy (bardzo specyficzny dla PostgreSQL)

Oto przykład (jak zapewne domyślić, próbuję wdrożyć specjalizacji/uogólnienia używając reguł):

-- 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; 

dane specyficzne dla dzieci pierwszego rodzaju są przechowywane w

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) 
); 

Następnie zdefiniowałem widok Children1, który łączy obie powyższe tabele (przepisałem widok, wyraźnie stwierdzając, co PostgreSQL definiuje widoki zgodnie z dokumentacją).

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; 

końcu reguła przepisywania Mam problemy:

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'); 
); 

Próbuje wstawić dane z

insert into Children1 (attribute1, attribute2) 
    values ('a1', 'a2'), 
     ('b1', 'b2'); 

daje komunikat o błędzie

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". 

sposób na rozwiązanie tego zastępuje drugą wstawkę reguły przepisywania przez

insert into Partial_Children1(id, attribute2, type) 
    select p.id, new.attribute2, p.type 
    from Parents p 
    where p.attribute1 = new.attribute1 

ale to zależy od wyjątkowości atrybutu1, którego nie chcę narzucać. Innym rozwiązaniem byłoby wstawienie wartości najpierw do tabeli tymczasowej, a następnie dwukrotne wybranie tam wstawień do dwóch tabel. Ale nie podoba mi się to ze względu na wydajność.

Czy ktoś ma inny pomysł, jak uzyskać te same wartości domyślne w obu tabelach (tylko przy użyciu reguł i wyzwalaczy nie)?

Odpowiedz

5

Od docs http://www.postgresql.org/docs/8.4/static/rules.html

It (System reguły) modyfikuje zapytań wziąć reguły pod uwagę, a przechodzi następnie zmodyfikowany zapytanie do planowania zapytań o planowaniu i wykonanie

więc najpierw przepisuje zapytania bez wykonywania czegokolwiek.

możesz pracować kiedy nie wstawiać rekordy Nieograniczone naraz:

create or replace rule ct_i_children1 as 
    on insert to Children1 
    do instead (
    insert into Parents(id, attribute1, type) 
     values(nextval('parents_id_seq'), new.attribute1, 'Child1'); 
    insert into Partial_Children1(id, attribute2, type) 
     values(currval('parents_id_seq'), new.attribute2, 'Child1'); 
); 

Następnie można zrobić:

insert into Children1 (attribute1, attribute2) values ('a1', 'a2'); 
insert into Children1 (attribute1, attribute2) values ('b1', 'b2'); 

ale nie

insert into Children1 (attribute1, attribute2) 
    values ('a1', 'a2'), 
     ('b1', 'b2'); 

więc naprawdę nie powinien używać systemu reguł z trudnymi połączeniami currval().

Dodatkowo spojrzeć na komentarze na tych stronach:

Kolejna wskazówka: wsparcie na listę PostgreSQL korespondencji jest tak doskonałe, jak sam silnik bazy danych!

A przy okazji: czy wiesz, że postgresql ma obsługę dziedziczenia natychmiastowego?

Podsumowanie: należy użyć wyzwalaczy lub uniknąć wielu wkładek rzędu!

+0

Dzięki za linki. Nie rozwiązują problemu, ale przynajmniej nie czuję się już sam ;-). Wbudowane dziedziczenie nie oferowało tego, co chciałem. –

0

Reguły zrobią to za ciebie - przepisują zapytanie przed jego wykonaniem.

Dopóki masz rzeczywisty stół dla bazy (Dzieci1), myślę, że będziesz w stanie osiągnąć to samo z TRIGGEREM zamiast REGUŁY.

+0

Przepraszam, ale czy przeczytałeś moje pytanie całkowicie? –

+0

Um, myślałem, że tak. Ale myślę, że przynajmniej przegapiłem część "nie wyzwalającą", przepraszam za to. –

+0

I zasady dają złe wyniki ;-). –