Sql-Server

如何用數據庫備份中的標識主鍵列替換單個表?

  • April 25, 2017

我需要從備份中恢復表。我的理解是將單個表重新放入數據庫的唯一方法是將其複製到臨時表中。然後刪除舊表並將新表重命名為舊名稱。由於主鍵列是身份列,因此我的問題與此特定步驟有關。該表還具有多個外鍵約束。如何將備份數據庫中的一張表複製到原始數據庫中,同時保持主鍵標識列和所有外部約束?

這是我目前的腳本嘗試:

CREATE TABLE dbo.Incidents_tmp
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[IncidentAction_ID] [int] NULL,
[IncidentCompromise_ID] [int] NULL,
[IncidentDamage_ID] [int] NULL,
[IncidentReportingEntity_ID] [int] NULL,
[IncidentStatus_ID] [int] NULL,
[IncidentType_ID] [int] NULL,
[IncidentID] [varchar](20) NULL,
[Version] [timestamp] NOT NULL,
CONSTRAINT [PK_Incidents_tmp] PRIMARY KEY CLUSTERED 
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

SET IDENTITY_INSERT dbo.Incidents_tmp ON
GO

IF EXISTS ( SELECT * 
       FROM DB_old.dbo.Incidents )
INSERT INTO DB_new.dbo.Incidents_tmp 
       ( 
       ID ,
       IncidentAction_ID ,
       IncidentCompromise_ID ,
       IncidentDamage_ID ,
       IncidentReportingEntity_ID ,
       IncidentStatus_ID ,
       IncidentType_ID ,
       IncidentID 
       )
   SELECT 
   ID ,
   IncidentAction_ID ,
   IncidentCompromise_ID ,
   IncidentDamage_ID ,
   IncidentReportingEntity_ID ,
   IncidentStatus_ID ,
   IncidentType_ID ,
   IncidentID ,
   FROM DB_old.dbo.Incidents TABLOCKX
GO

SET IDENTITY_INSERT DB_new.dbo.Incidents_tmp OFF
GO

ALTER TABLE dbo.IncidentSubject DROP CONSTRAINT 
FK_IncidentSubject_Incidents;
ALTER TABLE dbo.IncidentsReportLog DROP CONSTRAINT 
FK_IncidentsReportLog_Incidents;
ALTER TABLE dbo.Incidents DROP CONSTRAINT PK_Incidents;

DROP TABLE DB_new.dbo.Incidents
GO

Exec sp_rename 'Incidents_tmp', 'Incidents'

Exec sp_rename 'PK_incidents_tmp', 'PK_Incidents'


ALTER TABLE [dbo].[IncidentSubject]  WITH CHECK ADD  CONSTRAINT 
[FK_IncidentSubject_Incidents] FOREIGN KEY([Incident_ID])
REFERENCES [dbo].[Incidents] ([ID])
ON DELETE CASCADE
GO

ALTER TABLE [dbo].[IncidentSubject] CHECK CONSTRAINT 
[FK_IncidentSubject_Incidents]
GO

當我嘗試重新添加約束時,我收到一條錯誤消息:

Msg 547, Level 16, State 0, Line 1
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_IncidentSubject_Incidents". The conflict occurred in database "DB_new", table "dbo.Incidents", column 'ID'.

編輯:一些附加資訊。此應用程序的使用者意外刪除了 175 個事件。不幸的是,她直到兩週後才告訴我們,然後直到將近一個月後才發送給我們。使用者一直在訪問應用程序並進行更改,因此無法選擇完整的數據庫還原。使用者請求僅恢復已刪除的事件。我查看了數據庫並註意到一個事件表,其中包含目前數據庫中的缺失數據和備份數據庫中存在的 175 條記錄。希望這為我為什麼要嘗試僅還原單個事件表提供一些更好的上下文。它開始看起來需要恢復其他表。

根據您在問題中提供的資訊,我認為您需要將良好的備份(缺少事件的行)恢復到測試數據庫中。您需要將 Incidents 表的備份版本中缺少的行插入到真實的目前 Incidents 表中(確保正確使用SET IDENTITY_INSERT命令)。使用 SET IDENTITY_INSERT ON 允許將顯式值插入到表的標識列中,從而允許您插入已刪除的行。確保在完成插入後發出 SET IDENTITY_INSERT OFF。您需要對要恢復的每個父行的子表進行完全相同的比較和插入,因為在刪除父行時會自動刪除子表(由於級聯刪除 FK)。

處理完所有子表後,您應該可以使用CHECK.

您可能希望在測試伺服器上對此進行原型設計。

--Demo IDENTITY_INSERT
--Create test table
IF OBJECT_ID('dbo.TestTable') IS NOT NULL
   DROP TABLE dbo.TestTable
GO

CREATE TABLE [dbo].[TestTable] (
   TestId INT identity(1, 1) NOT NULL
   ,TestColumn VARCHAR(5)
   ) ON [PRIMARY]
GO

--insert a few test rows
INSERT INTO TestTable (TestColumn)
VALUES ('one'),('Two')

--select the two rows - the id values will be 1 and 2
SELECT * FROM TestTable

--delete the two rows
DELETE FROM testtable

--set identity_insert on to allow you to explicitly insert id values
SET IDENTITY_INSERT dbo.TestTable ON

--insert id 1 and 2
INSERT INTO TestTable (TestId,TestColumn)
VALUES (1,'one'),(2,'Two')

--set identity_insert off
SET IDENTITY_INSERT dbo.TestTable OFF

--select the current rows - should be id 1 and 2
SELECT * FROM TestTable

引用自:https://dba.stackexchange.com/questions/171959