SQL Server:更新列中不存在的值
我正在使用SQLServer2008,并试图创建一条语句,如果满足某个参数,该语句将更新另一个表中一行中的单个值。我需要尽可能简单地让我的团队成员使用 所以在本例中,我想存储两个值,销售订单和引用。不幸的是,销售订单有一个唯一的标识符,我需要记录并输入到jobs表中,而不是实际的销售订单引用 需要满足的参数是,销售订单唯一标识符不能存在于jobs表的Sales order列中的任何位置。当while值设置为1时,我可以让它工作,但当它设置为0时,我的大脑中应该设置为0。有人知道为什么这样不行吗SQL Server:更新列中不存在的值,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我正在使用SQLServer2008,并试图创建一条语句,如果满足某个参数,该语句将更新另一个表中一行中的单个值。我需要尽可能简单地让我的团队成员使用 所以在本例中,我想存储两个值,销售订单和引用。不幸的是,销售订单有一个唯一的标识符,我需要记录并输入到jobs表中,而不是实际的销售订单引用 需要满足的参数是,销售订单唯一标识符不能存在于jobs表的Sales order列中的任何位置。当while值设置为1时,我可以让它工作,但当它设置为0时,我的大脑中应该设置为0。有人知道为什么这样不行吗
/****** Attach an SO to a WO ******/
/****** ONLY EDIT THE VALUES BETWEEN '' ******/
Declare @Reference nvarchar(30);
Set @Reference = 'WO16119';
Declare @SO nvarchar(30);
Set @SO = '0000016205';
/****** DO NOT ALTER THE CODE BEYOND THIS POINT!!!!!!!!!!!!! ******/
/* store more values */
Declare @SOID nvarchar(30);
Set @SOID = (Select SOPOrderReturnID
FROM Test_DB.dbo.SOTable
Where DocumentNo = @SO);
/* check if update should run */
Declare @Check nvarchar (30);
Set @Check = (Select case when exists (select *
from Test_DB.dbo.Jobs
where SalesOrderNumber != @SOID)
then CAST(1 AS BIT)
ELSE CAST(0 AS BIT) End)
While (@Check = 0)
/* if check is true run code below */
Begin
Update Test_DB.dbo.jobs
SET SalesOrderNumber = (Select SOPOrderReturnID
FROM Test_DB.dbo.SOPOrderReturn
Where DocumentNo = @SO)
Where Reference = @Reference
END;
一些评论。首先,为了避免陷入永无止境的循环,您可能需要更改IF语句的while。您没有更改@check值,因此它将永远运行:
IF (@Check = 0)
BEGIN
/* if check is true run code below */
Update Test_DB.dbo.jobs
SET SalesOrderNumber = (Select SOPOrderReturnID
FROM Test_DB.dbo.SOPOrderReturn
Where DocumentNo = @SO)
Where Reference = @Reference
END
然后,在不了解您的应用程序的情况下,我会说,您进行检查的方式将要求您锁定表,以避免其他用户使您选择的结果无效
我将转而在您想要唯一的列上创建一个唯一约束,并优雅地处理错误。这样,您就不需要在表上创建大锁
CREATE UNIQUE INDEX IX_UniqueIndex ON Test_DB.dbo.Jobs(SalesOrderNumber)
根据您的评论,如果无法创建唯一索引,您可能希望尝试以下SQL,尽管它可能会导致太多锁定并受竞争条件的影响:
IF NOT EXISTS (SELECT 1 FROM Test_DB.dbo.Jobs j INNER JOIN Test_DB.dbo.SOTable so ON j.SalesOrderNumber = so.SPOrderReturnId)
BEGIN
UPDATE Test_DB.dbo.jobs
SET SalesOrderNumber = so.SOPOrderReturnID
FROM
Test_DB.dbo.Jobs j
INNER JOIN Test_DB.dbo.SOTable so ON j.SalesOrderNumber = so.SPOrderReturnId
Where
Reference = @Reference
END
这样做的风险在于,您运行的是单独的查询(选择和更新),因此它们之间的数据库状态可能会发生变化。因此,第一个查询可能不会返回该Id的任何内容,但在更新时,其他用户已插入/更新该数据,因此先前的结果不再为真
您可以尝试通过使用隔离级别来避免此问题,该隔离级别在读取时锁定表(如Serializable),但这可能会导致数据库中出现锁甚至死锁
这里最好的解决方案是唯一索引。如果表中的某一列必须是唯一的,那么通过定义约束,最好的控制系统就是数据库本身。而且当我让它工作时,它会反复运行,我不相信它正在执行检查。为了澄清这一点,SalesOrderNumber列中不能存在值以运行此更新脚本。您有无限的循环
而(@Check=0)
使用如果(@Check=0)
您的意思是如果,而不是而,因为提供了信息,所以它只能运行一次。我现在遇到的问题是,它没有检查列中是否存在该值。是的,我想说这正是正确的处理方法,代码最少,并避免争用条件。因此,在这种情况下,我会只检查索引吗?如果检查设置为1,则它将在分钟运行,但这不是正确的方法,该列中不需要该值才能运行更新。无检查。您只需尝试更新,如果该值存在,索引将抱怨并抛出错误。您可以处理错误,也就是说。我现在可以在括号内输入SalesOrderNumber吗?从未使用过唯一的索引我不明白它是如何工作的,如果这些是愚蠢的问题,很抱歉。更新后会有更多的解释,但您应该在线查看一些关于数据库上的隔离级别、锁、死锁和竞争条件的文档。