简体   繁体   中英

How to create a Stored Procedure to count licences recursively?

I have only a very little experience with SQL and now i'm stuck.

So what i want is the following. We make installation packages, to install applications preconfigured. These packages will create a registry entry with the application's name. I read this registry entries and then i'm inserting it into an SQL database.

My Licences table has the following columns.
- PackageName
- DisplayName
- Bought
- Free
- SubstituteLicense
- Custom

The problem is with this SubstitueLicense. So i want to make a stored procedure which should work in the following way. If a record's substitutelicense has a value and Free is 0, then the substitulicense's Free value should be decremented. I made a stored procedure which works fine if substitulicense has no value, but i don't know how to do the rest.

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

Could someone help me to solve this?

Thanks!

Update:

Sorry i forgot to tell, that substitulicense is nvarchar type. It contains another package name. I need this, because for example we have 100 pcs Office 2007 Licences and 50 pcs Office 2010 Licences. But Office 2010 licences can be used for office 2007 too, and so we can use 150 pcs of Office 2007. Of course the packaga what substitilicense value is exists also in this table, and this value is what i want to decrement. Hope you understand now how i meant

I think part of the difficulty you're having (especially with recursive counting - if you're trying to do something in SQL on a row-by-row basis, that's a good indicator that you might want to look at the way you've built things) is related to how your database is structured.

What you're attempting to do is build a classic resource allocation tracker - if you have 10 licenses for Office 2007, you want to keep track of which computers are registered to use those licenses. Having more active software registrations than you have licenses is a recipe for trouble.

Consider the following facts about the problem: You have X licenses and Y installed registrations that you want to keep track of.

A license is a type of thing which has certain properties:

  • It is for a specific software version, like 'Office 2007' or 'Windows 7' or 'Office 2010' or... etc.
  • It allows you to run a specific number of instances of the specified software.
  • In your case, certain kinds of licenses are allowed to substitute for other licenses - for example, Office 2010 licenses can be used for Office 2007 installations.

A registration is, again, a type of thing with certain properties:

  • It shows the usage of a software license when performing an installation
  • It shows that the install is on a specific machine.

With these facts in mind, I constructed a set of tables:

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

The above table just holds the information about each license type.

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

This table contains information about relationships between different licences; in this case, each row in this table says 'this License_ID is allowed to substitute for the specified Allowed_Sub_License'.

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

If you have other information in your registry entry that I'm not aware of (like who the registration is for, where or what computers, etc.) columns in this table would be the best way to store that data.

Let's take the two licenses you mentioned (Office 2007 and Office 2010) and put them into the Licenses table:

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

We've just bought one copy of each, nothing special. Given your rules, we also know that a 2010 license can substitute for a 2007 license, so License_Substitutes looks like:

Substitute_ID   License_ID  Allowed_Sub_License
1               2           1

Once the licenses have been entered and the substitution relationships have been determined, you can register software using those licenses. If you were to register a copy of 2007 on my computer, Registrations would look like:

Registration_ID     Installed_License   Substitute_License  Description
1                   1                   NULL                Mikurski's computer

Substitute_License is left NULL as that registration does not need a substitute.

However, let's say that you now install 2007 on your computer. Registrations would look like:

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

Substitute_License here is recorded as 2 (for Office 2010). License_Substitutes.Substitute_ID is just an identity value to keep rows distinct.

You'll notice that 'Free' is not here as a column anymore. This is because the number of free spots for a license can be calculated in a query:

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

Normalizing the database like this (for more information about normalization, I've found this to be a good introduction) helps minimize the amount of upkeep work you have to put into maintaining data integrity, and means the database will be easier to extend if your needs change in the future.

Assuming SubstitueLicense is of type integer:

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

That should meet your requirement: If a record's substitutelicense has a value and Free is 0, then the substitulicense's Free value should be decremented

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM