【问题标题】:SQL Server: auto-generated custom format sequence numberSQL Server:自动生成的自定义格式序列号
【发布时间】:2017-03-03 16:55:46
【问题描述】:

我正在使用 Microsoft SQL Server 2014。在我们的要求中,包含自定义格式的序列号。

序列号格式为CAT-YYYY-MM-NNNNNN。样本数据:

CAT-2016-10-000001
CAT-2016-10-000002
                 .
                 .
                 .
CAT-2016-10-999999

我不想使用 GUID 或任何其他,我想使用过程或函数。

所以,我正在尝试这个:

CREATE TABLE [category]
(
    [id] int NOT NULL UNIQUE IDENTITY,
    [category_no] nvarchar(20) NOT NULL,
    [category_name] nvarchar(50) NOT NULL,
    PRIMARY KEY ([id])
);

CREATE FUNCTION generate_category_no() 
RETURNS CHAR(20) 
AS 
BEGIN 
    DECLARE @category_no CHAR(20) 
    SET @category_no = (SELECT MAX(category_no) FROM category) 

    IF @category_no IS NULL
         SET @category_no = 'CAT-' + YEAR(getDate()) + '-' + MONTH(getDate()) + '-000001' 

    DECLARE @no int 
    SET @no = RIGHT(@category_no,6) + 1 

    RETURN 'CAT-' + YEAR(getDate()) + '-' + MONTH(getDate()) + '-' + right('00000' + CONVERT(VARCHAR(10),@no),6) 
END
GO

ALTER TABLE category DROP COLUMN category_no;
ALTER TABLE category ADD category_no AS dbo.generate_category_no();

INSERT INTO category (category_name) 
VALUES ('BMW'), ('JAGUAR');

当我一步步运行上面的SQL,就OK了。它显示没有错误。但是当我运行以下命令时:

SELECT * FROM category;

它显示以下错误:

消息 217,第 16 级,状态 1,第 1 行
超出最大存储过程、函数、触发器或视图嵌套级别(限制 32)。

我不知道如何解决这个问题。甚至我不知道我的功能是否有效。我从互联网上引用了这个功能。

添加

我需要为每个月重置序列号。例如。下个月,no 应该如下:

CAT-2016-11-000001

请赐教。提前致谢!

【问题讨论】:

  • 如果两个会话同时运行(SELECT MAX(category_no) FROM category)怎么办?谁获得 +1 值?
  • 您在从表中选择数据、执行函数或创建函数时遇到错误?是否有任何与 table 关联的触发器?
  • 不,db 中没有触发器。只有这个功能。
  • 这里发生了无限循环,因此 SQL Server 引擎通过将嵌套级别的最大值设置为 32 来防止这种情况发生。无限循环是通过调用 select * from category 调用你的函数来发生的从同一张桌子..等等。如果您从 1= 2 的类别中选择 *,则没有错误,也没有数据:),但是在选择数据时,会发生无限循环。
  • 不,当我运行 sql Select id, category_name, category_no From category Where id < 3; 时,它显示了同样的错误。

标签: sql sql-server function procedure


【解决方案1】:

最后,我解决了这个问题。我的函数如下所示:

CREATE FUNCTION generate_category_no() 
RETURNS CHAR(20) 
AS 
BEGIN 
    DECLARE @category_no CHAR(20) 
    SET @category_no = (SELECT MAX(category_no) FROM category WHERE category_no LIKE CONCAT('CAT-', YEAR(getDate()), '-', MONTH(getDate()), '-%')) 
    IF @category_no is null SET @category_no = CONCAT('CAT-', YEAR(getDate()), '-', MONTH(getDate()), '-000000')
    DECLARE @no INT 
    SET @no = RIGHT(@category_no,6) + 1 
    RETURN CONCAT('CAT-', YEAR(getDate()), '-', MONTH(getDate()), '-', RIGHT('00000' + CONVERT(VARCHAR(10),@no),6))
END
GO

我插入数据如下:

