Чи є спосіб перевірити, чи не вийде DELETE через обмеження?


10

Я хотів би мати можливість передбачити, чи буде DELETE наштовхнутися на порушення обмеження, не виконуючи фактично видалення.

Які мої варіанти зробити це? Чи є простий спосіб зробити «сухий пробіг» DELETE?


Ви намагаєтеся запобігти виключенню лише для цього оператора чи ви намагаєтеся полегшити обробку помилок у більшій партії, що містить це видалення?
— Аарон Бертран

3
Чи можете ви перевірити, чи існує FK, та запустіть оператор SELECT, щоб перевірити значення?
— SQLRockstar

Аарон: Нам потрібно запустити партію декількох DELETE в окремих транзакціях. Якщо одна виходить з ладу, інші вже вчиняються. (Поганий дизайн з самого початку, я знаю, але це не моя програма, і вона не змінюється.) Найкращий на даний момент спосіб звучить, як зробити суху перевірку, щоб побачити, чи не будуть виходити ЗНО.
— Джей Салліван

Досі не впевнений, що розумію. Чи намагаєтесь ви дозволити решті видалених домогтися успіху, чи ви намагаєтесь перевірити, чи всі вони будуть успішними, або жоден з них не повинен?
— Аарон Бертран

Аарон: Вибачте, що я не дав зрозуміти, але так, я намагаюся переконатися, що всі вони досягли успіху, або жоден з них не досягне успіху.
— Джей Салліван

Відповіді:


24

Якщо ваша мета полягає в обробці всіх видалених файлів, лише якщо всі вони досягли успіху, чому б не просто використовувати TRY / CATCH:

BEGIN TRANSACTION;
BEGIN TRY
  DELETE #1;
  DELETE #2;
  DELETE #3;
  COMMIT TRANSACTION;
END TRY
BEGIN CATCH
  ROLLBACK TRANSACTION;
END CATCH

Якщо мета полягає в тому, щоб дозволити всім успішним делетам досягти успіху, навіть якщо один або декілька не вдасться, тоді ви можете використовувати індивідуальний TRY / CATCH, наприклад

BEGIN TRY
  DELETE #1;
END TRY
BEGIN CATCH
  PRINT 1;
END CATCH

BEGIN TRY
  DELETE #2;
END TRY
BEGIN CATCH
  PRINT 1;
END CATCH

6

Один із варіантів - почати транзакцію, запустити видалення, а потім завжди відкатати:

begin tran

delete Table1 where col1 = 1

-- Test whether it is there
select * from Table1 where col1 = 1

rollback tran

-- Confirm that it is still there
select * from Table1 where col1 = 1

1
І якщо видалення вдалося, запустити його знову? Що робити, якщо видалення дуже дороге? А якщо видалення не вдалося, що тоді? Ви виконали одне видалення та два вибори. Як вирішити перейти до наступного видалення чи ні?
— Аарон Бертран

1
Якщо вони є частиною вимог, то з ними слід впоратися. Ця відповідь стосується "простого" сухого пробігу ".
— GaTechThomas

Ну, вони не були, коли ви вперше подали свою відповідь, але вони були уточнені зараз.
— Аарон Бертран

4
@GaTechThomas Аарон багато сприяє, тому він іноді короткий, але я впевнений, що його намір не був агресивним. Я обговорював це в The Heap і буду вдячний за можливість зробити це з вами також.
— Джек каже, спробуйте topanswers.xyz

1
@JackDouglas Я прочитав коментарі Heap, які ви посилаєтесь і розумієте суть. Зауваження громади були розумними, за винятком тієї частини, де мене назвали клоуном за вказівку його агресії. Я не розумію, як я той, кого вважали агресивним. Я розмістив обґрунтовану відповідь на питання, як воно було поставлене на той час. Це не вимагало якості виробництва - іноді просто потрібно швидко і просто. Тож у своїй відповіді я отримую загострені запитання. Вигляд полягав у тому, що він заперечував мою відповідь, щоб його обрали. Чи слід взяти цю нитку в інше місце?
— GaTechThomas

0

Я хотів би вдосконалити рішення, надане Аароном Бертран, деяким кодом, на випадок, якщо ви хочете спробувати додати будь-який елемент таблиці, керуючи винятками, щоб ігнорувати помилки, а також зупинити помилки після процесу.

Цей обере записи із таблиці, а потім намагається видалити їх без винятку:

DECLARE @MaxErrors INT
SET @MaxErrors = 5;    // Setting 0 will stop process after the first error!

SELECT
    [Id]
    , ROW_NUMBER() OVER (ORDER BY Id ASC) AS [Index]
INTO #DeletingItems
FROM myTable

DECLARE @Current INT, @Max INT, @Id INT, @TotErrors INT
SELECT
    @Current = 1
    , @TotErrors = 0
    , @Max = MAX([Index])
FROM #DeletingTable

WHILE @Current <= @Max
BEGIN
    SELECT
        @Id = [Id]
    FROM #DeletingItems
    WHERE
        [Index] = @Index;

    BEGIN TRANSACTION;    
    BEGIN TRY    
        DELETE FROM myTable WHERE [Id] = @Id;

        COMMIT TRANSACTION;    
    END TRY    
    BEGIN CATCH    
        ROLLBACK TRANSACTION;

        SET @TotErrors = @TotErrors + 1;

        IF @TotErrors > @MaxErrors
            BREAK;
    END CATCH

    SET @Current = @Current + 1;
END

1
Чому? Як це поліпшення порівняно з прийнятою відповіддю?
— ToolmakerSteve
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.