T-SQL 条件更新 (v2)
我有一个表:
Message (MessageID int, Subject nvarchar(100), Body nvarchar(max))
在 UI 上更新消息后,我调用存储过程来更新该表。在某些情况下,用户可能仅更新主题,在其他情况下仅更新正文。我希望这个存储过程只更新已更改的内容,因此我还传递了显示主题或正文是否已更新的标志:
create proc UpdateMessage(
@MessageID int,
@Subject nvarchar(100),
@Body nvarchar(max),
@SubjectChanged bit,
@BodyChanged bit)
现在我很困惑如何构建条件 UPDATE
语句。我的第一个想法是使用 CASE
:
Update [Message]
SET
CASE WHEN @SubjectChanged = 1 THEN [Subject] = @Subject ELSE 1=1 END,
CASE WHEN @BodyChanged = 1 THEN Body = @Body ELSE 1=1 END,
WHERE MessageID = @MessageID
...但这似乎不是正确的语法,因为 CASE
必须位于分配的右侧。
我有什么想法可以做到这一点吗? (请记住,实际上有 6 个参数可以更新,而不是两个)
I have a table:
Message (MessageID int, Subject nvarchar(100), Body nvarchar(max))
After a message is being updated on UI, I call a stored proc to update that table. In some cases user might update just subject, in other cases just body. I want this stored proc to only update what has changed, so I'm also passing flags showing whether subject or body has been updated:
create proc UpdateMessage(
@MessageID int,
@Subject nvarchar(100),
@Body nvarchar(max),
@SubjectChanged bit,
@BodyChanged bit)
And now i'm confused how to build the conditional UPDATE
statement. My first thought was to use CASE
:
Update [Message]
SET
CASE WHEN @SubjectChanged = 1 THEN [Subject] = @Subject ELSE 1=1 END,
CASE WHEN @BodyChanged = 1 THEN Body = @Body ELSE 1=1 END,
WHERE MessageID = @MessageID
... but that doesn't seem to be a correct syntax as CASE
has to be the right side of an assigment.
Any ideas how I could do that? (And keep in mind that in reality there are 6 parameters that can be updated, not two)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
创建语句所需的语法是:
如果在所有建议之后您仍然想坚持它。
注意,如果省略 CASE 语句的 ELSE [Subject] 部分,则不会忽略 UPDATE,而是将该字段设置为 NULL。
The syntax required to create your statement is:
if you still want to stick to it after all the suggestions.
N.b. if you leave out the ELSE [Subject] part of the CASE statements, instead of ignoring the UPDATE it sets the field to NULL.
到目前为止,最好的选择是使用显式 IF 语句:
从性能的角度来看,没有什么比这更好的了。因为 SQL 在查询编译期间可以看到您只更新 Body 或主题或两者,所以它可以生成适当的计划,例如甚至不必费心打开(用于更新)主题上的非聚集索引(如果您有当然是一)当你只更新 Body 时。
从代码质量的角度来看,这是一场灾难,是维护的噩梦。但承认问题就80%解决了问题:)。例如,您可以使用代码生成技术来维护此类问题过程。
另一种可行的方法实际上是使用动态 SQL,在过程中构造 UPDATE 并使用 sp_executesql。与所有动态 SQL 一样,它也有自己的一系列问题。有一些关于动态 SQL 问题的资源,以及解决方法和解决方案,请参阅动态 SQL 的诅咒和祝福。
Your best bet, by far, is to use explicit IF statements:
From a performance point of view, nothing beats this. Because SQL can see during query compilation that you only update Body, or Subject, or both, it can generate the appropriate plan, for instance not even bothering to open (for update) the non-clustered index you have on Subject (if you have one, of course) when you only update Body.
From a code code quality point of view, this is disaster, a nightmare to maintain. But acknowledging the problem is 80% solving the problem :) . You can use code generation techniques for instance to maintain such problem procedures.
Another viable approach is actually to use dynamic SQL, construct the UPDATE in the procedure and use sp_executesql. It has its own set of problems, as all dynamic SQL has. There are resources about dynamic SQL problems, and there are workarounds and solutions, see The Curse and Blessings of Dynamic SQL.
这应该就是您所需要的。但是,如果您确实无法在字段未更改的情况下更新该字段,那么您必须在单独的语句中执行此操作。
That should really be all you need. However, if you truly can't update the field if it hasn't changed, then you'll have to do it in separate statements.
在我看来,你浪费了很多精力。如果您检索六个值,将它们显示给用户(在某些用户界面中),他们可以更改其中的一些可变数量
然后点击“保存”按钮 - 然后每次更新所有 6 个字段,从用户输入字段获取新值。
有些可能没有改变,但那又怎样。这样代码就简单多了。
Seems to me like you are wasting a lot of effort. If you retrieve the six values, display them to the user (in some user interface) and they can change some variable number of them
and hit a "save" button - then just update all 6 fields every time, getting the new values from the user input fields.
Some may not have changed, but so what. Much simpler code that way.
使用存储过程参数的 DEFAULT 值。
然后,您可以通过以下方式构建更新:
Use DEFAULT values for the stored procedure parameters.
Then, you can structure your update in this way:
我不确定这是否是最好的方法,但也许你可以尝试
I am not sure if this is the best way to do it, but maybe you can try
如果您需要将其放在单个存储过程中,我强烈建议您使用 Adam Robinson 的方法。
更好的方法是简单地对每一项更新使用单独的存储过程。
I would highly recommend using Adam Robinson's method if you require this to be in a single stored procedure.
Even better would be to simply use separate stored procedures for each one of these updates.