【问题标题】:SQL Server Stored Procedure to dump oldest X records when new records addedSQL Server 存储过程在添加新记录时转储最旧的 X 记录
【发布时间】:2011-02-24 18:25:43
【问题描述】:

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

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

提前感谢您的帮助。

【问题讨论】:

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


    【解决方案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
    

    【讨论】:

    • 我遇到了麻烦,也许你可以帮我解决。我的 Activations 表包含以下列:CustomerName、KeyCode、MachineName、ActivationDate。您可以重新激活同一台机器,所以我可能有 10 条记录,除了 ActivationDate 之外的所有内容都相同。我需要一些方法来首先获得一个具有 DISTINCT 和有序 DESC 激活的结果集,这样我就没有重复信息计数的行号对同一台机器重新激活。在我得到不同的结果集之后,我需要按照你的建议应用行号。关于如何做到这一点的任何想法?谢谢。
    • @Neal:我已经在你打开的follow-up question 上发布了my answer
    【解决方案2】:

    使用视图或表值函数与 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
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 感谢帕特里克 - 很棒的信息,感谢您的帮助。我确实选择了乔的答案,因为它是最简单的实现。
      猜你喜欢
      • 2015-11-27
      • 2011-08-10
      • 2014-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-03
      相关资源
      最近更新 更多