Как создать уникальный индекс для подмножества строк в таблице db2 - PullRequest
0 голосов
/ 23 февраля 2019

Я пытаюсь создать уникальный индекс для подмножества данных в конкретной таблице.Существующие данные выглядят примерно так:

enter image description here

Но фактические данные должны выглядеть следующим образом -

enter image description here

Подмножеством строк будут строки с состоянием условия как A или B. Для этого набора строк комбинация unique_id и значение суммы должна быть уникальной.

DB2Версия была использована здесь 9,7 на сервере Windows.Возможен ли частичный или условный индекс в DB2?

1 Ответ

0 голосов
/ 23 февраля 2019

Новая таблица

create or replace function generate_unique_det()
returns varchar(13) for bit data
deterministic
no external action
contains sql
return generate_unique();

create table test_unique (
  unique_id int not null
, status char(1) not null
, amount int not null
, status2 varchar(13) for bit data not null generated always as 
  (case when status in ('A', 'B') then '' else generate_unique_det() end)
) in userspace1;

create unique index test_unique1 on test_unique (unique_id, amount, status2);

insert into test_unique (unique_id, status, amount) 
values
  (1234, 'A', 400)
--, (1234, 'B', 400)
, (1234, 'Z', 400)
, (1234, 'Z', 400);

Стандартная функция generate_unique не является детерминированной.Такие функции не разрешены в предложении generated always.Вот почему мы создаем нашу собственную функцию на основе стандартной.
Проблема с такой «поддельной» функцией могла бы быть, если бы Db2 фактически не вызывал эту функцию для каждой обновленной / вставленной строки во время операции многострочного изменения (зачем вызывать функцию deterministic несколько раз для одного и того же набора параметров, если этого достаточно, чтобы сделать это один раз и впоследствии повторно использовать результат для других затронутых строк).Но в действительности это работает - Db2 вызывает такую ​​функцию для каждой затронутой строки, что желательно в нашем случае.
Вы не можете вставить закомментированную строку в последнем утверждении.

Существующая таблица

set integrity for test_unique off;

alter table test_unique add 
status2 varchar(13) for bit data not null 
generated always as (case when status in ('A', 'B') then '' else generate_unique_det() end);

set integrity for test_unique immediate checked force generated;

-- If you need to save the rows violated future unique index
create table test_unique_exc like test_unique in userspace1;

-- If you don't need to save the the rows violated future unique index,  
-- then just run the inner DELETE statement only,
-- which just removes these rows.
-- The whole statement inserts the deleted rows into the "exception table".
with d as (
  select unique_id, status, amount, status2
  from old table (
    delete from (select t.*, rownumber() over (partition by unique_id, amount, status2) rn_ from test_unique t) where rn_>1
  )
)
select count(1)
from new table (
  insert into test_unique_exc select * from d
);

create unique index test_unique1 on test_unique (unique_id, amount, status2);
...