我正在使用SQL Server 2008并尝试创建一个语句,如果满足某个参数,它将更新来自另一个表的行中的单个值。我需要让我的团队成员尽可能简单地使用它。
所以在这种情况下我想存储2个值,即销售订单和参考。不幸的是,销售订单具有我需要记录并输入作业表的唯一标识符,而不是实际的销售订单参考。
需要满足的参数是,销售订单唯一标识符不能存在于jobs表中的销售订单列中的任何位置。我可以在while值设置为1时将其设置为工作,但是当它设置为0并且在我的头脑中它应该设置为0.任何人都有任何想法为什么这不起作用?< / p>
/****** 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;
答案 0 :(得分:2)
一些评论。首先,为了避免进入永无止境的循环,您可能希望更改IF语句的时间。您没有更改@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
然后,在不知道您的应用程序的情况下,我会说您进行检查的方式是要求您锁定表格以避免其他用户使SELECT的结果无效。
我会转而在你想要独特的列上创建一个UNIQUE约束,并优雅地处理错误。这样您就不需要在表上创建大锁了
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)来避免此问题,但这可能会导致数据库中的锁甚至死锁。
这里最好的解决方案是唯一索引。如果某个列在表中必须是唯一的,那么最好的控制器系统就是db本身,它通过定义约束。