多个 SQL UPDATE 语句还是单个包含 CASE 的语句?

发布于 2024-08-08 18:49:52 字数 948 浏览 3 评论 0原文

我构建了一个触发器,试图保持优先级顺序并且不允许重复的优先级值。有一些事情需要考虑。

  1. 用户可以自由设置优先级。
  2. 没有什么可以阻止他们选择与另一个项目相同的优先级。
  3. 当输入的值等于另一个值时,新确定优先级的项目应优先考虑优先级,而另一个值应递增。

    创建触发器 dbo.trg_Priority
        ON dbo.故事
        插入、更新、删除后
    作为
    开始
        设置不计数;
    
    -- 在此插入触发器语句
    声明@StoryId INT
    声明@OldLocation INT
    声明@NewLocation INT
    
    从插入中选择 @NewLocation = 优先级,@StoryId = StoryId
    选择@OldLocation = 优先删除
    
    IF @NewLocation = @OldLocation
        返回;
    
    IF @NewLocation 为 NULL
    开始
        更新故事集
            优先级 = 优先级 - 1
        其中优先级> @旧位置
    结尾
    
    如果@NewLocation> @旧位置
    开始
        更新故事集
            优先级 = 优先级 + 1
        WHERE 优先级 >= @NewLocation
        和 StoryId <> @StoryId
    结尾
    
    如果@NewLocation < @旧位置
    开始
        更新故事集
            优先级 = 优先级 + 1
        WHERE 优先级 >= @NewLocation
        且优先级< @旧位置
        和 StoryId <> @StoryId
    结尾
    结尾
    去
    

我还没有对这个触发器进行过多次测试,所以如果有什么值得关注的地方,请随意说出来。我最终想知道的是我是否应该尝试将其转换为带有 case 语句的单个更新。 (如果这甚至可能的话。)

如果将其设为单个 UPDATE 语句会更高效,我真的可以用手来解决它!

I've built a trigger where I am trying to keep priorities in order and not allow duplicate priority values. There are some things to consider.

  1. The user can free form the priority in.
  2. There is nothing blocking them from picking the same priority as another item.
  3. When a value is entered equal to another value the newly prioritized item should take precedence in the priority and the other should be incremented.

    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
    

I haven't tested this trigger a whole lot so if there's areas of concern feel free to speak up. What I ultimately want to know is if I should try and convert this to a single update with a case statement. (If that's even possible.)

If it would be more performant to make this a single UPDATE statement I could really use a hand figuring it out!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

木森分化 2024-08-15 18:49:52

您需要重写触发器。它假设一次只会插入/更新或删除一条记录。您不能用这种假设编写触发器,触发器对批量数据进行操作,而不是逐行操作。您需要加入才能在更新中插入和删除。所以是的,我会尝试用案例陈述来编写更新。

为什么这是一个已删除的触发器?如果删除,则不会有记录可更新。

You need to rewrite the trigger. It assumes only one records will ever be inserted/updated or delted at atime. You cannot write a trigger with that assumption, triggers operate on batches of data not row-byrow. You need to join to inserted and deleted in your updates. So yes, I would try to write the update with a case statement.

And why is this a deleted trigger? There won;t be arecord to update if it was deleted.

贵在坚持 2024-08-15 18:49:52

确保在 @@ROWCOUNT > 时回滚并引发错误(严重性 16)。 1. 当前编写的触发器会导致用户尝试一次插入、更新或删除多行,从而导致大量数据损坏。

也就是说,IronGoofy 是对的:无论情况如何,您只会接触桌子一次。因此,将其分解为多个语句使代码更易于阅读/更易于维护。

如果您允许一次更新多行,则需要更改此设置。逻辑可能令人畏惧!

Make sure you rollback and raise an error (severity 16) if @@ROWCOUNT > 1. Your trigger as currently written would cause a great deal of data corruption of the user attempted to insert, update or delete multiple rows at once.

That said, IronGoofy is right: you will only be touching the table once, regardless if the condition. So, breaking it out into multiple statements makes the code easier to read/more maintainable.

If you were to allow multiple rows to be updated at once, you would need to change this. The logic may be daunting!

始终不够爱げ你 2024-08-15 18:49:52

这个怎么样:

 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

How about this:

 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
花开半夏魅人心 2024-08-15 18:49:52

不应该有任何(明显的)性能差异,在任何情况下您都会向数据库发出单个更新语句。

There shouldn't be any (noticeable) performance difference, in any case you will be issuing a single update statement to the database.

叹梦 2024-08-15 18:49:52

我决定放弃这个想法,并让 UI 来更新优先级。我已停止允许用户输入。

我不确定这些答案中哪个是正确的,因此我将其标记为正确,并让社区通过反复试验找出答案。 :)

I decided to ditch this idea, and I leave it up to the UI to update the priority. I've stopped allowing user input.

I'm not sure which of these answers are correct, so I'm going to mark this as correct and let the community figure it out with trial and error. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文