Как добавить 'ON DELETE CASCADE' в инструкцию ALTER TABLE

130

У меня есть ограничение внешнего ключа в моей таблице, я хочу добавить ON DELETE CASCADE к нему.

Я пробовал это:

изменить таблицу child_table_name
  изменить ограничение fk_name
  внешний ключ (child_column_name)
  ссылается parent_table_name (parent_column_name) на каскад удаления;

Не работает

РЕДАКТИРОВАТЬ:
Внешний ключ уже существует, в столбце внешнего ключа есть данные.

Сообщение об ошибке, которое я получаю после выполнения инструкции:

ORA-02275: такое ссылочное ограничение уже существует в таблице
Ула Крукар
источник
В чем проблема? Заявление отклонено, удаление не происходит ..
Торстен

Ответы:

162

Вы не можете добавить ON DELETE CASCADEк уже существующим ограничениям. Вы должны будете dropи повторно createограничить. В документации показывает , что MODIFY CONSTRAINTположение может изменить только состояние ограничения (то есть: ENABLED/DISABLED...).

Винсент Малграт
источник
86

Сначала dropвведите ваш внешний ключ и попробуйте команду, указанную выше, add constraintвместо modify constraint. Теперь это команда:

ALTER TABLE child_table_name 
  ADD CONSTRAINT fk_name 
  FOREIGN KEY (child_column_name) 
  REFERENCES parent_table_name(parent_column_name) 
  ON DELETE CASCADE;
Прадип
источник
24
Он дает нам весь код, который является очевидным преимуществом для людей, которые не имеют ничего общего с postgres
Маттис Кохли
1
@WiiMaxx Основатель ревнивый парень. lol. Этот ответ важнее, чем первый, так как он также содержит код ..
Я самый глупый человек
11

Этот PL * SQL запишет в DBMS_OUTPUT скрипт, который удалит каждое ограничение, не имеющее каскад удаления, и заново создаст его с помощью каскада удаления.

ПРИМЕЧАНИЕ: запуск выходных данных этого сценария выполняется на свой страх и риск. Лучше всего прочитать полученный скрипт и отредактировать его перед выполнением.

DECLARE
      CURSOR consCols (theCons VARCHAR2, theOwner VARCHAR2) IS
        select * from user_cons_columns
            where constraint_name = theCons and owner = theOwner
            order by position;
      firstCol BOOLEAN := TRUE;
    begin
        -- For each constraint
        FOR cons IN (select * from user_constraints
            where delete_rule = 'NO ACTION'
            and constraint_name not like '%MODIFIED_BY_FK'  -- these constraints we do not want delete cascade
            and constraint_name not like '%CREATED_BY_FK'
            order by table_name)
        LOOP
            -- Drop the constraint
            DBMS_OUTPUT.PUT_LINE('ALTER TABLE ' || cons.OWNER || '.' || cons.TABLE_NAME || ' DROP CONSTRAINT ' || cons.CONSTRAINT_NAME || ';');
            -- Re-create the constraint
            DBMS_OUTPUT.PUT('ALTER TABLE ' || cons.OWNER || '.' || cons.TABLE_NAME || ' ADD CONSTRAINT ' || cons.CONSTRAINT_NAME 
                                        || ' FOREIGN KEY (');
            firstCol := TRUE;
            -- For each referencing column
            FOR consCol IN consCols(cons.CONSTRAINT_NAME, cons.OWNER)
            LOOP
                IF(firstCol) THEN
                    firstCol := FALSE;
                ELSE
                    DBMS_OUTPUT.PUT(',');
                END IF;
                DBMS_OUTPUT.PUT(consCol.COLUMN_NAME);
            END LOOP;                                    

            DBMS_OUTPUT.PUT(') REFERENCES ');

            firstCol := TRUE;
            -- For each referenced column
            FOR consCol IN consCols(cons.R_CONSTRAINT_NAME, cons.R_OWNER)
            LOOP
                IF(firstCol) THEN
                    DBMS_OUTPUT.PUT(consCol.OWNER);
                    DBMS_OUTPUT.PUT('.');
                    DBMS_OUTPUT.PUT(consCol.TABLE_NAME);        -- This seems a bit of a kluge.
                    DBMS_OUTPUT.PUT(' (');
                    firstCol := FALSE;
                ELSE
                    DBMS_OUTPUT.PUT(',');
                END IF;
                DBMS_OUTPUT.PUT(consCol.COLUMN_NAME);
            END LOOP;                                    

            DBMS_OUTPUT.PUT_LINE(')  ON DELETE CASCADE  ENABLE VALIDATE;');
        END LOOP;
    end;
