簡體   English   中英

如何在沒有序列的情況下自動遞增SQL Server 2016合並插入中的主鍵?

[英]How can I auto increment the primary key in SQL Server 2016 merge insert without sequences?

我正在編寫一個查詢來將數據從一個表導入到一個新表中。 我需要插入新表中不存在的記錄,並更新確實存在的記錄。 我正在嘗試使用MERGE“upsert”方法。

由於客戶端的數據庫和應用程序結構,我有一些獨特的問題。 我插入的表有一個唯一ID字段,每個新行增加1,但表不執行自動遞增; insert語句需要拉出目標表中的最高ID,並為新記錄添加1。

根據我的研究,我無法弄清楚如何用MERGE做到這一點。 我沒有數據庫權限來創建序列。 我嘗試了很多東西,但目前我的查詢看起來像:

MERGE
    dbo.targetTable as target
USING
    dbo.sourceTable AS source
ON
    target.account_no = source.account_ID

WHEN NOT MATCHED THEN
    INSERT (
        ID,
        FIELD1,
        FIELD2,
        FIELD3
) VALUES (
        (SELECT MAX(ID) + 1 FROM dbo.targetTable),
        'field1',
        'field2',
        'field3'
)

我遇到這個代碼的問題是它似乎只運行一次新ID的select語句。 也就是說,如果目標表中的最高ID是10,它將插入ID為11的每個新記錄。這將無法正常工作,因為我收到Violation of PRIMARY KEY constraint. Cannot insert duplicate key in object Violation of PRIMARY KEY constraint. Cannot insert duplicate key in object錯誤中Violation of PRIMARY KEY constraint. Cannot insert duplicate key in object 我一直在做大量的谷歌搜索和嘗試不同的東西,但無法弄清楚這一點。 感謝任何幫助,謝謝。

編輯:為了澄清,唯一ID列不會自動填充。 如果我沒有為ID列插入值,我得到的Cannot insert the value NULL into column 'ID', table 'dbo.targetTable'; column does not allow nulls. UPDATE fails. Cannot insert the value NULL into column 'ID', table 'dbo.targetTable'; column does not allow nulls. UPDATE fails.

而且,正如我最初提到的,我沒有創建序列的權限。 它只是拋出一個錯誤,並說我沒有這樣做的許可。

我同意將ID列自動更改為自動增量是完美的,但我沒有能力像這樣修改表格。

如果您不需要連續的ID,則可以將最后一個可用ID添加到ROW_NUMBER()以生成新的非重復ID。

BEGIN TRANSACTION

    DECLARE @NextAvailableID INT = (SELECT ISNULL(MAX(ID), 0) FROM dbo.targetTable WITH (TABLOCKX))

    ;WITH SourceWithNewIDs AS
    (
        SELECT
            S.*,
            NewID = @NextAvailableID + ROW_NUMBER() OVER (ORDER BY S.account_ID)
        FROM
            dbo.sourceTable AS S
    )
    MERGE
        dbo.targetTable as target
    USING
        SourceWithNewIDs AS source
    ON
        target.account_no = source.account_ID
    WHEN NOT MATCHED THEN
        INSERT (
            ID,
            FIELD1,
            FIELD2,
            FIELD3
    ) VALUES (
            NewID,
            'field1',
            'field2',
            'field3'
    )

COMMIT

請記住,此示例缺少使用回滾的正確錯誤處理,並且用於檢索最大ID的鎖將阻止所有其他操作,直到提交或回滾。

如果您需要新行具有連續的ID,那么您可以使用相同的方法使用常規INSERT (使用WHERE NOT EXISTS... )而不是MERGE (必須單獨編寫UPDATE )。

這不是使用Merge的另一種方式。 臨時表不需要權限,因此我將使用一個來保存需要插入的帳號,並使用標識字段來幫助進行遍歷。 while循環可以遍歷標識,將關於源表的account_no-的值插入到目標表中。 由於插入是在循環中完成的,因此MAX函數應該在每個循環上正確地獲取目標表的MAX(account_no)

DECLARE @tempTable TABLE (pkindex int IDENTITY(1,1) PRIMARY KEY, account_no int)
DECLARE @current int = 1
       ,@endcount int = 0

--account_no's that should be inserted
INSERT INTO @tempTable(account_no)
SELECT account_no 
  FROM sourceTable 
 WHERE account_no NOT IN (SELECT account_no FROM targetTable)

SET @endcount = (SELECT COUNT(*) FROM @tempTable)

--looping condition, should select the MAX(ID) with each subsequent loop
WHILE (@endcount > 0) AND (@current <= @endcount)
BEGIN
INSERT INTO dbo.targetTable(ID, FIELD1, FIELD2, FIELD3)
SELECT (SELECT MAX(T2.ID) + 1 FROM dbo.targetTable T2) AS MAXID
      ,S.field1
      ,S.field2
      ,S.field3
  FROM @tempTable T INNER JOIN sourceTable S ON T.account_no = S.account_no
 WHERE T.pkindex = @current --traversing temp table by its identity

SET @current += 1

END

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM