一尘不染

如何创建由其他列细分的自动递增列

sql

我需要创建一个包含增量ID的表,但是我希望这些ID根据另一列自动进行细分。这是我想要的:

CREATE TABLE dbo.MyTable (
    myKey INT IDENTITY PRIMARY KEY,
    category INT,
    incrementalId INT
);

INSERT INTO dbo.MyTable (category) VALUES (100);
INSERT INTO dbo.MyTable (category) VALUES (200);
INSERT INTO dbo.MyTable (category) VALUES (100);
INSERT INTO dbo.MyTable (category) VALUES (100);
INSERT INTO dbo.MyTable (category) VALUES (100);
INSERT INTO dbo.MyTable (category) VALUES (200);

SELECT *
FROM dbo.MyTable;

我想要显示类似以下内容:

myKey       category    incrementalId
----------- ----------- -------------
1           100         1
2           200         1
3           100         2
4           100         3
5           100         4
6           200         2

意思是我希望incrementalId每个类别自动递增,并为插入的任何新类别从1重新开始。我希望在表中的任何插入处自己完成此操作(我不想在插入此表时记得这样做)。

我认为这可以通过窗口函数或触发器来完成,但我不知道如何做到。

编辑:

我希望数据能够持久保存,以避免在发生数据删除时对增量ID进行移位。另外,理想情况下,在删除行的情况下,不会重新赋予相同的ID(与序列或IDENTITY的工作方式相同)

任何的想法 ?


阅读 217

收藏
2021-03-08

共1个答案

一尘不染

CREATE TABLE dbo.MyTable (
  myKey INT IDENTITY PRIMARY KEY,
  category INT,
  incrementalId INT
);
GO

create table dbo.nextCategoryID (
  category int,
  nextidvalue int,
  constraint PK_nextCategoryID primary key clustered( category, nextidvalue )
);
GO

create trigger numberByCategory on dbo.MyTable
after insert as

-- Automatically add any net new category
insert into dbo.nextCategoryID ( category, nextidvalue )
    select distinct category, 1 as nextidvalue
    from inserted
    where not exists ( select * from dbo.nextCategoryID s
        where s.category = inserted.category );


-- Number the new rows in each incoming category
with numberedrows as (
    select 
        i.myKey, 
        i.category, 
        n.nextidvalue - 1 + row_number() over ( partition by i.category order by i.category ) as incrementalId
    from inserted i
    join dbo.nextCategoryID n on i.category = n.category
)
update m
    set incrementalId = n.incrementalId
from dbo.MyTable m
join inserted i on m.myKey = i.myKey
join numberedrows n on n.myKey = i.myKey;


update dbo.nextCategoryID
    set nextidvalue = 1 + ( select max( m.incrementalId ) 
        from inserted i 
        join dbo.MyTable m on i.myKey = m.myKey
        where i.category = nextCategoryID.category 
    )
where exists ( select * 
    from inserted i
    where i.category = nextCategoryID.category
);

GO

-- Test data

INSERT INTO dbo.MyTable (category) VALUES (100);
INSERT INTO dbo.MyTable (category) VALUES (200);
INSERT INTO dbo.MyTable (category) VALUES (100);
INSERT INTO dbo.MyTable (category) VALUES (100);
INSERT INTO dbo.MyTable (category) VALUES (100);
INSERT INTO dbo.MyTable (category) VALUES (200);

insert into dbo.MyTable (category) 
values 
    ( 200 ),
    ( 200 ),
    ( 100 ),
    ( 300 ),
    ( 400 ),
    ( 400 )


SELECT *
FROM dbo.MyTable;
2021-03-08