更新存储过程 - 仅更新某些字段并保留其他字段

时间:2017-04-25 14:01:39

标签: sql sql-server tsql

我目前正在制作一个存储过程,用于更新产品详细信息。我想制作它(如果可能的话),这样只有在'值下输入的字段才能生成。执行时更新列,其余列保持不变。

ALTER PROCEDURE [dbo].[spUpdateProduct]
@ProductID int, @Brand nvarchar(30), @ModelNo nvarchar(9), @Description 
nvarchar(50), @CostPrice decimal(6,2), @Stock int, @SalePrice decimal(6,2)  

AS
BEGIN
SET NOCOUNT ON

UPDATE tblProduct 
SET                 
    Brand = @Brand,
    ModelNo = @ModelNo,
    [Description] = @Description,
    CostPrice = @CostPrice,
    Stock = @Stock,
    SalePrice = @SalePrice

WHERE ProductID = @ProductID 

END

这是我现在所拥有的。当我改变一个值时,它出错了,说我没有输入“品牌”的价值。这是产品ID'之后的下一个值。

Execute Window

Error when trying to update two fields (ProductID and CostPrice)

编辑:字段全部设置为' not null'当我创建表格时。

3 个答案:

答案 0 :(得分:6)

我就是这样做的。具有无效参数

ALTER PROCEDURE [dbo].[spUpdateProduct]
@ProductID int, 
@Brand nvarchar(30) = null, 
@ModelNo nvarchar(9) = null, ..... (to all the parameters except @ProductID)

AS
BEGIN
SET NOCOUNT ON

UPDATE tblProduct 
SET                 
    Brand = isNull(@Brand, Brand),
    ModelNo = isNull(@ModelNo, ModelNo),
    [Description] = isNull(@Description, Description),...


WHERE ProductID = @ProductID 

END

基本上,如果参数不为null,则只更新字段,否则保留旧值。

答案 1 :(得分:1)

您有两个问题 - (a)必须提供存储过程的参数(错误告诉您)和(b)未提供参数时该怎么做。对于第一个问题,请检查pass null值或使用SQL查询执行存储过程,如下所示:

exec spUpdateProduct 1, null, null, null, 140.99, null, null

对于问题(b),使用coalesce根据传递的值进行更新:

ALTER PROCEDURE [dbo].[spUpdateProduct]
@ProductID int, @Brand nvarchar(30), @ModelNo nvarchar(9), @Description 
nvarchar(50), @CostPrice decimal(6,2), @Stock int, @SalePrice decimal(6,2)  

AS
BEGIN
SET NOCOUNT ON

UPDATE t 
SET                 
    Brand = coalesce(@Brand, t.Brand),
    ModelNo = coalesce(@ModelNo, t.ModelNo),
    [Description] = coalesce(@Description, t.Description),
    CostPrice = coalesce(@CostPrice, t.CostPrice),
    Stock = coalesce(@Stock, t.Stock),
    SalePrice = coalesce(@SalePrice, t.SalePrice)
FROM tblProduct as t
WHERE ProductID = @ProductID 

END

答案 2 :(得分:0)

经过一段时间的思考,我想出了一个不使用动态 sql 的解决方案,也解决了 coaleseisNull 方法无法解决的问题。注意:最少的测试……看起来确实增加了一点开销……但是拥有这种能力可能会让您的客户端代码具有灵活性。

表架构:

FirstName NVARCHAR(200)
LastName NVARCHAR(200)
BirthDate DATE NULL
Activated BIT

Xml 参数:

DECLARE @param = 
N'<FirstName>Foo</FirstName>
<LastName>Bar</LastName>
<BirthDate>1999-1-1</BirthDate>
<Activated>1</Activated>'
UPDATE [dbo].[UserMaster]
[FirstName] = case when @param.exist('/FirstName') = 1 then @param.value('/FirstName[1]','nvarchar(200)') else [FirstName] end,
[LastName] = case when @param.exist('/LastName') = 1 then @param.value('/LastName[1]','nvarchar(200)') else [LastName] end,
[BirthDate] = case when @param.exist('/BirthDate') = 1 then @param.value('/BirthDate[1]','date') else [BirthDate]end,
[Activated] = case when @param.exist('/Activated') = 1 then @param.value('/Activated[1]','bit') else [Activated] end
WHERE [UserMasterKey] = @param.value('/UserMasterKey[1]','bigint')

这将允许您传入一个 XML 参数,包含您想要的任何字段并更新该字段。请注意,在此上下文中将字段设置为等于自身,例如 [FirstName] = [FirstName],完全没问题。引擎会对此进行优化。

现在,这是@Anand 和@r.net 答案的更复杂的解决方案,但是它确实解决了一些评论者指出的“设置可空值”问题。

我喜欢他们的解决方案的优雅,但希望能够在可空列上设置 NULL,同时如果我不为该字段传递参数,仍然保留使用默认字段值的能力。在这种情况下,使用 null 检查作为默认值的基础填补了漏洞并挖掘了另一个漏洞,可以这么说,因为它们不允许将字段显式更新为 null。

传递 xml 参数允许您这样做,而无需采用动态 sql 方法。

我也会考虑使用 Table-valued parameters,因为我相信使用这些可以有类似的解决方案。