2010-06-11 60 views
3

我知道這有點奇怪,但如果任何人有任何幫助,將不勝感激。使一個表等於另一個沒有刪除*

這種情況是我們在遠程站點有一個生產數據庫,在本地辦事處有一個開發人員數據庫。開發人員直接對開發人員數據庫進行更改,並且作爲C#應用程序運行的部署過程的一部分,並生成一系列可在遠程端執行的.sql腳本(實質上刪除*,插入),但我們正在尋找一些東西由於刪除*的停機時間是不可接受的,所以更詳細。這是控制主要網站菜單項,功能等的所有參考數據。

我有一個本質上返回兩個表的差異的sproc。我的想法是,我可以將所有預期的數據插入到tmp表中,執行diff,並從目標表中刪除不在源代碼中的任何內容,然後插入其他所有內容。

問題是,有沒有一種簡單的方法來做到這一點,而不使用遊標?爲了說明存儲過程返回結構類似這樣的記錄:

表名Col1中col2的COL3 目的地 的Src與表名=目的地記錄

任何應予以刪除(因爲它沒有在SRC存在)和任何東西Src應該被插入到dest中。我想不出一種純粹基於此設置的方式,但我的DB-fu很弱。

任何幫助,將不勝感激。如果解釋粗略,道歉;讓我知道你是否需要更多的細節。

+0

聽起來像使用SQL Server複製的候選人? – 2010-06-11 01:19:56

+0

我昨天剛剛問了一個類似的問題(但不是相同的)。我選擇使用Visual Studio 2010數據比較。 http://stackoverflow.com/questions/3012544/t-sql-is-there-a-free-way-to-compare-data-in-two-tables – RPM1984 2010-06-11 01:24:57

+0

我沒有選擇數據比較和我們仍然在SQL Server 2005上(所以沒有T-SQL MERGE)。由於我們只定期部署(有時每週一次,有時一個月一次),並且生產數據應該在這些時間之外保持不變,複製也不會有好處。 – 2010-06-11 01:31:49

回答

3

是的,該sproc會工作。對該表使用FULL JOIN並添加一列以指示插入,更新或刪除。然後根據列指示符爲它們創建單獨的SQL語句。基於設置。


對不起,沒有一個完整的聯接,你需要把它們分開來分開左和右聯接。在記事本這樣做,所以道歉,如果它不工作:

INSERT INTO tempDeployData(ID,IUDType) 
SELECT ed.id, 'D' 
FROM tmpDeployData td 
    RIGHT JOIN existingData ed ON td.id = ed.id 
WHERE td.id IS NULL  


UPDATE td 
SET td.IUDType = CASE WHEN ed.id IS NULL THEN 
         'I' 
         ELSE 
         'U' 
         END 
FROM tmpDeployData td 
    LEFT JOIN existingData ed ON td.id = ed.id 


INSERT INTO existingData(ID,a,b,c) 
SELECT td.ID,td.a,td.b,td.c 
FROM tmpDeployData td 
WHERE td.IUDType = 'I' 

DELETE ed 
FROM existingData ed 
    INNER JOIN tmpDeployData td ON ed.ID = td.ID 
WHERE td.IUDType = 'D' 

UPDATE ed 
SET  ed.a = td.a, 
     ed.b = td.b, 
     ed.c = td.c 
FROM existingData ed 
INNER JOIN tmpDeployData td ON ed.ID = td.ID 
WHERE td.IUDType = 'U' 

剛剛意識到你拉的信息到不是Temptable作爲一個臨時表,而不是數據的來源。在這種情況下,您可以使用FULL JOIN:

INSERT INTO tmpDeployData(ID,a,b,c,IUDType) 
SELECT sd.ID, 
     sd.a, 
     sd.b, 
     sd.c 
     'IUDType' = CASE WHEN ed.id IS NULL THEN 
         'I' 
         WHEN sd.id IS NULL THEN 
         'D' 
         ELSE 
         'U' 
         END 
FROM sourceData sd 
    FULL JOIN existingData ed ON sd.id = ed.id 

然後與之前相同的DML語句。

+0

這是'根據列指示符爲他們創建單獨的sql語句',我遇到了問題。我應該注意到,我試圖通用地處理它,因爲它需要完全在遠程站點執行,並且在部署之前無法訪問遠程/ prod數據。 你能提供樣品嗎? – 2010-06-11 00:54:53

+0

這很完美。非常感謝詳細的例子。 – 2010-06-11 03:04:20

1

假設您使用的是SQL Server 2008,有很多簡單的方法可以做到這一點:MERGE語句。

遷移從一個表到另一個的所有變化是非常簡單:

MERGE DestinationTable d 
USING SourceTable s 
    ON d.Id = s.Id 
WHEN MATCHED THEN UPDATE 
    SET d.Col1 = s.Col1, d.Col2 = s.Col2, ... 
WHEN NOT MATCHED BY TARGET THEN 
    INSERT (Id, Col1, Col2, ...) 
    VALUES (s.Id, s.Col1, s.Col2, ...) 
WHEN NOT MATCHED BY SOURCE THEN 
    DELETE; 

就是這樣。此後DestinationTable將與SourceTable相同。

+0

我希望我是。我們現在停留在2005年。 我不得不重新合併,本質上。 – 2010-06-11 02:57:58

+0

@Joshua:我看到你已經有了一個可行的答案,但是在將來,你應該在問題中提及你的版本,這樣人們就會意識到你的限制。更好的是,添加特定於版本的'sql-server-2005'標籤。 – Aaronaught 2010-06-11 14:15:10

+0

非常感謝Aaronaught - 我錯過了它。未來會得到它! – 2010-06-12 03:11:15

1

了在tablediff

表不需要參與複製到運行該實用程序。有一個美妙的-f開關產生的T-SQL把表「中同步」:

生成一個Transact-SQL腳本 把表在目標 服務器到融合與表 在源服務器。您可以 (可選)爲生成的Transact-SQL腳本 文件指定 的名稱和路徑。如果未指定file_name,則 實用程序運行的目錄中生成的Transact-SQL腳本文件爲 。

+0

看起來很棒。它會採取刪除/ upserts還是隻是架構更改?這不是很具體。無論如何,我不得不重新發明輪子,因爲我們沒有直接訪問生產的SQL服務器(我們提供他們的腳本來執行)。我懷疑我可以說服他們讓我們運行這個。 – 2010-06-11 02:59:35

+0

是的,會做插入/更新和刪除,取決於從源表的變化是什麼 – 2010-06-18 06:56:05

0

爲什麼不直接備份生產數據庫並將其恢復到開發數據庫?您應該更改生產數據庫中所有ddl差異的腳本,這些差異可以在還原後在數據庫上運行,並且會將部署測試爲生產。

編輯: 對不起,只需重新閱讀您的問題,它看起來像您將您的配置信息存儲在您的開發數據庫中,並從中生成您的更改腳本,所以這是行不通的。

我會建議手動創建更改腳本並將它們存儲在源代碼管理中。然後使用sqlcmd或osql和批處理文件在數據庫上運行更改腳本。

+0

嗨德克爾 - 這基本上就是我們所做的。問題是我們沒有權限訪問生產服務器,直到腳本運行,因此通過比較dev/prod生成更改腳本是不可能的。基本上需要在生產服務器上執行時動態生成更改腳本。 – 2010-06-12 03:13:12

相關問題