如何创建存储过程以递归计算许可证?

时间:2011-12-30 21:52:36

标签: sql sql-server tsql

我对SQL的经验很少,现在我被卡住了。

所以我想要的是以下内容。我们制作安装包,以安装预先配置的应用程序。这些包将使用应用程序的名称创建一个注册表项。我读了这个注册表项,然后我将它插入到SQL数据库中。

我的许可证表格包含以下列 - PackageName
- DisplayName
- 买了 - 免费
- 替代许可证
- 自定义

问题在于SubstitueLicense。所以我想制作一个应该以下列方式工作的存储过程。如果记录的替代许可具有值且Free为0,则应减少替代许可证的免费值。我制作了一个存储过程,如果替代品没有价值,它可以正常工作,但我不知道如何做其余的事。

USE [HWSW_Inventory]
GO
/****** Object:  StoredProcedure [dbo].[InsertWrapAppAndDecrementLicence]    Script Date: 12/30/2011 22:45:37 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[InsertWrapAppAndDecrementLicence]
-- Add the parameters for the stored procedure here
@String    varchar( 8000 ),
@HostName  varchar( 50 )
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

-- Insert statements for procedure here
declare @LineIdx        int
declare @PackageIdx     int
declare @Line           varchar( 8000 )
declare @InsertValues   varchar( 4000 )
declare @PackageName    varchar( 200 )
declare @Command        varchar( 8000 )

select @LineIdx = 1

if ( ( len( @String ) < 1 ) or ( @String is null ) ) return
while ( @LineIdx != 0 )
begin
    --set LineIdx to the first occurence of a line separator
    set @LineIdx = charindex( ';', @String )
    if ( @LineIdx != 0 ) set @Line = left( @String, @LineIdx - 1 )
    else set @Line = @String

    --replace value delimeters and concatenate the hostname so we have a string what we can insert into the database
    set @InsertValues = '''' + REPLACE( @Line, '|', ''', ''') + ''', ''' + @HostName + ''''

    --get the first occurence of a ',' from the string what we want to insert, because it is the PackageName
    set @PackageIdx = CHARINDEX( '|', @String )
    if ( @PackageIdx != 0 ) set @PackageName = left( @String, @PackageIdx - 1 )
    else set @PackageName = @String

    set @Command = 'insert into dbo.WrapperApplications values ( ' + @InsertValues + ' )'
    exec ( @Command )

    update Licences set Free = Free - 1 where ( Licences.PackageName = @PackageName )

    set @String = right( @String, len( @String ) - @LineIdx )
    if ( len( @String ) = 0 ) break
end--while
END--main

有人可以帮我解决这个问题吗?

谢谢!

更新

抱歉,我忘了告诉我,替代品是nvarchar类型。它包含另一个包名称。我需要这个,因为例如我们有100个Office 2007许可证和50个Office 2010许可证。但是Office 2010许可证也可以用于Office 2007,因此我们可以使用150个Office 2007.当然,在这个表中也存在什么替代品值的packaga,这个值是我想要减少的。希望你现在明白我的意思

2 个答案:

答案 0 :(得分:1)

我认为你遇到的部分困难(特别是对于递归计数 - 如果你试图逐行地在SQL中做某事,那么这是一个很好的指标,你可能想看看你建造东西的方式与你的数据库结构有关。

您尝试执行的操作是构建经典资源分配跟踪器 - 如果您拥有10个Office 2007许可证,则需要跟踪已注册的计算机以使用这些许可证。拥有比许可证更多的有效软件注册是一个麻烦的方法。

考虑以下关于该问题的事实: 您有X许可证和Y安装的注册要跟踪。

许可证是一种具有某些属性的东西:

  • 适用于特定的软件版本,例如“Office 2007”或“Windows” 7'或'Office 2010'或......等。
  • 它允许您运行指定软件的特定数量的实例。
  • 在您的情况下,允许某些类型的许可证替代其他许可证 - 例如,Office 2010许可证可用于Office 2007安装。

注册又是一种具有某些属性的东西:

  • 显示执行安装时软件许可证的使用情况
  • 表明安装在特定计算机上。

考虑到这些事实,我构建了一组表格:

Licenses:
License_ID          integer identity(1,1)
Package_Name        varchar( 200 )
Display_Name        varchar( 400 )
Bought              integer

上表仅包含有关每种许可类型的信息。

License_Substitutes:
Substitute_ID       integer identity(1,1)
License_ID          integer
Allowed_Sub_License integer

此表包含有关不同许可之间关系的信息;在这种情况下,此表中的每一行都显示“允许此License_ID替换指定的Allowed_Sub_License”。

Registrations:
Registration_ID     integer identity(1,1)
Installed_License   integer
Substitute_License  integer
Description         varchar(80)

如果您在注册表项中有其他我不知道的信息(例如注册的对象,地点或计算机等),此表中的列将是存储该数据的最佳方式。< / p>

我们将您提到的两个许可证(Office 2007和Office 2010)放入许可证表中:

License_ID  Package_Name    Display_Name            Bought
1           Off2007         Microsoft Office 2007   1
2           Off2010         Microsoft Office 2010   1

我们刚买了一份,没什么特别的。根据您的规则,我们也知道2010许可证可以替代2007许可证,因此License_Substitutes看起来像:

Substitute_ID   License_ID  Allowed_Sub_License
1               2           1

输入许可证并确定替代关系后,您可以使用这些许可证注册软件。如果您要在我的计算机上注册2007的副本,注册将如下所示:

Registration_ID     Installed_License   Substitute_License  Description
1                   1                   NULL                Mikurski's computer

Substitute_License保留为NULL,因为该注册不需要替换。

但是,假设您现在在计算机上安装了2007。注册看起来像:

Registration_ID     Installed_License   Substitute_License  Description
1                   1                   NULL                Mikurski's computer
1                   1                   2                   kampi's computer

此处的Substitute_License记录为2(对于Office 2010)。 License_Substitutes.Substitute_ID只是一个标识值,用于保持行不同。

你会注意到'Free'不再是一个专栏了。这是因为可以在查询中计算许可证的空闲点数:

select count(*) from Registrations
where   (installed_license = @Your_License_ID and substitute_license is NULL)
        or substitute_license = @Your_License_ID

像这样规范化数据库(有关规范化的更多信息,我发现this是一个很好的介绍)有助于最大限度地减少维护数据完整性所需的维护工作量,并且意味着数据库如果您的需求在未来发生变化,将会更容易扩展。

答案 1 :(得分:0)

假设SubstitueLicense的类型为整数:

update
  Licences set Free = Free - 1
where
  (
    Licences.PackageName = @PackageName and
    Licenses.SubstitueLicese > 0 and
    Licenses.Free = 0
  )

这应符合您的要求:如果记录的替代许可具有值且Free为0,则替代许可证的免费值应减少