Несколько операторов SQL UPDATE ИЛИ один с CASE в нем? - PullRequest
1 голос
/ 28 октября 2009

Я построил триггер, в котором я пытаюсь поддерживать приоритеты в порядке и не допускать дублирования значений приоритетов. Есть некоторые вещи, которые следует учитывать.

  1. Пользователь может свободно сформировать приоритет в.
  2. Ничто не мешает им выбрать тот же приоритет, что и у другого предмета.
  3. Когда значение вводится равным другому значению, элемент с новым приоритетом должен иметь приоритет в приоритете, а другой должен увеличиваться.

    CREATE TRIGGER dbo.trg_Priority
        ON  dbo.Stories
        AFTER INSERT,UPDATE,DELETE
    AS
    BEGIN
        SET NOCOUNT ON;
    
    -- Insert statements for trigger here
    DECLARE @StoryId INT
    DECLARE @OldLocation INT
    DECLARE @NewLocation INT
    
    SELECT @NewLocation = Priority, @StoryId = StoryId FROM INSERTED
    SELECT @OldLocation = Priority FROM DELETED
    
    IF @NewLocation = @OldLocation
        RETURN;
    
    IF @NewLocation IS NULL
    BEGIN
        UPDATE Stories SET
            Priority = Priority - 1
        WHERE Priority > @OldLocation
    END
    
    IF @NewLocation > @OldLocation
    BEGIN
        UPDATE Stories SET
            Priority = Priority + 1
        WHERE Priority >= @NewLocation
        AND StoryId <> @StoryId
    END
    
    IF @NewLocation < @OldLocation
    BEGIN
        UPDATE Stories SET
            Priority = Priority + 1
        WHERE Priority >= @NewLocation
        AND Priority < @OldLocation
        AND StoryId <> @StoryId
    END
    END
    GO
    

Я не много тестировал этот триггер, поэтому, если есть проблемы, не стесняйтесь говорить. В конечном итоге я хочу знать, стоит ли мне пытаться преобразовать это в одно обновление с помощью оператора case. (Если это вообще возможно.)

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

Ответы [ 5 ]

1 голос
/ 28 октября 2009

Вам нужно переписать триггер. Предполагается, что только одна запись будет когда-либо вставлена ​​/ обновлена ​​или удалена одновременно. Вы не можете написать триггер с таким допущением, триггеры работают с пакетами данных, а не по строкам. Вам необходимо присоединиться к вставленным и удаленным в ваших обновлениях. Так что да, я бы попытался написать обновление с указанием случая.

А почему это удаленный триггер? Не будет места для обновления, если оно было удалено.

1 голос
/ 28 октября 2009

Убедитесь, что вы выполняли откат и выдавали ошибку (уровень серьезности 16), если @@ ROWCOUNT> 1. Ваш триггер в том виде, в котором он написан в настоящий момент, может привести к значительному повреждению данных пользователя, который попытался вставить, обновить или удалить несколько строк одновременно.

Тем не менее, IronGoofy прав: вы будете касаться стола только один раз, независимо от условий. Таким образом, разбиение его на несколько операторов делает код более легким для чтения / более легким в обслуживании.

Если вы хотите разрешить одновременное обновление нескольких строк, вам необходимо изменить это. Логика может быть пугающей!

0 голосов
/ 29 октября 2009

Я решил отказаться от этой идеи и оставляю это на усмотрение пользовательского интерфейса для обновления приоритета. Я перестал разрешать ввод данных пользователем.

Я не уверен, какой из этих ответов является правильным, поэтому я собираюсь отметить это как правильный и позволить сообществу выяснить это методом проб и ошибок. :)

0 голосов
/ 28 октября 2009

Не должно быть никаких (заметных) различий в производительности, в любом случае вы будете выдавать один оператор обновления для базы данных.

0 голосов
/ 28 октября 2009

Как насчет этого:

 UPDATE Stories SET Priority = CASE 
     WHEN Priority > @OldLocation THEN Priority-1
     WHEN Priority >= @NewLocation AND StoryID <> @StoryID THEN Priority+1
     WHEN Priority >= @NewLocation AND @Priority < @OldLocation And StoryID <> StoryID THEN Priority +1
END
GO
...