Использование правила для вставки в последовательность автоинкрементов вторичной таблицы - PullRequest
4 голосов
/ 12 февраля 2010

Чтобы автоматически добавить столбец во второй таблице, чтобы связать его с первой таблицей с помощью уникального индекса, у меня есть правило, такое как:

CREATE OR REPLACE RULE auto_insert AS ON INSERT TO user DO ALSO
INSERT INTO lastlogin (id) VALUES (NEW.userid);

Это прекрасно работает, если user.userid является целым числом. Однако, если это последовательность (например, тип serial или bigserial ), то то, что вставлено в таблицу lastlogin , является следующим идентификатором последовательности. Итак, эта команда:

INSERT INTO user (username) VALUES ('john');

вставит столбец [1, 'john', ...] в user , но столбец [2, ...] в lastlogin . Следующие 2 обходных пути работают, за исключением того, что второй использует вдвое больше серийных номеров, так как последовательность все еще автоматически увеличивается:

CREATE OR REPLACE RULE auto_insert AS ON INSERT TO user DO ALSO
INSERT INTO lastlogin (id) VALUES (lastval());

CREATE OR REPLACE RULE auto_insert AS ON INSERT TO user DO ALSO
INSERT INTO lastlogin (id) VALUES (NEW.userid-1);

К сожалению, обходные пути не работают, если я вставляю несколько строк:

INSERT INTO user (username) VALUES ('john'), ('mary');

Первый обходной путь будет использовать тот же идентификатор, а второй обходной путь - это все виды ошибок.

Возможно ли это сделать с помощью правил postgresql, или я должен просто сделать 2-ю вставку в lastlogin самостоятельно или использовать триггер строки? На самом деле, я думаю, что триггер строки также будет автоматически увеличивать последовательность при доступе к NEW.userid .

1 Ответ

6 голосов
/ 12 февраля 2010

Забудьте правила вообще. Они плохо .

Триггеры лучше для вас. И в 99% случаев, когда кто-то считает, что ему нужно правило. Попробуйте это:

create table users (
  userid serial primary key,
  username text
);

create table lastlogin (
  userid int primary key references users(userid),
  lastlogin_time timestamp with time zone
);

create or replace function lastlogin_create_id() returns trigger as $$
  begin
    insert into lastlogin (userid) values (NEW.userid);
    return NEW;
  end;
$$
language plpgsql volatile;

create trigger lastlogin_create_id
  after insert on users for each row execute procedure lastlogin_create_id();

Тогда:

insert into users (username) values ('foo'),('bar');

select * from users;
<i> userid | username 
--------+----------
      1 | foo
      2 | bar
(2 rows)
</i>
select * from lastlogin;
<i> userid | lastlogin_time 
--------+----------------
      1 | 
      2 | 
(2 rows)
</i>
...