2017-02-02 6 views
2

Цель: Обмен первичными ключами двух записей без столкновения с ORA-00001: нарушено уникальное ограничение. Решение, которое «работает» (далее), является просто глупым взломом. Есть ли функция/метод, чтобы отложить принудительное принуждение до совершения транзакции?
Насколько мотивации - унаследованное приложение, которое использует эти данные имеют недостаток дизайна и опирается на порядке идентификаторов и значениях - запрос должен поменять значения PK следующим образом:Лучший способ обмена двумя значениями первичного ключа и обход ORA-00001: уникальное ограничение нарушено?

BEFORE: 
388 English 
389 French 

AFTER: 
389 English 
388 French 

Что Безразлично «т Работа:

BEGIN 
    UPDATE SPOKEN_LANGUAGES 
     SET id = 388 
    WHERE id = 389; 

    UPDATE SPOKEN_LANGUAGES 
     SET id = 389 
    WHERE id = 388; 
END; 

Hack/решение, что 'работает'

DECLARE 
    V_MAGIC_NUMBER NUMBER := 9999999; 
BEGIN 
    UPDATE SPOKEN_LANGUAGES 
    SET id = 388 + V_MAGIC_NUMBER 
    WHERE id = 389; 

    UPDATE SPOKEN_LANGUAGES 
    SET id = 389 + V_MAGIC_NUMBER 
    WHERE id = 388; 

    UPDATE SPOKEN_LANGUAGES 
    SET id = id - V_MAGIC_NUMBER 
    WHERE id = 389 + V_MAGIC_NUMBER; 

    UPDATE SPOKEN_LANGUAGES 
    SET id = id - V_MAGIC_NUMBER 
    WHERE id = 388 + V_MAGIC_NUMBER; 

END; 

Таблица Определение:

CREATE TABLE SPOKEN_LANGUAGES 
(
    ID    NUMBER(10)      NOT NULL, 
    LANGUAGE_NAME VARCHAR2(40 BYTE)    NOT NULL 
) 

PK/UNIQUE INDEX:

CREATE UNIQUE INDEX SL_PK ON SPOKEN_LANGUAGES (ID) 
+0

насчет просто сбросив индекс, выполняющий обновление, а затем перестраивающий индекс? – BobC

+0

@BobC Это было определенно предложение, которое появилось - казалось, разработчики приложений неохотно приняли эту стратегию. Я также предложил реорганизовать схему и/или приложение для поддержки того, что они пытаются выполнить; а не пытаться «исправить», как есть. –

+0

Это одноразовое решение или какое-то регулярное обслуживание? Если это был один, я не вижу большой проблемы с откатом и перестройкой индекса. Сказав это, @a_hourse придумал правильный ответ. Но, как вы говорите, и приложение полагается на этот заказ, скорее всего, столкнется с другими проблемами позже ... – BobC

ответ

7

Вы должны сделать это в одном операторе:

UPDATE SPOKEN_LANGUAGES 
    SET id = case when id = 388 then 389 else 388 end 
WHERE id in (388,389);