Уникальное ограничение на один столбец с исключением строки с такими же значениями в другом - PullRequest
3 голосов
/ 16 февраля 2012

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

id | header_id | value
 1 |         1 | a
 2 |         1 | a
 3 |         2 | a

Таким образом, строки 1 и 2 указывают на один и тот же объект, и уникальный ключ должен их принимать, но строка 3 имеет другой header_id (указывающий на другой объект) и, поскольку он имеет тот же value, что и объект 1, должен нарушать уникальное ограничение и выдавать ошибку.

Изменить 16.2: 1327:
Я использую базовую структуру, которая генерирует столбцы для обработки истории, поэтому я не могу нормализовать таблицу. В моем классе много столбцов, но в этом примере я рассматриваю только столбец value.

Ответы [ 3 ]

3 голосов
/ 16 февраля 2012

Вы можете сделать это, если можете немного изменить структуру таблицы:

your_table
id   header_value
1    1
2    1
3    2

header_value
id   header_id value
1    1         a
2    2         a

Добавить ограничение внешнего ключа от your_table.header_value до header_value.id.

Теперь вы можете добавить уникальное ограничение на header_value.value.

2 голосов
/ 17 февраля 2012

Через некоторое время я что-то нашел.Использование ограничения CHECK с функцией для определения наличия (невозможно использовать SELECT в операторе CHECK, но можно использовать функцию с желаемым выбором)

CREATE OR REPLACE FUNCTION is_value_free(_header_id integer, _value varchar) RETURNS BOOLEAN AS 
$$
  BEGIN
    RETURN NOT EXISTS (SELECT header_id,value FROM myschema.mytalbe WHERE value LIKE _value AND header_id != _header_id LIMIT 1);
  END;
$$ LANGUAGE plpgsql;

ALTER TABLE mytable ADD CONSTRAINT uniq_value CHECK (is_value_free(header_id,value))
2 голосов
/ 16 февраля 2012

Вы можете использовать триггер для имитации уникального ограничения с вашими желаемыми свойствами.Что-то вроде этого поможет:

create or replace function sort_of_unique() returns trigger as $$
declare
    got_one boolean;
begin
    select exists(
        select 1
        from your_table
        where header_id != new.header_id
          and value      = new.value
    ) into got_one;
    if got_one then
        raise exception 'Uniqueness violation in your_table';
    end if;
    return new;
end;
$$ language plpgsql;

create trigger sort_of_unique_trigger
before insert or update on your_table
for each row execute procedure sort_of_unique();

Тогда вы получите такие вещи:

=> insert into your_table (id, header_id, value) values (1, 1, 'a');
=> insert into your_table (id, header_id, value) values (2, 1, 'a');
=> insert into your_table (id, header_id, value) values (3, 2, 'a');
ERROR:  Uniqueness violation in your_table
=> insert into your_table (id, header_id, value) values (3, 2, 'b');
=> update your_table set value = 'a' where id = 3;
ERROR:  Uniqueness violation in your_table

Вы можете создать частичные уникальные индексы , прикрепивпредложение WHERE для индекса.Это позволяет вам применить ограничение уникальности к фрагментам таблицы;однако я не могу придумать, как в предложении WHERE указать «антислайс», поэтому я не вижу способа заставить эту работу работать с частичным индексом.Хотя я мог упустить что-то очевидное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...