shindigo
источник
11

Как объяснялось ранее:

ALTER TABLE TABLEName
drop CONSTRAINT FK_CONSTRAINTNAME;

ALTER TABLE TABLENAME
ADD CONSTRAINT FK_CONSTRAINTNAME
    FOREIGN KEY (FId)
    REFERENCES OTHERTABLE
        (Id)
    ON DELETE CASCADE ON UPDATE NO ACTION;

Как вы видите, эти команды должны быть разделены, сначала отбрасывая, затем добавляя.

Давид Сильва-Баррера
источник
Это недопустимо для Oracle
a_horse_with_no_name
Только что протестировано в SqlServer, но, возможно, у вас есть шанс goс точкой с запятой, как в postgres и самом SqlServer. Но оставшиеся основные коды соответствуют стандарту sql. Тест с
Дэвид Сильва-Баррера
[Или ]недействительны в стандарте SQL (и Oracle). Oracle также не поддерживает on updateпредложение для внешнего ключа.
a_horse_with_no_name 03
Вы правы, [ ]специфичны для SqlServer. Я почищу еще. Насчет on updateничего не могу сказать.
Дэвид Сильва-Баррера
11

Ответ для ПОЛЬЗОВАТЕЛЕЙ MYSQL:

ALTER TABLE ChildTableName 
DROP FOREIGN KEY `fk_table`;
ALTER TABLE ChildTableName 
ADD CONSTRAINT `fk_t1_t2_tt`
  FOREIGN KEY (`parentTable`)
  REFERENCES parentTable (`columnName`)
  ON DELETE CASCADE
  ON UPDATE CASCADE;
Bhavani
источник
Добро пожаловать в StackOverflow. Узнайте о коде форматирования на stackoverflow.com/editing-help . Я отредактировал код для вас, чтобы он был более читабельным.
Adrian W
3

Для тех, кто использует MySQL:

Если вы перейдете на свою PHPMYADMINвеб-страницу и перейдете к таблице с внешним ключом, который вы хотите обновить, все, что вам нужно сделать, это щелкнуть значок, Relational view расположенный на Structureвкладке, и изменить параметр On deleteменю выбора на Cascade.

Изображение показано ниже:

введите описание изображения здесь

James111
источник
OP относится к 2009 году, его вопрос об Oracle помечен, а PHPMYADMIN - это сторонний программный компонент для MySQL.
vegatripy
7
Абсолютная правда. Но я погуглил по этому вопросу, желая узнать, как это сделать в MySQL, и Google привел меня сюда. Да, вопрос помечен тегом Oracle, поэтому этот ответ неверен ... но он будет полезен читателям вроде меня, которые наткнулись на этот ответ. Так же добавить значение этой страницы, даже если она не является Oracle специфичны. Итак, спасибо, James111!
Майк Гледхилл,
3

Вот удобное решение! Я использую SQL Server 2008 R2.

Если вы хотите изменить ограничение FK, добавив ON DELETE / UPDATE CASCADE, выполните следующие действия:

НОМЕР 1:

Щелкните ограничение правой кнопкой мыши и выберите " Изменить".

введите описание изображения здесь

НОМЕР 2:

Выберите ограничение слева (если их больше одного). Затем с правой стороны сверните пункт « ВСТАВИТЬ И ОБНОВИТЬ спецификацию » и укажите действия в строке «Удалить правило» или «Обновить правило» в соответствии с вашими потребностями. После этого закройте диалоговое окно.

введите описание изображения здесь

НОМЕР 3:

Последний шаг - сохранить эти модификации (конечно же!)

введите описание изображения здесь

PS: Это избавило меня от кучи работы, так как я хочу изменить первичный ключ, указанный в другой таблице.

Серж Кишико
источник
Отлично, именно то, что мне нужно!
Wildview
1

Если вы хотите изменить внешний ключ, не отбрасывая его, вы можете сделать:

ALTER TABLE child_table_name  WITH CHECK ADD FOREIGN KEY(child_column_name)
REFERENCES parent_table_name (parent_column_name) ON DELETE CASCADE
RedPelle
источник
0
ALTER TABLE `tbl_celebrity_rows` ADD CONSTRAINT `tbl_celebrity_rows_ibfk_1` FOREIGN KEY (`celebrity_id`) 
REFERENCES `tbl_celebrities`(`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
Хасан Али Шахзад
источник