在 SQL 中实现递增计数器
Implement Incrementing Counter in SQL
所以我基本上需要实现一个自动增量列。我在一个 table 中有一列,其中有一个 int 将充当计数器,并且还有另一个 table 具有相应的行数,每行都有自己的计数器。我认为这实现起来相当简单,但在做了一些研究后,我发现了一些论坛,他们提到如果多个交易 运行 大致同时发生,在这种情况下可能会出现问题,即使 运行 select,update, & insert in one transaction
虽然在我看来,如果我使用 OUTPUT 子句来获取第一个 table 更新的新值,我可以完全避免该问题。
这就是我想的T-SQL。这适合我的情况吗?
BEGIN TRANSACTION;
DECLARE @tblCtrs table (Ctr int)
DECLARE @CtrVal INT
UPDATE Table1
SET Ctr = Ctr+1
OUTPUT inserted.Ctr INTO @CtrVals
WHERE id=<whatever id value>
SET @CtrVal = (SELECT TOP(1) Ctr FROM @tblCtrs)
INSERT INTO TABLE2 (Ctr, ....)
VALUES( @CtrVal, ....)
COMMIT;
如果我对你的问题的理解正确,那么担心的是并发事务可能会导致计数器值出现意外结果。您知道如何很好地管理计数器值,这只是其他事务是否可以同时 read/modify 的问题。如果这种理解是正确的,那就是隔离级别的目的。取决于数据的方式 accessed/stored(例如,是否可以有多个记录具有相同的 或者它是唯一的?)和应用程序要求(例如,如果 不是唯一的并且可以吗?有插入的新记录由于时间的原因没有更新)你应该相应地SET TRANSACTION ISOLATION LEVEL。
如果您能够使用标识列,则可以使用 SCOPE_IDENTITY() 来查找最后插入的记录的标识值,如下所示:
DECLARE
@ParentData varchar(20) = 'ParentData1',
@ChildData varchar(20) = 'ChildData1',
@ParentID int
DECLARE @ParentTable table (ParentId int IDENTITY(1, 1), ParentData Varchar(20))
DECLARE @ChildTable table (ChildId int IDENTITY(1,1), ParentId int, ChildData varchar(20))
INSERT INTO @ParentTable
(ParentData)
VALUES
(@ParentData)
SET @ParentId = SCOPE_IDENTITY()
INSERT INTO @ChildTable
(ParentId, ChildData)
VALUES
(@ParentID, @ChildData)
SET @ChildData = 'ChildData1,1'
INSERT INTO @ChildTable
(ParentId, ChildData)
VALUES
(@ParentID, @ChildData)
SET @ParentData = 'ParentData2'
SET @ChildData = 'ChildData2'
INSERT INTO @ParentTable
(ParentData)
VALUES
(@ParentData)
INSERT INTO @ChildTable
(ParentId, ChildData)
VALUES
(SCOPE_IDENTITY(), @ChildData)
SELECT * FROM @ParentTable
SELECT * FROM @ChildTable
所以我基本上需要实现一个自动增量列。我在一个 table 中有一列,其中有一个 int 将充当计数器,并且还有另一个 table 具有相应的行数,每行都有自己的计数器。我认为这实现起来相当简单,但在做了一些研究后,我发现了一些论坛,他们提到如果多个交易 运行 大致同时发生,在这种情况下可能会出现问题,即使 运行 select,update, & insert in one transaction
虽然在我看来,如果我使用 OUTPUT 子句来获取第一个 table 更新的新值,我可以完全避免该问题。
这就是我想的T-SQL。这适合我的情况吗?
BEGIN TRANSACTION;
DECLARE @tblCtrs table (Ctr int)
DECLARE @CtrVal INT
UPDATE Table1
SET Ctr = Ctr+1
OUTPUT inserted.Ctr INTO @CtrVals
WHERE id=<whatever id value>
SET @CtrVal = (SELECT TOP(1) Ctr FROM @tblCtrs)
INSERT INTO TABLE2 (Ctr, ....)
VALUES( @CtrVal, ....)
COMMIT;
如果我对你的问题的理解正确,那么担心的是并发事务可能会导致计数器值出现意外结果。您知道如何很好地管理计数器值,这只是其他事务是否可以同时 read/modify 的问题。如果这种理解是正确的,那就是隔离级别的目的。取决于数据的方式 accessed/stored(例如,是否可以有多个记录具有相同的
如果您能够使用标识列,则可以使用 SCOPE_IDENTITY() 来查找最后插入的记录的标识值,如下所示:
DECLARE
@ParentData varchar(20) = 'ParentData1',
@ChildData varchar(20) = 'ChildData1',
@ParentID int
DECLARE @ParentTable table (ParentId int IDENTITY(1, 1), ParentData Varchar(20))
DECLARE @ChildTable table (ChildId int IDENTITY(1,1), ParentId int, ChildData varchar(20))
INSERT INTO @ParentTable
(ParentData)
VALUES
(@ParentData)
SET @ParentId = SCOPE_IDENTITY()
INSERT INTO @ChildTable
(ParentId, ChildData)
VALUES
(@ParentID, @ChildData)
SET @ChildData = 'ChildData1,1'
INSERT INTO @ChildTable
(ParentId, ChildData)
VALUES
(@ParentID, @ChildData)
SET @ParentData = 'ParentData2'
SET @ChildData = 'ChildData2'
INSERT INTO @ParentTable
(ParentData)
VALUES
(@ParentData)
INSERT INTO @ChildTable
(ParentId, ChildData)
VALUES
(SCOPE_IDENTITY(), @ChildData)
SELECT * FROM @ParentTable
SELECT * FROM @ChildTable