INSERT INTO category (category_no, category_name) VALUES (dbo.generate_category_no(),'BMW');
INSERT INTO category (category_no, category_name) VALUES (dbo.generate_category_no(),'JAGUAR');

有一件事是我们可以从 INSERT 查询中调用函数。

所以,当我运行以下 sql 时:

SELECT * FROM category;

它给出的结果如下所示。

+---+--------------------+--------------+
|id |category_no         |category_name |
+---+--------------------+--------------+
| 1 |CAT-2016-10-000001  | BMW          |
| 2 |CAT-2016-10-000002  | JAGUAR       |
+---+--------------------+--------------+

感谢大家帮助我。谢谢!!!

【讨论】:

  • 可以处理并发吗?
  • table inset同时发送100条记录时,这个函数管理并发吗?我和你一样有这个问题
  • 对我来说,到目前为止还可以。我还测试了 1000 多条记录,它正在工作。
【解决方案2】:

如下修改你的函数

ALTER TABLE category DROP COLUMN category_no;

alter FUNCTION dbo.generate_category_no( @id int) 
RETURNS CHAR(20) 
AS 
BEGIN 

    RETURN 'CAT-' + cast(YEAR(getDate()) as varchar(10)) + '-' + cast(MONTH(getDate()) as varchar(10))+ '-' + right('00000' + CONVERT(VARCHAR(10),@id),6) 
END



ALTER TABLE category ADD category_no AS dbo.generate_category_no(id);

INSERT INTO category
(category_name) 
VALUES 
('BMW13'),
('JAGUAR');

SELECT * FROM category 将给出以下结果。

1   BMW     CAT-2016-10-000001  
2   JAGUAR  CAT-2016-10-000002  
3   BMW1    CAT-2016-10-000003  
4   BMW13   CAT-2016-10-000004  

【讨论】:

  • 很好的解决方案,只是注意:您将 category_no 与 id 相关联,因此如果 identity 中存在间隙,则 category_no 也具有相同的间隙范围。这是否是询问业务的问题?
  • 然后尝试下面的查询 select id,category_name,'CAT-2016-10-00000'+cast(row_number() over(order by id) as varchar(10)) as catid from category跨度>
【解决方案3】:

您的功能中最大的缺陷是它不适用于 Batch Insert 的

因为你已经自动生成了ID,这里有一个更简单的方法来做到这一点

category_no AS Concat('CAT-', Year(Getdate()), '-', Month(Getdate()), '-', RIGHT(Concat('00000', id), 6))

演示

CREATE TABLE #seq
  (
     id   INT IDENTITY(1, 1),
     name VARCHAR(10),
     category_no AS Concat('CAT-', Year(Getdate()), '-', Month(Getdate()), '-', RIGHT(Concat('00000', id), 6))
  )

INSERT INTO #seq
            (name)
VALUES      ('val') 

结果:

id  name    category_no
--  ----    -----------
1   val     CAT-2016-10-000001

【讨论】:

    【解决方案4】:

    试试这个:

    初始化新字段:

    ALTER TABLE category DROP COLUMN category_no;
    ALTER TABLE category ADD category_no CHAR(20)
    
    UPDATE category set category_no = dbo.generate_category_no()
    

    对于其他插入:

    CREATE TRIGGER [dbo].[category_i] 
    ON  [dbo].[category]
    AFTER INSERT
    AS BEGIN
        UPDATE category
        SET category_no = dbo.generate_category_no()
        FROM inserted
        WHERE category.pk = inserted.pk
    END
    

    但你可以尝试使用SEQUENCE 功能,在 Sql Server 2012 版本之前可用

    关于SEQUENCE可以看here

    【讨论】:

    • 我只是赞成你的回答,因为触发器不是我的目标。你的答案在一方面是正确的。但是,我只想在列中使用函数。现在我知道了。谢谢。
    • @NaingWinHtun:您好,亲爱的,感谢您的支持。显然你接受了答案实现了你的目标,所以你接受了你的答案是对的;)祝你有美好的一天
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    • 1970-01-01
    • 2010-10-18
    • 1970-01-01
    • 2019-04-30
    相关资源
    最近更新 更多