Чи є спосіб перевірити, чи не вийде 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.