SQL Server存储过程在添加新记录时转储最旧的X记录

时间:2011-02-23 21:48:21

标签: sql-server tsql sql-server-2008 stored-procedures

我有一个许可方案,当一个人激活一个新系统时,它会将旧激活添加到一个锁定表中,这样他们只能激活他们最新的X系统。我需要传递一个参数,指出要保留的最近激活次数,并且如果尚未锁定,则应将所有较旧的激活添加到锁定表中。我不确定如何最好地做到这一点,即临时表(我从未做过)等等。

例如,激活来自系统XYZ上的John Doe。然后,我需要查询激活表,查看John Doe的所有激活,并按DATE DESC对其进行排序。在这种情况下,John Doe可能拥有允许两个系统的许可证,因此我需要所有早于前2个停用的记录,即插入锁定表。

提前感谢您的协助。

3 个答案:

答案 0 :(得分:1)

或许这样的事情?

insert into lockouts
    (<column list>)
    select <column list>
        from (select <column list>, 
                     row_number() over (order by date desc) as RowNum
                  from activations) t
        where t.RowNum > @NumLicenses

答案 1 :(得分:0)

使用视图或表值函数将row_number()结合起来可能最简单:

WITH ActivationRank AS
(
SELECT SystemId,ProductId,CreatedDate,ROW_NUMBER() OVER(PARTITION BY ProductId ORDER BY CreatedDate DESC) AS RANK     
FROM [Activations]
)

SELECT SystemId, ProductId, CASE WHEN RANK < @lockoutParameterOrConstant 0 ELSE 1 END AS LockedOut
FROM ActivationRank

答案 2 :(得分:0)

在你花时间阅读和尝试我的方法之前,我想说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