Question

I'm trying to make an even simpler function than the one described here to get the next value of an order number for a shopping cart.

  • I don't care if there are gaps
  • Only completed orders get an ID (i.e. I'm deliberately not using IDENTITY)
  • Obviously there must not be duplicates
  • I don't care about performance and locking. If we have so many new orders that I care about lockin then I'll have other problems first

I've found quite a few other similar questions, but not the exact solution i'm looking for.

What I have so far is this :

USE [ShoppingCart]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Sequence_CompletedOrderID]
([val] [int] NOT NULL 
  CONSTRAINT [DF_Sequence_CompletedOrderID_NextValue]  DEFAULT ((520000))
) ON [PRIMARY]

then for the stored proc :

CREATE PROC dbo.GetNextCompletedOrderId 
  @nextval AS INT OUTPUT
AS

UPDATE dbo.sequence_completedorderid SET @nextval=val += 1;
GO

Like I said I'm trying to base it on the article I linked to above - so perhaps this just a clumsy way of doing it. My SQL isn't quite up to much for even simple things like this, and its past my bedtime. Thanks!

Was it helpful?

Solution

OK, so you already have an IDENTITY column in your main table - but how about just having an additional table with again has an IDENTITY column?? This would save you so much trouble and hassle.....

USE [ShoppingCart]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Sequence_CompletedOrderID]
([val] [int] NOT NULL IDENTITY(520000, 1)
) ON [PRIMARY]



CREATE PROC dbo.GetNextCompletedOrderId 
  @nextval AS INT OUTPUT
AS
   INSERT INTO dbo.Sequence_CompletedOrderID DEFAULT VALUES

   SELECT @nextval = SCOPE_IDENTITY()
GO

That way, you can leave all the hassle of making sure things are unique etc. to SQL Server, and it will also make sure you won't ever get back the same value twice from the IDENTITY column!

OTHER TIPS

If you use the Sequence_CompletedOrderID table as a one row table of order IDs then you should use UPDATE and rely on the OUTPUT clause to capture the new value:

CREATE PROC dbo.GetNextCompletedOrderId 
  @nextval AS INT OUTPUT
AS
SET NOCOUNT ON;
UPDATE dbo.Sequence_CompletedOrderID
SET val=val + 1
OUTPUT @nextval = INSERTED.val;
GO

The solution from @marc_s creates a new row for each number generated. At first I didn't think I liked this, but realized I can use it to my advantage.

What I did was added a date time audit column, and also an @orderid parameter to the stored proc. For a particular orderid it will be guaranteed to return the same completedorderid, which is the number from the sequence generator.

If for some reason my application layer requests the next id, but then crashes before it can commit the transaction - it will still be linked to that order so that when it is requested again the same number will be returned.

This is what I ended up with:

USE [ShoppingCart]
GO
/****** Object:  Table [dbo].[Sequence_CompletedOrderID]    Script Date: 11/29/2009 03:36:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Sequence_CompletedOrderID](
    [val] [int] IDENTITY(520000,1) NOT NULL,
    [CreateDt] [datetime] NOT NULL CONSTRAINT [DF_Sequence_CompletedOrderID_CreateDt]  DEFAULT (getdate()),
    [Orderid] [int] NOT NULL CONSTRAINT [DF_Sequence_CompletedOrderID_Orderid]  DEFAULT ((0)),
 CONSTRAINT [PK_Sequence_CompletedOrderID] PRIMARY KEY CLUSTERED 
(
    [Orderid] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]


USE [ShoppingCart]
GO
/****** Object:  StoredProcedure [dbo].[GetCompletedOrderId]    Script Date: 11/29/2009 03:34:08 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[GetCompletedOrderId] 
  @orderid AS INT,
  @completedorderid AS INT OUTPUT
AS

IF EXISTS (SELECT * FROM dbo.Sequence_CompletedOrderID WHERE orderid = @orderid)
BEGIN 
    SET @completedorderid =(SELECT val FROM dbo.Sequence_CompletedOrderID WHERE orderid = @orderid)
END 
ELSE
BEGIN
   INSERT INTO dbo.Sequence_CompletedOrderID (orderid) VALUES (@orderid)
   SET @completedorderid =(SELECT SCOPE_IDENTITY())
END

How about using the following statement after inserting data in your table?

UPDATE dbo.sequence_completedorderid
SET @nextval = (SELECT MAX(val) + 1 FROM dbo.sequence_completedorderid)

You don't need a new id column, all you need is to add a new OrderCompleted column (bit), and combine that with the id you already have.

SELECT Id FROM T_Order WHERE OrderCompleted = 1
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top