Oracle: Когда проверяются ограничения? - PullRequest
2 голосов
/ 31 января 2020

В моем понимании ограничения должны обычно проверяться в конце транзакции.

Итак, в простом примере, где у нас есть одна таблица A с единственным столбцом P, который является ее основным ключом и таблицей B с первичным ключом P и внешним ключом F для A.P, должно работать следующее (для пустых таблиц):

begin

    insert into B (P, F)
    values (1, 1);
    insert into A (P)
    values (1);

    commit;
end;

Однако Oracle выдает ошибку (на немецком языке):

[23000][2291] ORA-02291: Integritäts-Constraint (DATABASE.AB_constraint) verletzt - übergeordneter Schlüssel nicht gefunden
ORA-06512: in Zeile 3
Position: 0

, что означает Нарушено ограничение целостности - указанный ключ не найден . Если я переверну порядок

begin

    insert into A (P)
    values (1);
    insert into B (P, F)
    values (1, 1);

    commit;
end;

, он будет работать нормально. Не подтверждены ли ограничения в конце транзакции в Oracle? И если да, то есть ли способ обеспечить такое поведение?

В Oracle документах указано, что (в соответствии со свойствами A C ID)

[t] транзакция переводит базу данных из одного согласованного состояния в другое согласованное состояние.

Таким образом, можно ожидать, что промежуточные состояния не обязательно должны быть последовательным. Это, безусловно, относится к примеру Oracle: деньги переводятся с одного счета на другой, в то время как общая сумма денег не совпадает (не соответствует), так как деньги были сняты с одного счета, но еще не добавлено к другому. Так почему же это не похоже на ограничения внешнего ключа?

Ответы [ 3 ]

5 голосов
/ 31 января 2020

И если да, то есть ли способ заставить это поведение

Да, так оно и есть. Это называется отложенным ограничением.

Если ограничение отложено, оно проверяется в конце транзакции, а не при выполнении инструкции.

alter table some_table
   add constraint fk_something 
   foreign key (some_column) references other_table(pk_column)
   deferrable initially deferred;

См. этот ответ для объяснения разница между initially deferred и initially immediate

1 голос
/ 31 января 2020

Одним из способов решения этой проблемы будет отсрочить связанное ограничение внутри блока, например:

begin
    execute immediate 'set constraint ab_constraint deferred';
    insert into B (P, F) values (1, 1);
    insert into A (P) values (1);
    execute immediate 'set constraint ab_constraint immediate';
    commit;
end;
1 голос
/ 31 января 2020

Если вы явно не определите ограничение как отложенное ограничение , ограничения проверяются при вставке строк в таблицу.

Данные фактически не видны снаружи, пока транзакция не будет зафиксирована , но целостность данных проверяется пошагово.

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