2015-10-13 61 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'中的記錄。 –