Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQl Server Express 2005-更新2个表和原子性?_Sql Server - Fatal编程技术网

Sql server SQl Server Express 2005-更新2个表和原子性?

Sql server SQl Server Express 2005-更新2个表和原子性?,sql-server,Sql Server,首先,我想说我不是SQL程序员(我是C++/Delphi程序员),所以我的一些问题可能非常明显。所以请原谅我的无知:哦) 我负责编写一个脚本,根据CSV文件的内容更新数据库中的某些表。我让它工作起来了,但我担心其中一个步骤的原子性: 其中一个表只包含一个字段—一个每次都必须递增的int,但从我所看到的情况来看,由于某种原因,它没有定义为标识。我必须在此表中创建一个新行,并将该行的值插入另一个表中新创建的行中 我就是这样做的(作为更大脚本的一部分): DECLARE@uniqueID INT, @

首先,我想说我不是SQL程序员(我是C++/Delphi程序员),所以我的一些问题可能非常明显。所以请原谅我的无知:哦)

我负责编写一个脚本,根据CSV文件的内容更新数据库中的某些表。我让它工作起来了,但我担心其中一个步骤的原子性: 其中一个表只包含一个字段—一个每次都必须递增的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);