Не может удалить несуществующее ограничение и не может создать его

16

При тестировании некоторых сценариев миграции с копией производственных данных (сценарии хорошо работают с данными разработки) я обнаружил любопытную ситуацию. Ограничение изменилось, поэтому я выполняю команды DROP + ADD:

ALTER TABLE A_DUP_CALLE
DROP CONSTRAINT A_DUP_CALLE_UK1;

ALTER TABLE A_DUP_CALLE
ADD CONSTRAINT A_DUP_CALLE_UK1 UNIQUE (
    CONTROL_ID,
    CALLE_AYTO_DUPL
)
ENABLE;

Команда DROP работала нормально, но команда ADD не удалась. Теперь я в замкнутом круге. Я не могу удалить ограничение, потому что оно не существует (первоначальное удаление сработало как ожидалось):

ORA-02443: Невозможно удалить ограничение - несуществующее ограничение

И я не могу создать его, потому что имя уже существует:

ORA-00955: имя уже используется существующим объектом

Я A_DUP_CALLE_UK1ввожу в поле поиска разработчика SQL и ... вот оно! Владелец, имя таблицы, Tablescape ... все совпадает: это не другой объект с тем же именем, что это мое первоначальное ограничение. Таблица отображается в деталях ограничения, но ограничение не отображается в деталях таблицы.

Мои вопросы:

  • Чем это объясняется?
  • Как я могу гарантировать, что этого не произойдет, когда я произвожу реальное обновление на живом сервере?

(Сервер 10g XE, у меня недостаточно репутации для создания тега.)

Альваро Гонсалес
источник
Может быть, он был создан как объект другого типа, а не как ограничение? Может быть, уникальный индекс ..
Мариан
Может ли начальное создание быть выполнено с кавычками вокруг имени таблицы? Это сделало бы имя чувствительным к регистру. Если это так, вы можете оставить с кавычками и тот же случай.
Адам Батлер

Ответы:

13

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

create table t( k1 integer, k2 integer, 
                constraint u1 unique(k1,k2) using index(create unique index u1 on t(k1,k2)),
                constraint u2 unique(k2,k1) using index u1);

select count(*) from user_indexes where index_name='U1';

COUNT(*)               
---------------------- 
1  

alter table t drop constraint u1;

select count(*) from user_indexes where index_name='U1';

COUNT(*)               
---------------------- 
1  

Обычно, когда вы добавляете уникальное ограничение, создается уникальный индекс с тем же именем, но индекс и ограничение - это не одно и то же. Посмотрите, all_indexesесть ли индекс с именем, A_DUP_CALLE_UK1и попытайтесь выяснить, используется ли он чем-то другим, прежде чем вы его уроните!

Джек говорит, попробуйте topanswers.xyz
источник
Это была проблема. Файл дампа, созданный expкомандой, содержит CREATE UNIQUE INDEX "A_DUP_CALLE_UK1" ...оператор, которого нет в исходном наборе скриптов.
Альваро Гонсалес
6

Кажется очень странным

Вы можете запустить:

 SELECT *
 FROM user_objects
 WHERE object_name = 'A_DUP_CALLE_UK1'

проверить, жалуется ли на какой объект Oracle. Затем вы можете запустить appROAIRATE DROP для этого.

Единственное, о чем я могу подумать, это полностью удалить таблицу, DROP TABLE A_DUP_CALLE CASCADE CONSTRAINTSчтобы избавиться от всего, что принадлежит этой таблице, а затем заново создать ее.

Если таблица содержит ценные данные, вы можете сделать их резервную копию раньше:

CREATE TABLE old_data
AS
SELECT *
FROM A_DUP_CALLE;

После того, как вы воссоздали таблицу, вы можете сделать

INSERT INTO A_DUP_CALLE (col1, col2, col3) 
SELECT col1, col2, col3
FROM old_data

восстановить данные.

a_horse_with_no_name
источник
4

У меня была такая же проблема всего несколько минут назад ... и я нашел объяснение.

Создав Первичный Ключ, Oracle создает два объекта: ограничение и индекс, который управляет частью «УНИКАЛЬНАЯ».

При удалении ограничения индекс остается там, используя то же имя индекса, поэтому, если вы просто выполните

alter table t drop constraint u1;

Вы будете отбрасывать только ограничение. Чтобы удалить индекс, вам нужно выполнить

drop index u1;

Это должно сделать работу. Кроме того, вы можете выполнить обе эти команды одновременно с командой

alter table t drop constraint u1 including indexes;
Кристиан Менезес А
источник
какой дб? в том числе не работает в оракуле
Дерик
1

Ограничение первичного ключа идет с индексом. Вы отбрасываете ограничение, но не индекс. Проверьте:

select * from ALL_OBJECTS where OBJECT_NAME = 'PK_TBL_CONSTR';

и вы видите OBJECT_TYPEэто INDEX.

Так что сделайте оба:

alter table TBL drop constraint PK_TBL_CONSTR;
drop index PK_TBL_CONSTR;
gavenkoa
источник
1

Сделай это

ALTER TABLE A_DUP_CALLE
DROP CONSTRAINT "A_DUP_CALLE_UK1";

Это будет работать.

ОБРАЗ: введите описание изображения здесь

Сэчин
источник
Нет, это не сработает. Ваше утверждение точно такое же, как первое утверждение в вопросе:ALTER TABLE A_DUP_CALLE DROP CONSTRAINT A_DUP_CALLE_UK1;
a_horse_with_no_name
Это работало на самом деле. У меня была такая же проблема с сегодняшнего дня, и в поисках решения я наткнулся на это. Иногда CONSTRAINTS могли создаваться с учетом регистра, и в этом случае вам нужно будет указывать имя ограничения в двойных кавычках при его удалении.
Сачин
И это сработало для меня. Я не назвал ограничения явно, поэтому система дала ему свое собственное сгенерированное имя, Relationship142а другому NOT NULLОграничению было дано имя SYS_C0015910. Так что SYS_C0015910был успешно удален с помощью простого запроса ALTER, но Relationship142нужны ДВОЙНЫЕ ЦИТАТЫ
Sachin
1
Вы создали ограничения, используя двойные кавычки, например: alter table ... add constraint "Relationship143" ... "Relationship143"действительно другое имя, чем RELATIONSHIP143. Но "RELATIONSHIP143"и RELATIONSHIP143являются идентичными
a_horse_with_no_name
2
Oracle (база данных) никогда не создаст имя, как само "Relationship143"по себе. Вероятно, это был один из ваших инструментов. Во всяком случае: как бы то ни было, ваш ответ просто неверен в контексте исходного вопроса.
a_horse_with_no_name