Oracle 支援 sequence, 可以每次呼叫時都得到不同的號碼. 請問在 SQL Server 上要如何達成?
我的做法是建一個 identity table (整個 table 只有 identity column) 每次插 default 然後取目前值. 但是如果應用程式同時呼叫的話, 無法保證每次給的都是不同的號碼. (batch 或是 multi-thread 的時候)
我的另一個方案是 identity + uid, 但是這樣一來 index 無用, table 大的時候就很有趣了. 請問有魚與熊掌兼得的方式嗎?
(不排斥使用 assembly, 不排斥 row level locking, 只要每次叫都可以拿到不同值就好了)
(同文發問在 ithome)
感恩
identity column "或許/可能"在某種程度上"建議"在同一個 table 的值是 unique 的, 但我無法保證對於新加入的 transaction, 10 個 table 都有一樣的 transactionid.
--
在 Oracle/DB2 上我可以用 row locking 來達成類似的需求, 但是 SQL Server 上我就找不到類似的方法了.
Oracle
- insert dummy
- select row id (非 row number)
- update dummy status where row id = rowid
- return id or update exception
CREATE TABLE [dbo].[test1](
[SEQ] [int] IDENTITY(1,1) NOT NULL,
[Value1] [varchar](20) NULL
)
GO
CREATE TABLE [dbo].[test2](
[SEQ] [int] NOT NULL,
[Value2] [varchar](20) NULL
)
GO
CREATE TABLE [dbo].[test3](
[SEQ] [int] NOT NULL,
[Value3] [varchar](20) NULL
)
GO
CREATE TRIGGER GetSEQ
ON test1
AFTER INSERT
AS
BEGIN
INSERT INTO test2
SELECT SEQ,'TEST' FROM inserted
INSERT INTO test3
SELECT SEQ,'TEST' FROM inserted
END
GO
INSERT INTO test1 (Value1) VALUES ('TEST')
GO
INSERT INTO test1 (Value1) VALUES ('TEST')
GO
INSERT INTO test1 (Value1) VALUES ('TEST')
GO
SELECT * FROM dbo.test1
SELECT * FROM dbo.test2
SELECT * FROM dbo.test3
請問如果我不只要每個 table 都有一樣的 transactionid, 這個 transactionid 還要返回給呼叫的應用程式該如何處理?
=== 原始問題
我有一個 transaction table, 應用程式(multi-thread)每次呼叫都要去 transaction table 找一個沒處理過的 transactionid 來處理: (sp 返回一個 cursor)
table: transaction
- transactionid number pk
- some other column (varchar, date, blob..etc)
我在 Oracle 的做法是建一個 lookup, 然後用 sequence 一個一個處理下去. (seq = id 找出對應的 transactionid, 然後處理)
table: lookup
- id identity (1,1)
- transactionid number unique
但在 SQL Server 上我並沒有辦法保證每次應用程式呼叫 sp 時, sp 每次都能給不同的值. 換句話說, 能否用 trigger 以外的方式達成原始的問題? (或是 SQL Server 上的 trigger 可以返回值給 app?)
CREATE TABLE [dbo].[test1](
[SEQ] [int] IDENTITY(1,1) NOT NULL,
[Value1] [varchar](20) NULL
)
GO
CREATE TABLE [dbo].[test2](
[SEQ] [int] NOT NULL,
[Value2] [varchar](20) NULL
)
GO
CREATE TABLE [dbo].[test3](
[SEQ] [int] NOT NULL,
[Value3] [varchar](20) NULL
)
GO
CREATE TRIGGER GetSEQ
ON test1
AFTER INSERT
AS
BEGIN
INSERT INTO test2
SELECT SEQ,'TEST' FROM inserted
INSERT INTO test3
SELECT SEQ,'TEST' FROM inserted
END
GO
CREATE PROCEDURE AddRecord
@VAR1 VARCHAR(200)
AS
BEGIN
DECLARE @OP TABLE(SEQ INT);
INSERT test1 (Value1)
OUTPUT inserted.SEQ INTO @OP
VALUES (@VAR1)
DECLARE @Ret INT
SELECT @Ret = SEQ FROM @OP
RETURN @Ret
END
GO
DECLARE @Ret INT
EXECUTE @Ret = AddRecord 'TEST'
SELECT @Ret
SELECT * FROM dbo.test1
SELECT * FROM dbo.test2
SELECT * FROM dbo.test3
如果可以接受output是一個dataset的話也可以用這個方式
DECLARE @Ret TABLE(SEQ INT);
INSERT test1
(Value1)
OUTPUT inserted.SEQ
INTO @Ret
VALUES ('TEST')
SELECT * FROM @Ret
SELECT * FROM dbo.test1
SELECT * FROM dbo.test2
SELECT * FROM dbo.test3