2014-12-21 5 views
1

Вот сценарий:Вставить вставить идентификатор в другую таблицу

create table a (
id serial primary key, 
val text 
); 

create table b (
id serial primary key, 
a_id integer references a(id) 
); 

create rule a_inserted as on insert to a do also insert into b (a_id) values (new.id); 

Я пытаюсь создать запись в b ссылающийся на a при вставке в a таблице. Но я получаю, что new.id имеет значение NULL, поскольку он автоматически генерируется из последовательности. Я также попробовал спусковой крючок AFTER вставить FOR EACH ROW, но результат был тот же. Любой способ справиться с этим?

+0

Он отлично работает со мной: http://sqlfiddle.com/#!15/bdd7b/1 может быть это связано с версией Ot вашей БД. У меня нет знаний о postgresql –

+0

@ Blood-HaZaRd это работает, потому что вы действительно вставили id, фактический случай заключается в том, что идентификатор автоматически сгенерирован 'DEFAULT next_val ('sequence_name')' и не переходит в NEW, поскольку новый определяет входные значения, потому что правило происходит ** перед ** фактической вставкой (whitch означает, что идентификатор еще не создан). Попробуйте вставить это в свой скрипт «вставить в значения (« Буджа »);' –

ответ

2

Избегайте правил, так как они вернутся, чтобы укусить вас.

Используйте триггер после таблицы a, который запускается для каждой строки. Это должно выглядеть примерно так (непроверенный):

create function a_ins() returns trigger as $$ 
begin 
    insert into b (a_id) values (new.id); 
    return null; 
end; 
$$ language plpgsql; 

create trigger a_ins after insert on a 
for each row execute procedure a_ins(); 
+0

Прочтите вопрос! «Я также попробовал это с помощью триггера, который запускается ПОСЛЕ ВСТАВКИ ДЛЯ КАЖДОЙ РУКИ на столе, но результат был таким же» –

+0

Я прочитал этот вопрос, и он полностью неясен в нем * почему * это не сработало для вас, поскольку вы не предоставили код, который вы использовали. Я ответил, что вам нужно сделать в конце. –

+0

Я сделал ** тот же ** с помощью триггера. И результат был ** одинаковым **. Код был бы очень очевиден, так как я представил, какие атрибуты были использованы, и это не сработало, потому что «но то, что я получаю, это то, что new.id равно null». С другой стороны, если вы уверены, что он должен работать с триггером, возможно, что-то я сделал неправильно.Итак, я проверю его и предоставил код. Но это не меняет того факта, что ответ не соответствует вопросу. –

2

Чтобы сохранить его простым, вы также можете просто использовать data-modifying CTE (а не триггер или правило):

WITH ins_a AS (
    INSERT INTO a(val) 
    VALUES ('foo') 
    RETURNING a_id 
    ) 
INSERT INTO b(a_id) 
SELECT a_id 
FROM ins_a 
RETURNING b.*; -- last line optional if you need the values in return 

Родственный ответ с более подробной информации:

Или у НУ может работать с currval() and lastval():

-1

Не использовать триггеры или другие базы данных кунг-фу. Эта ситуация происходит каждый момент где-то в мире - существует простое решение:

После вставки используйте функцию LASTVAL(), которая возвращает значение последней последовательности, которая была автоматически увеличена.

Ваш код будет выглядеть следующим образом:

insert into a (val) values ('foo'); 
insert into b (a_id, val) values (lastval(), 'bar'); 

Легко читать, поддерживать и понимать.

+0

Это не совсем то, что я просил, и Я фактически препятствую таким узорам. Наличие такого кода в базе данных, первое, что нелегко, это ** поддерживать **. –

+0

@RimantasJacikevicius это то, что все делают. Кажется, это именно то, о чем вы просите. Что касается легкости, триггеры записи являются болезненными, и вы просто просочились в приложение. Оставляя весь код в приложении, это хороший дизайн. – Bohemian

+3

@Bohemian: 'Оставляя весь код в приложении хорошим дизайном'. Это совершенно произвольное требование. Я мог бы ответить, что использование большей части вашей логики и правил в базе данных - лучший дизайн. Правда в том, что все зависит от точных требований. У вас может быть одна общая БД и десять различных приложений, основанных на ней ... –