Sql server SQl Server Express 2005-更新2个表和原子性?
首先,我想说我不是SQL程序员(我是C++/Delphi程序员),所以我的一些问题可能非常明显。所以请原谅我的无知:哦) 我负责编写一个脚本,根据CSV文件的内容更新数据库中的某些表。我让它工作起来了,但我担心其中一个步骤的原子性: 其中一个表只包含一个字段—一个每次都必须递增的int,但从我所看到的情况来看,由于某种原因,它没有定义为标识。我必须在此表中创建一个新行,并将该行的值插入另一个表中新创建的行中 我就是这样做的(作为更大脚本的一部分):Sql server SQl Server Express 2005-更新2个表和原子性?,sql-server,Sql Server,首先,我想说我不是SQL程序员(我是C++/Delphi程序员),所以我的一些问题可能非常明显。所以请原谅我的无知:哦) 我负责编写一个脚本,根据CSV文件的内容更新数据库中的某些表。我让它工作起来了,但我担心其中一个步骤的原子性: 其中一个表只包含一个字段—一个每次都必须递增的int,但从我所看到的情况来看,由于某种原因,它没有定义为标识。我必须在此表中创建一个新行,并将该行的值插入另一个表中新创建的行中 我就是这样做的(作为更大脚本的一部分): DECLARE@uniqueID INT, @
DECLARE@uniqueID INT,
@计数器INT,
@最大计数整数
从Testable中选择@maxCount=COUNT(*)
设置@counter=1
而(@counter您需要一个事务来确保原子性,您需要将select和insert移动到一个语句中,或者使用updlock执行select,以防止两个人同时运行select,获取相同的值,然后尝试将相同的值插入表中
基本上
DECLARE @MaxValTable TABLE (MaxID int)
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO uniqueIDTable VALUES (id)
OUTPUT inserted.id INTO @MaxValTable
SELECT MAX(id) + 1 FROM uniqueIDTable
UPDATE TOP(1) tempTable
SET userID = (SELECT MAXid FROM @MaxValTable)
WHERE userID IS NULL
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
RAISERROR 'Error occurred updating tempTable' -- more detail here is good
END CATCH
这就是说,使用标识会使事情简单得多。这是一个潜在的并发问题。有没有办法将列更改为标识
编辑:确保一次只能插入一个连接到uniqueIDtable中。但不能很好地扩展
编辑:Table变量比exclusive Table lock好。如果需要,也可以在插入用户时使用它。您可以在一条语句中完成整个9码:
WITH cteUsers AS (
SELECT t.*
, ROW_NUMBER() OVER (ORDER BY userID) as rn
, COALESCE(m.id,0) as max_id
FROM tempTable t WITH(UPDLOCK)
JOIN (
SELECT MAX(id) as id
FROM uniqueIDTable WITH (UPDLOCK)
) as m ON 1=1
WHERE userID IS NULL)
UPDATE cteUsers
SET userID = rn + max_id
OUTPUT INSERTED.userID
INTO uniqueIDTable (id);
通过使用ROW_NUMBER()
,您可以获得MAX(id)
,锁定uniqueIDTable
,为NULL
userID
的用户计算连续的用户id,更新tentable
,并将新的id插入uniqueIDTable
。所有操作都是一次完成的
对于性能,您需要在uniqueIDTable(id)
上创建索引,并在tentable(userID)
上创建索引
SQL完全是面向集合的操作,而循环是SQL的代码味道。INSERT…SELECT MAX()不是原子的。后续更新可以将其他提交的插入视为新的MAX,从而导致多个更新应用相同的id。感谢您的回复。我认为我无法更改该列-这不是我们的应用程序-但我会看到。假设我可以,在这种情况下它将如何更改?好的,我将编辑它以使其更偏执,但远比ss performant。如果您可以将列更改为identity,则根本不需要UniquedTable。您只需插入到TENTRABLE中,SQL将处理ID列本身。谢谢Gila。在这种情况下,性能不是一个大问题,这是为了维护,在下班后的操作。但是,我似乎无法在我的while循环中实现这一点.一定很简单,但正如我所提到的,我在这里不适合,当然这是昨天到期的:o)我现在就按照下面雷姆斯的答案来做。我将在周末测试这两个方面的更多细节(希望如此)谢谢你,雷姆斯。我有一种感觉,虽然循环不是解决问题的办法,但我想不出像你这样的说法。从目前为止我做的几个测试来看,它似乎工作得很好。
WITH cteUsers AS (
SELECT t.*
, ROW_NUMBER() OVER (ORDER BY userID) as rn
, COALESCE(m.id,0) as max_id
FROM tempTable t WITH(UPDLOCK)
JOIN (
SELECT MAX(id) as id
FROM uniqueIDTable WITH (UPDLOCK)
) as m ON 1=1
WHERE userID IS NULL)
UPDATE cteUsers
SET userID = rn + max_id
OUTPUT INSERTED.userID
INTO uniqueIDTable (id);