在您花时间阅读和尝试我的方法之前,我想说 Joe Stefanelli 的答案非常出色 - 简短、紧凑、先进并且可能比我的更好,尤其是在性能方面。另一方面,性能可能不是您首先关心的问题(您期望每天激活多少次?每小时?每分钟?),我的示例可能更易于阅读和理解。
由于我不知道您的数据库架构是如何设置的,因此我不得不对其进行一些假设。您可能无法将此代码用作复制和粘贴模板,但它应该让您了解如何操作。
您说的是锁定表,所以我认为您有理由将部分数据复制到第二个表中。如果可能,我宁愿在包含系统数据的表中使用锁定标志,但显然这取决于您的情况。
请注意,我目前无权访问 SQL Server,因此无法检查代码的有效性。我尽力了,但还是有错别字。
第一个假设:一个简约的“注册系统”表:
CREATE TABLE registered_systems
(id INT NOT NULL IDENTITY,
owner_id INT NOT NULL,
system_id VARCHAR(MAX) NOT NULL,
activation_date DATETIME NOT NULL)
第二个假设:一个简约的“锁定系统”表:
CREATE TABLE locked_out_systems
(id INT NOT NULL,
lockout_date DATETIME NOT NULL)
然后我们可以定义一个存储过程来激活一个新系统。它以 owner_id、允许的系统数量,当然还有新的系统 id 作为参数。
CREATE PROCEDURE register_new_system
@owner_id INT,
@allowed_systems_count INT,
@new_system_id VARCHAR(MAX)
AS
BEGIN TRANSACTION
-- Variable declaration
DECLARE @sid INT -- Storage for a system id
-- Insert the new system
INSERT INTO registered_systems
(owner_id, system_id, activation_date)
VALUES
(@owner_id, @system_od, GETDATE())
-- Use a cursor to query all registered-and-not-locked-out systems for this
-- owner. Skip the first @allowed_systems_count systems, then insert the
-- remaining ones into the lockout table.
DECLARE c_systems CURSOR FAST_FORWARD FOR
SELECT system_id FROM
registered_systems r
LEFT OUTER JOIN
locked_out_systems l
ON r.system_id = l.system_id
WHERE l.system_id IS NULL
ORDER BY r.activation_date DESC
OPEN c_systems
FETCH NEXT FROM c_systems INTO @sid
WHILE @@FETCH_STATUS = 0
BEGIN
IF @allowed_systems_count > 0
-- System still allowed, just decrement the counter
SET @allowed_systems_count = @allowed_systems_count -1
ELSE
-- All allowed systems used up, insert this one into lockout table
INSERT INTO locked_out_systems
(id, lockout_date)
VALUES
(@sid, GETDATE())
FETCH NEXT FROM c_systems INTO @sid
END
CLOSE c_systems
DEALLOCATE c_systems
COMMIT