Я думаю, что это будет немного эзотерично, но я хотел бы добавить это на тот случай, если кто-нибудь попробовал что-то подобное или кто-то уже пытался и нашел это невозможным.
У нас есть таблица, которая требует ограничения уникальности для определенного набора столбцов, но она также имеет индикатор «мягкого удаления». Записи, помеченные как «удаленные», не должны включаться в проверку уникальности.
Все хорошо, я мог бы легко решить эту проблему с помощью уникального индекса на основе функций. Однако, что усложняет дело, так это то, что если мы собираемся реализовать это ограничение в базе данных, оно должно быть отложенным, из-за того, как работает Hibernate. Если это невозможно, мы должны будем опустить ограничение, и я бы предпочел этого не делать, если это вообще возможно.
Например:
CREATE TABLE jkemp_test
( id NUMBER NOT NULL
, deleted_ind CHAR(1) DEFAULT 'N' NOT NULL);
CREATE UNIQUE INDEX jkemp_test_funique
ON jkemp_test
(CASE WHEN deleted_ind = 'N' THEN id END);
-- make this use the function-based index, maybe?
ALTER TABLE jkemp_test
ADD CONSTRAINT jkemp_test_unique
UNIQUE (id)
DEFERRABLE INITIALLY DEFERRED;
INSERT INTO jkemp_test VALUES (1,'N');
INSERT INTO jkemp_test VALUES (2,'N');
COMMIT;
UPDATE jkemp_test SET deleted_ind='Y' WHERE id=1;
COMMIT;
-- depending on whether the constraint is deferred or not, either
-- the insert or the commit will fail "unique constraint violated"
INSERT INTO jkemp_test VALUES (1,'N');
COMMIT;
Беспроигрышный сценарий будет для последнего коммита, который будет успешным, но все же позволит отложить ограничение. (Мне известно, что наличие уникального индекса означает, что ограничение в настоящее время не отложено.)
Наша единственная возможность на данный момент - реализовать ограничение с помощью приложения, которое не будет таким надежным. Кроме того, мы не хотим слишком сильно изменять модель данных (например, мы можем переместить удаленные строки в другую таблицу, например, JKEMP_TEST_DELETED
, но это может привести к слишком большим сложностям в приложении).
Это в Oracle 11.2.0.1.0.