程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SqlServer數據庫 >> 關於SqlServer >> 處理SQL 2008/08 中的OUTPUT與CHECK約束沖突的問題

處理SQL 2008/08 中的OUTPUT與CHECK約束沖突的問題

編輯:關於SqlServer

在SQL Server 2005中,新增的OUTPUT子句極大地提高了數據轉移的方便性,不過很遺憾的是, OUTPUT子句的輸出表不能包含啟用狀態的CHECK約束。這未免讓人覺得很不爽。不過,在實際使用過程中,卻發現了一個很奇怪的問題,某些具有啟用狀態的CHECK約束的表確實無法用於OUTPUT子句,而某些表卻是可以的,經過對比,發現了這個很奇怪現象的原因,使得可以把有啟用狀態的CHECK約束的表用於OUTPUT子句。

下面是演示的代碼:

USE tempdb;

GO

-- 建立測試表

CREATE TABLE dbo.tb_source(

    id int

);

 

CREATE TABLE dbo.tb_target(

    id int,

    CONSTRAINT CHK__tb_target__id

       CHECK(

           id > 0)

);

GO

 

-- OUTPUT 測試1

DELETE dbo.tb_source

    OUTPUT deleted.*

       INTO dbo.tb_target;

 

/*-- 會收到錯誤

消息333,級別16,狀態1,第3 行

OUTPUT INTO 子句的目標表'dbo.tb_target' 不能具有任何啟用的檢查約束或任何啟用的規則。找到檢查約束或規則'CHK__tb_target__id'。

--*/

GO

 

-- 禁用和啟用約束

ALTER TABLE dbo.tb_target

    NOCHECK CONSTRAINT ALL;

 

ALTER TABLE dbo.tb_target

    CHECK CONSTRAINT ALL;

GO

-- OUTPUT 測試2

DELETE dbo.tb_source

    OUTPUT deleted.*

       INTO dbo.tb_target;

      

/*-- 測試成功

 

(0 行受影響)

--*/

GO

 

-- 驗證CHECK 約束是否正常工作

INSERT dbo.tb_target

VALUES(

    -1);

/*-- 結果(違反約束)

消息547,級別16,狀態0,第3 行

INSERT 語句與CHECK 約束"CHK__tb_target__id"沖突。該沖突發生於數據庫"tempdb",表"dbo.tb_target", column 'id'。

語句已終止。

--*/

GO

 

 

-- 驗證OUTPUT 時, CHECK 約束是否正常工作

INSERT dbo.tb_source

VALUES(

    -1);

 

DELETE dbo.tb_source

    OUTPUT deleted.*

       INTO dbo.tb_target;

 

/*-- 結果(違反約束)

 

(1 行受影響)

消息547,級別16,狀態0,第6 行

DELETE 語句與CHECK 約束"CHK__tb_target__id"沖突。該沖突發生於數據庫"tempdb",表"dbo.tb_target", column 'id'。

語句已終止。

--*/

GO

 

 

-- 刪除測試

DROP TABLE dbo.tb_source, dbo.tb_target;

 

         從測試可以看出,只要CHECK約束是使用WITH NOCHECK啟用的,則可以作為OUTPUT子句的輸出表(與微軟給的錯誤提示信息顯示不一樣)。

         而且這種情況,同樣適用於使用WITH NOCHECK創建的約束,參考下面的腳本。

USE tempdb;

GO

 

-- 建立測試表

CREATE TABLE dbo.tb_source(

    id int

);

 

CREATE TABLE dbo.tb_target(

    id int

);

ALTER TABLE dbo.tb_target

    WITH NOCHECK

    ADD CONSTRAINT  CHK__tb_target__id

           CHECK(

              id > 0);

GO

 

-- OUTPUT 測試

DELETE dbo.tb_source

    OUTPUT deleted.*

       INTO dbo.tb_target;

 

/*-- 測試成功

 

(0 行受影響)

--*/

GO

-- 刪除測試

DROP TABLE dbo.tb_source, dbo.tb_target;

注:
         1. 默認情況下,建立約束使用的是WITH CHECK,而啟用約束使用的是WITH NOCHECK;
         2. WITH NOCHECK只是確定在建立(啟用)約束時,是否檢查表中的現有數據,對新進的數據沒有影響;
         3. WITH NOCHECK會導致分區視圖失敗。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved