在sql server中生成自动增量varchar主键

时间:2013-07-27 15:19:29

标签: sql-server sql-server-2008

我想为每个单独订单生成varchar自动递增主键(订单ID)值,如下所示。

'O201307270001'

'O'用于订单,'20130727'用于日期(27-jul-2013),'0001'用于自动递增值

我希望重新启动自动递增的数字(上述ID中的最后4位数字)从新的一天开始时从'1'开始。

以下是我希望如何为在不同时间和日期下订单生成订单ID的示例:

O201307270001   when date is like '2013-07-27 01:23:45.235'
O201307270002   when date is like '2013-07-27 03:12:22.212'
.
.
.
O201307270040   when date is like '2013-07-27 11:34:56.189'
.
.
//Now when new day starts:
O201307280001   when date is like '2013-07-28 00:00:00.000'
O201307280002   when date is like '2013-07-28 00:13:05.000'

请帮助我,我该怎么做

5 个答案:

答案 0 :(得分:2)

这是我的建议,它具有(非常大:))不读取目标表的优点,并且随着表的增长将提供更好的性能。

您必须创建一个简短的存储过程和一个参数表。

只需调用存储过程,它将返回正确的ID:

DECLARE @NewOrderId AS CHAR(13)

EXEC usp_NewOrderId @NewOrderId OUTPUT

SELECT @NewOrderId

这是您需要创建的内容:

CREATE TABLE OrderNumberGenerator (
  Id INTEGER IDENTITY(1,1),
  CreatedDate DATE DEFAULT(GETDATE()) 
 )
GO

CREATE PROCEDURE usp_NewOrderId 
(@NewOrderIdOut char(13) OUTPUT ) 
AS 
BEGIN

   IF EXISTS (SELECT 1 FROM OrderNumberGenerator WHERE CreatedDate <> CAST(GETDATE() AS DATE) )
    TRUNCATE TABLE OrderNumberGenerator --restart the counter everyday :)

  INSERT INTO OrderNumberGenerator DEFAULT VALUES

  SELECT @NewOrderIdOut = 
  'O' +
  CONVERT(CHAR(8), GETDATE(), 112) +
  RIGHT( '000' + CAST(SCOPE_IDENTITY() AS VARCHAR(4)) ,  4 ) 

END

在此处查看http://sqlfiddle.com/#!3/fdb91/4

答案 1 :(得分:0)

我强烈建议您不要将此varchar生成的代码用作表的主键,而是使用数值代替并将此生成的字符串保存为单独列上的订单代码(它将使您远离噩梦与未来querys)。您可以将此代码列标记为“唯一”,并获得相同的结果。

关于如何生成订单代码,如果背后的逻辑不像自动增量或类似的东西那么基本,那么最好将这个donde放在系统的上层(如果有的话)。 / p>

答案 2 :(得分:0)

您可以使用INSTEAD OF INSERT触发器或我建议的CreateOrder存储过程执行此操作。

以下是您必须遵循的步骤:

  1. 计算当前日期前缀。 'O' + CONVERT(char(8), GETDATE(), 112)
  2. 从表格中选择最后一个订单号。 SELECT MAX(OrderNum) FROM Order
  3. 如果最后一个订单号具有当前日期前缀,请提取数字后缀,将其递增,然后将其附加到日期前缀。 WHEN @CurrentPrefix = LEFT(@LastOrder, 9) THEN @CurrentPrefix + RIGHT('000' + (CONVERT(int, RIGHT(@LastOrder, 4)) + 1))
  4. 否则,只需使用0001作为后缀。 ELSE @CurrentPrefix + '0001'
  5. 使用生成的密钥执行插入。

答案 3 :(得分:0)

正如其他答案已经指出这样做可能是一个坏主意,但如果你想要反正这个代码应该完成你想要的我相信。我没有尝试过所有的角落情况,但是对于小的测试数据,它提供了它。

我试过的一些测试数据:

declare @tab table (pk char(13))
insert @tab values ('O201307270001')
insert @tab values ('O201307270002')
insert @tab values ('O201307270003')
insert @tab values ('O201307278999')
insert @tab values ('O201307280001')
insert @tab values ('O201307280002')
insert @tab values ('O201307290001')

然后是实际代码:

SELECT 
  CASE ISNULL(MAX(RIGHT(pk,4)),0) 
    WHEN 0 THEN 'O' + CONVERT(CHAR(8),GETDATE(),112) + '0001' 
   ELSE 'O' + CONVERT(CHAR(8),GETDATE(),112) + RIGHT(CAST(MAX(RIGHT(pk,4)) + 10001 AS CHAR(5)),4) END 
FROM @tab 
WHERE SUBSTRING(pk,2,8) = CONVERT(CHAR(8),GETDATE(),112)

理想情况下,它应该包含在一个函数中,并且可能也使用锁定来避免相同的密钥被分发两次。

答案 4 :(得分:0)

CREATE TABLE OrderNumberGenerator(   [ID] INTEGER IDENTITY(1,1),  [New_ID] AS'O'+ CONVERT(varchar)  ) GO