2016-09-14 9 views
1

インクリメンタルIDを含むテーブルを作成する必要がありますが、IDは他の列に従って自動的に分割されます。ここで私が欲しいものです:私はincrementalIdが自動的にカテゴリごとに増分され、挿入された新しいカテゴリの1から再起動することにしたい意味他の列でセグメント化された自動インクリメント列を作成する方法

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

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; 

私はこのようなものを表示したいと思います。私はこれをテーブル内の任意のインサートで実行する必要があります(このテーブルに挿入するときに覚えておく必要はありません)。

私はこれがウィンドウ関数とトリガーかもしれないと思いますが、私は方法を理解できません。

EDIT:

私はデータは、データの削除が発生した場合にシフトすることがincrementalIdを避けるために、永続化したいと思います。また、理想的には、同じIDが列削除の場合に再指定されません(シーケンスまたはIDENTITYと同じ方法)

ご存知ですか?

+0

カテゴリは無制限ですか? – scsimon

+0

@scsimonはい、いつでも追加できます。今日は50、次の月には55などがあります。 – MaxiWheat

+0

おそらくちょうど更新するより速く、インサートIMHOのロジックを処理する方が速いでしょう。 – scsimon

答えて

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; 
+0

すばらしい答えありがとうございます。同じような結果が、何らかの方法でSequence(または複数のシーケンス)を使ってインクリメンタルIDを生成することができるのだろうか – MaxiWheat

+0

可能ですが、すべてのカテゴリに対してシーケンスが必要です – onupdatecascade

+0

カテゴリが安定していると、 。そうでない場合は、それが実行可能かどうかを言うのは難しいです – onupdatecascade

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 
+0

データを後で簡単に照会できるようにしたいと思います。 – MaxiWheat

+0

実際のテーブルから 'view'を作成する方が良いと思います。 –

-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 

トリガーを使用しながら、2点を覚えておいてください - 1.あなたがいずれかを持っているかのように、我々は内部トリガーからテーブルを更新していますこのテーブルの他のトリガ(更新後)もそのトリガが実行されます。 2.単一選択クエリでこのテーブルに複数の行を挿入すると、このトリガは1回だけ実行されます。

CREATE TRIGGER dbo.UpdateIncrementalID 
ON dbo.MyTable 
AFTER INSERT 
AS 
     UPDATE x 
     SET incrementalId = ROW_NUMBER() OVER(PARTITION BY category ORDER BY myKey DESC) 
     FROM dbo.MyTable x 
+0

ちょうど間違って、同じカテゴリの多くの行に同じincrementalIdが与えられます。 – MaxiWheat

+0

このトリガーで私のテストの画像を追加しました。何かが足りない? – BhatiaAshish

+0

多くの行を一度に挿入するとどうなりますか?INSERT INTO dbo.MyTable(category)VALUES(100)、(100)、(100); ? – MaxiWheat

0

計算列から呼び出されます。

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])) 
); 
0

あなたが更新クエリの下

だUDFにKannanのソリューション@拡張
;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 
0

を使用して、同じテーブルを更新することができます:あなたは簡単にトリガを経由して、これを達成することができます

enter image description here

0

は、列のデフォルトの制約を作成してください。関数によって返されるデフォルト行として、行の次の値を生成する関数を使用します。

関連する問題