postgresql でのテンポラル データベースの設定に関する情報をフォローしています。最初に質問、次に技術的なビット。
質問: テーブルにクリーンな挿入を 1 回実行すると、public.countries
テーブルに行が 2 重になるのはなぜtemporal.countries
ですか? countries_ins
(ルール内に) 1 つの挿入のみが表示されます。これは機能ですか、それともバグですか?
さて、スキーマは次のとおりです。
DROP SCHEMA IF EXISTS temporal CASCADE;
DROP SCHEMA IF EXISTS history CASCADE;
----------------------------
-- Temporal countries schema
-- vjt@openssl.it
--
create schema temporal; -- schema containing all temporal tables
create schema history; -- schema containing all history tables
-- Current countries data - nothing special
--
create table temporal.countries (
id serial primary key,
name varchar UNIQUE
);
-- Countries historical data.
--
-- Inheritance is used to avoid duplicating the schema from the main table.
-- Please note that columns on the main table cannot be dropped, and other caveats
-- http://www.postgresql.org/docs/9.0/static/ddl-inherit.html#DDL-INHERIT-CAVEATS
--
create table history.countries (
hid serial primary key,
valid_from timestamp not null,
valid_to timestamp not null default '9999-12-31',
recorded_at timestamp not null default now(),
constraint from_before_to check (valid_from < valid_to),
constraint overlapping_times exclude using gist (
box(
point( extract( epoch from valid_from), id ),
point( extract( epoch from valid_to - interval '1 millisecond'), id )
) with &&
)
) inherits ( temporal.countries );
create index timestamps on history.countries using btree ( valid_from, valid_to ) with ( fillfactor = 100 );
create index country_id on history.countries using btree ( id ) with ( fillfactor = 90 );
-- The countries view, what the Rails' application ORM will actually CRUD on, and
-- the core of the temporal updates.
--
-- SELECT - return only current data
--
create view public.countries as select * from only temporal.countries;
-- INSERT - insert data both in the current data table and in the history table
--
create rule countries_ins as on insert to public.countries do instead (
insert into temporal.countries ( name )
values ( new.name )
returning temporal.countries.*;
insert into history.countries ( id, name, valid_from )
values ( currval('temporal.countries_id_seq'), new.name, now() )
);
-- UPDATE - set the last history entry validity to now, save the current data in
-- a new history entry and update the current table with the new data.
--
create rule countries_upd as on update to countries do instead (
update history.countries
set valid_to = now()
where id = old.id and valid_to = '9999-12-31';
insert into history.countries ( id, name, valid_from )
values ( old.id, new.name, now() );
update only temporal.countries
set name = new.name
where id = old.id
);
-- DELETE - save the current data in the history and eventually delete the data
-- from the current table.
--
create rule countries_del as on delete to countries do instead (
update history.countries
set valid_to = now()
where id = old.id and valid_to = '9999-12-31';
delete from only temporal.countries
where temporal.countries.id = old.id
);
-- EOF
そして、それを空のデータベースにロードして単一の挿入を行うと、次のことが起こります((私にとって)驚くべき結果については、39〜40行目を確認してください)。
1 test=# \i /home/username/temporal.sql
2 psql:/home/sirrobert/temporal.sql:1: NOTICE: drop cascades to 3 other objects
3 DETAIL: drop cascades to table temporal.countries
4 drop cascades to view countries
5 drop cascades to table history.countries
6 DROP SCHEMA
7 DROP SCHEMA
8 CREATE SCHEMA
9 CREATE SCHEMA
10 CREATE TABLE
11 CREATE TABLE
12 CREATE INDEX
13 CREATE INDEX
14 CREATE VIEW
15 CREATE RULE
16 CREATE RULE
17 CREATE RULE
18 test=# SELECT * FROM public.countries;
19 id | name
20 ----+------
21 (0 rows)
22
23 test=# SELECT * FROM temporal.countries;
24 id | name
25 ----+------
26 (0 rows)
27
28 test=# INSERT INTO public.countries (name) VALUES ('USA');
29 INSERT 0 1
30 test=# SELECT * FROM public.countries;
31 id | name
32 ----+------
33 1 | USA
34 (1 row)
35
36 test=# SELECT * FROM temporal.countries;
37 id | name
38 ----+------
39 1 | USA
40 1 | USA
41 (2 rows)