2009-08-24 40 views
10

Khi tôi sử dụng quy tắc viết lại để tách một chèn vào một bảng thành chèn vào hai bảng khác, nơi một trong các giá trị được chèn vào làm mặc định tiếp theo ('some_sequence ') với cùng một trình tự cho cả hai bảng, sau đó các giá trị mặc định được chèn khác nhau trong hai bảng. Điều này có thể do thay thế văn bản đơn giản bằng quy tắc viết lại. Tôi đã hy vọng thay vào đó giá trị mặc định sẽ được giải quyết đầu tiên và sau đó giá trị tương tự được ghi vào cả hai bảng.Các quy tắc và vấn đề tiếp theo() của PostgreSQL (rất cụ thể về PostgreSQL)

Dưới đây là một ví dụ (như bạn có thể đoán, tôi đang cố gắng để thực hiện chuyên môn hóa/tổng quát sử dụng quy tắc):

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

Số liệu cụ thể cho con cái của các loại đầu tiên được lưu giữ trong

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

Tiếp theo, tôi đã xác định chế độ xem Children1 tham gia cả hai bảng ở trên (tôi đã viết lại chế độ xem bằng cách nêu rõ những gì PostgreSQL thực hiện để xác định lượt xem theo tài liệu)

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; 

Cuối cùng viết lại quy tắc tôi đang gặp vấn đề với:

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

Đang cố gắng để chèn dữ liệu với

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

mang lại được thông báo lỗi

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

Một cách để giải quyết việc này đang thay thế chèn thứ hai của quy tắc viết lại bằng

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

nhưng điều này phụ thuộc vào tính duy nhất của thuộc tính1 mà tôi không muốn áp đặt. Một giải pháp khác sẽ là chèn các giá trị đầu tiên vào một bảng tạm thời, và sau đó chọn hai lần từ đó cho các chèn vào hai bảng. Nhưng tôi không thích vì lý do hiệu suất.

Có ai có ý tưởng khác về cách nhận các giá trị mặc định giống nhau trong cả hai bảng (chỉ sử dụng quy tắc và không kích hoạt trình kích hoạt)?

Trả lời

5

Từ các tài liệu http://www.postgresql.org/docs/8.4/static/rules.html

Nó (Hệ thống Rule) sẽ thay đổi các truy vấn để có quy tắc xem xét, và sau đó chuyển truy vấn sửa đổi để các nhà quy hoạch truy vấn cho việc lập kế hoạch và thực hiện

để nó viết lại lần đầu các truy vấn mà không thực hiện bất kỳ điều gì.

bạn có thể làm cho nó hoạt động khi bạn không chèn các bản ghi multipe cùng một lúc:

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

Sau đó, bạn có thể làm:

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

nhưng không

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

Vì vậy, bạn thực sự không nên sử dụng hệ thống quy tắc với các lời gọi().

Ngoài ra hãy xem những ý kiến ​​trên các trang này:

Một mẹo: vùng hỗ trợ tại danh sách postgresql gửi thư là coi là tuyệt vời như chính cơ sở dữ liệu!

Và nhân tiện: bạn có biết rằng postgresql có hỗ trợ thừa kế ngoài hộp không?

Tóm tắt: bạn nên sử dụng trigger hoặc tránh chèn nhiều hàng!

+0

Cảm ơn các liên kết. Họ không giải quyết vấn đề, nhưng ít nhất tôi không cảm thấy cô đơn nữa ;-). Tính năng kế thừa được tích hợp không hoàn toàn cung cấp những gì tôi muốn. –

0

Quy tắc sẽ làm điều đó cho bạn - họ viết lại truy vấn trước khi nó được thực hiện.

Miễn là bạn có bảng thực sự cho cơ sở (Children1), tôi nghĩ bạn sẽ có thể thực hiện điều tương tự với TRIGGER thay vì RULE.

+0

Xin lỗi, nhưng bạn đã đọc hoàn toàn câu hỏi của tôi chưa? –

+0

Um, tôi nghĩ là tôi đã làm. Nhưng tôi đoán tôi ít nhất là bỏ lỡ phần "không gây nên", xin lỗi về điều đó. –

+0

Và các quy tắc cho kết quả sai ;-). –

Các vấn đề liên quan