Выполнение UPSERT, когда на строку ссылается FK - PullRequest
1 голос
/ 11 апреля 2011

Допустим, у меня есть таблица предметов, и для каждого предмета может быть сохранена дополнительная информация, которая попадает во вторую таблицу. На дополнительную информацию ссылается FK в первой таблице, которая может быть NULL (если элемент не имеет дополнительной информации).

TABLE item (
    ...
    item_addtl_info_id INTEGER
)

CONSTRAINT fk_item_addtl_info FOREIGN KEY (item_addtl_info)
    REFERENCES addtl_info (addtl_info_id)

TABLE addtl_info (
    addtl_info_id INTEGER NOT NULL
    GENERATED BY DEFAULT 
    AS IDENTITY (
        INCREMENT BY 1
        NO CACHE
        ),
    addtl_info_text VARCHAR(100)
    ...
    CONSTRAINT pk_addtl_info PRIMARY KEY (addtl_info_id)
)

Какова "лучшая практика" для обновления дополнительной информации элемента (предпочтительно в IBM DB2 SQL)?

Это должна быть операция UPSERT, означающая, что если дополнительная информация еще не существует, то новая запись создается во второй таблице, но если она существует, то она только обновляется, а FK в первой таблице нет изменить.

Поэтому обязательно, это логика:

UPSERT(item, item_info):
CASE WHEN item.item_addtl_info_id IS NULL THEN
    INSERT INTO addtl_info (item_info)
    UPDATE item.item_addtl_info_id (addtl_info.addtl_info_id)
                                               ^^^^^^^^^^^^^
ELSE
    UPDATE addtl_info (item_info)
END

Моя основная проблема заключается в том, как получить недавно вставленный идентификатор строки addtl_info (подчеркнуто выше). В хранимой процедуре я могу запросить идентификатор из последовательности и сохранить его в переменной, но, возможно, есть более простой способ. Разве это не то, что все время возникает при программировании баз данных?

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

На самом деле эта операция UPSERT должна быть частью языка SQL как стандартная операция (может быть, и я просто не знаю об этом?) ...

1 Ответ

2 голосов
/ 11 апреля 2011

Синтаксис, который я искал:

SELECT * FROM NEW TABLE ( INSERT INTO phone_book VALUES ( 'Peter Doe','555-2323' ) )

из Википедии (http://en.wikipedia.org/wiki/Insert_%28SQL%29)

Это способ обращения к записи, которая была только что вставлена ​​в таблицу.

Мой коллега назвал эту конструкцию "триггером на месте", который на самом деле ...

Вот первая версия, которую я собрал как составной оператор SQL:

begin atomic
declare addtl_id integer;
set addtl_id = (select item_addtl_info_id from item where item.item_id = XXX);
if addtl_id is null
then
    set addtl_id = (select addtl_info_id from new table 
                    (insert into addtl_info
                        (addtl_info_text)
                        values ('My brand new additional info')
                    )
                  );
    update item set item.item_addtl_info_id = addtl_id
    where item.item_id = XXX;

else
   update addtl_info set addtl_info_text = 'My updated additional info'
   where addtl_info.addtl_info_id = addtl_id;
end if;
end

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

Я также пытался использовать MERGE INTO, но не смог выяснить синтаксис для обновления таблицы, отличный от того, который был указан в качестве цели.

...