如何创建由其他列分段的自动增量列

时间:2016-09-14 19:57:12

标签: sql sql-server tsql auto-increment

我需要创建一个包含增量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每个类别自动递增,并从插入的任何新类别重新开始。我希望这可以在表中的任何插入中自行完成(我不想在我在此表中插入时记住这样做)。

我认为这可能是通过窗口函数完成的,也许是触发器,但我无法弄清楚如何。

修改

我希望保留数据,以避免在发生数据删除时移动incrementalId。此外,理想情况下,如果删除行,则不会重新给出相同的ID(与序列或IDENTITY的工作方式相同)

有什么想法吗?

7 个答案:

答案 0 :(得分:2)

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;

答案 1 :(得分:0)

我认为您不需要在表格中添加额外的列“IncrementalID”。

您可以在select语句中进行此操作。

SELECT myKey,category,ROW_NUMBER() OVER(PARTITION BY category ORDER BY myKey )incrementalId
FROM MyTable
ORDER BY myKey

样本输出。

enter image description here

否则,您可以从实际表格中创建视图。

CREATE VIEW dbo.VIEW_MyTable 
 AS
  SELECT myKey,category,ROW_NUMBER() OVER(PARTITION BY category ORDER BY myKey )incrementalId
    FROM MyTable
    ORDER BY myKey

答案 2 :(得分:0)

您可以通过触发器轻松实现此目的:

Help -> Check for Updates...

答案 3 :(得分:0)

您可以使用以下更新查询

更新同一个表格
;with cte as (
select mykey, category, incrementalid, row_number() over (partition by category order by mykey,category) as rn from MyTable
)
update cte
set incrementalId = rn

答案 4 :(得分:0)

将@ Kannan的解决方案扩展到从计算列调用的UDF中:

create function dbo.fnsPartId(@mykey int)
returns int
as
begin
    declare @Ret int
    ;
    with
    enum as
    (
        select mykey, category, incrementalid, 
            row_number() over (partition by category order by mykey, category) as rn 
            from MyTable
    )
    select @Ret = rn from enum where mykey = @mykey
    return @Ret
end 

将表格修改为:

CREATE TABLE dbo.MyTable (
    myKey INT IDENTITY PRIMARY KEY,
    category INT,
    incrementalId AS ([dbo].[fnsPartId]([mykey]))
);

答案 5 :(得分:0)

尝试在列上创建默认约束。使用函数为该行生成下一个值作为函数返回的默认行。

答案 6 :(得分:-2)

请尝试这个(在此表上插入触发器后添加) -

create trigger InsertIncrementalID
on dbo.MyTable
after insert
as
begin
    update  mt
    set     incrementalId = (select count(mt1.category) from dbo.MyTable mt1 where mt1.category = mt.category)
    from    dbo.MyTable mt
    inner join inserted i on i.myKey = mt.myKey
end

使用触发器时请记住两点 - 1.我们正在从内部触发器更新表,所以如果你在这个表上有任何其他触发器(更新后),那么该触发器也将被执行。 2.使用单选查询在此表中插入多行时,此触发器仅执行一次。

enter image description here