2015-10-13 58 views
0

如何使用默认约束,触发器或其他某种机制自动从序列中将多个连续值插入到表的同一行的多个列中?使用序列填充连续值的多个列

SQL Server中序列的标准用法是将其与多个表上的默认约束组合,以基本上获得一个跨表标识。请参阅Microsoft文档文章“Sequence Numbers”中的“C.在多个表中使用序列号”一节。

如果您只想从插入的每行的序列中获取单个值,此功能非常有用。但有时我想获得多个连续的值。所以理论上我将创建一个这样的序列和表:

CREATE SEQUENCE DocumentationIDs; 

CREATE TABLE Product 
    (
     ProductID BIGINT NOT NULL IDENTITY(1, 1) PRIMARY KEY 
    , ProductName NVARCHAR(100) NOT NULL 
    , MarketingDocumentationID BIGINT NOT NULL DEFAULT (NEXT VALUE FOR DocumentationIDs) 
    , TechnicalDocumentationID BIGINT NOT NULL DEFAULT (NEXT VALUE FOR DocumentationIDs) 
    , InternalDocumentationID BIGINT NOT NULL DEFAULT (NEXT VALUE FOR DocumentationIDs) 
    ); 

不幸的是这将在所有三列中插入相同的值。这是by design

如果对于函数指定单个Transact-SQL语句在同一个序列发生器的下一个值的多个实例,所有这些实例以供该处理的给定行返回相同的值的Transact SQL语句。这种行为符合ANSI标准。

增量由黑客

唯一suggestion我能在网上找到了用一个黑客,你必须通过你需要(我人为的例子三)插入的列数的顺序增量,手动添加到NEXT VALUE FOR功能在默认约束:

CREATE SEQUENCE DocumentationIDs START WITH 1 INCREMENT BY 3; 

CREATE TABLE Product 
    (
     ProductID BIGINT NOT NULL IDENTITY(1, 1) PRIMARY KEY 
    , ProductName NVARCHAR(100) NOT NULL 
    , MarketingDocumentationID BIGINT NOT NULL DEFAULT (NEXT VALUE FOR DocumentationIDs) 
    , TechnicalDocumentationID BIGINT NOT NULL DEFAULT ((NEXT VALUE FOR DocumentationIDs) + 1) 
    , InternalDocumentationID BIGINT NOT NULL DEFAULT ((NEXT VALUE FOR DocumentationIDs) + 2) 
    ) 

但这不是为我工作,因为使用并不是所有的表我的SE quence需要相同数量的值。

+0

无法你只是使用另一个序列的其他表?他们是如何相关的,他们需要相同的序列?第二种解决方案是增加最大数量的列像10,这应该满足所有表,但你会得到空白。 – lad2025

回答

1

使用AFTER INSERT触发器的一种可能方式如下。

表定义需要进行slighlty改变(DocumentationID列应被默认为0,或允许可为空):

CREATE TABLE Product 
    (
     ProductID BIGINT NOT NULL IDENTITY(1, 1) 
    , ProductName NVARCHAR(100) NOT NULL 
    , MarketingDocumentationID BIGINT NOT NULL CONSTRAINT DF_Product_1 DEFAULT (0) 
    , TechnicalDocumentationID BIGINT NOT NULL CONSTRAINT DF_Product_2 DEFAULT (0) 
    , InternalDocumentationID BIGINT NOT NULL CONSTRAINT DF_Product_3 DEFAULT (0) 
    , CONSTRAINT PK_Product PRIMARY KEY (ProductID) 
    ); 

和触发做的工作是以下几点:

CREATE TRIGGER Product_AfterInsert ON Product 
AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    IF NOT EXISTS (SELECT 1 FROM INSERTED) 
     RETURN; 

    CREATE TABLE #DocIDs 
     (
     ProductID BIGINT NOT NULL 
     , Num INT NOT NULL 
     , DocID BIGINT NOT NULL 
     , PRIMARY KEY (ProductID, Num) 
     ); 

    INSERT INTO #DocIDs (ProductID, Num, DocID) 
     SELECT 
      i.ProductID 
      , r.n 
      , NEXT VALUE FOR DocumentationIDs OVER (ORDER BY i.ProductID, r.n) 
     FROM INSERTED i 
      CROSS APPLY (VALUES (1), (2), (3)) r(n) 
      ; 

    WITH Docs (ProductID, MarketingDocID, TechnicalDocID, InternalDocID) 
    AS (
     SELECT ProductID, [1], [2], [3] 
     FROM #DocIDs d 
      PIVOT (MAX(DocID) FOR Num IN ([1], [2], [3])) pvt 
    ) 
    UPDATE p 
    SET 
     p.MarketingDocumentationID = d.MarketingDocID 
     , p.TechnicalDocumentationID = d.TechnicalDocID 
     , p.InternalDocumentationID = d.InternalDocID 
    FROM Product p 
     JOIN Docs d ON d.ProductID = p.ProductID 
     ; 

END 
+0

_upd:_然而,这样的设计看起来有点奇怪。通常,如果你有'文档'表,它应该有身份PK列。有了这个,你首先插入到这个表中,然后使用'Documentation'中的ID插入(或更新)'Product'中的记录。 –