2010-01-25 101 views
19

基本上我們有一個表(original table),它被備份到另一個表(backup table);因此這兩個表具有完全相同的模式。如何驗證兩個表是否具有完全相同的數據?

在開始時,兩個表(original tablebackup table)都包含完全相同的一組數據。由於某種原因,我需要驗證original table中的數據集是否已更改。

爲了做到這一點,我必須將original table中的數據集與backup table進行比較。

比方說,有original table下面的模式:

create table LemmasMapping (
    lemma1 int, 
    lemma2 int, 
    index ix_lemma1 using btree (lemma1), 
    index ix_lemma2 using btree (lemma2) 
) 

我怎麼能實現數據集中的比較呢?

更新:該表沒有主鍵。它只是存儲兩個ID之間的映射。

回答

13

我會寫三個查詢。

  1. 一個內部聯接來選取兩個表中存在主鍵的行,但是其中一個或多個其他列的值存在差異。這會在原始文件中選取更改的行。

  2. 左外部連接可以選取原始表中但不在備份表中的行(即原始行中有一個主鍵在備份中不存在)。這將返回插入原始的行。

  3. 一個右外連接來拾取原始中不再存在的備份行。這將返回已從原始刪除的行。

您可以將三個查詢合併在一起以返回單個結果集。如果你這樣做了,你需要添加一個列來指明它是哪種類型的行(更新,插入或刪除)。

經過一番努力,您可能可以在一個查詢中使用完全外連接完成此操作。小心外連接,因爲它們在不同的SQL引擎中表現不同。將謂詞放在where子句中,而不是join子句有時可以將外部聯接轉換爲內部聯接。

+0

這工作。謝謝! – 2010-01-25 01:58:11

+2

「*小心外連接,因爲它們在不同的SQL引擎中表現不同*」 - 請注意解釋這一點嗎?我沒有看到任何DBMS在使用外連接時會做不同的事情。 「*謂詞放在where子句中,而不是join子句有時可以將外部聯接變成內部聯接*」 - 當然,如果這些謂詞使用「外部表」中的列,他們會這樣做。當將空值與常數值進行比較時,具有空值的行將被丟棄。 – 2014-07-30 13:26:09

+0

邁克,請你提供查詢。謝謝^^ – stacheldraht27 2016-05-11 08:00:32

1
select count(*) 
from lemmas as original_table 
     full join backup_table using (lemma_id) 
where backup_table.lemma_id is null 
     or original_table.lemma_id is null 
     or original_table.lemma != backup_table.lemma 

完全加入/檢查null應包括添加或刪除以及更改。

  • backup.id爲null =此外
  • original.id爲null =刪除
  • 沒有空=變化
+0

好主意,除了MySQL不支持完整的外連接。 – 2014-07-30 13:20:49

28

您可以使用CHECKSUM TABLE並比較結果。您甚至可以使用alter the table以啓用實時校驗和,以便它們持續可用。

CHECKSUM TABLE original_table, backup_table; 

它不要求表具有主鍵。

+1

校驗和爲+1 – 2010-01-25 01:57:50

+3

注意,即使校驗和相同,表格也可能不同。 – 2014-07-07 04:49:41

+0

顯然是PostgreSQL中沒有的功能。 – 2014-07-29 09:31:04

0

對於使用MS SQL Server的懶惰或更多的SQL厭惡開發人員,我會推薦SQL Delta(www.sqldelta.com)用於這個以及任何其他數據庫差異類型的工作。它有一個偉大的GUI,快速而準確,可以區分所有數據庫對象,生成並運行必要的更改腳本,同步整個數據庫。它是DBA的下一個最好的東西;-)

我認爲有一個類似的工具可以從RedGate調用SQL Compare。我相信的一些版本的Visual Studio(2010)的最新版本也包含一個非常類似的工具。

+0

更新 - 我一直在使用VS2010中的數據比較工具,並且他們不適合喜歡以上任一產品的靴子...... – 5arx 2010-05-11 13:35:07

15
SELECT * FROM Table1 
UNION 
SELECT * FROM Table2 

如果您獲得的記錄大於兩個表中的任意一個,則它們不具有相同的數據。

+0

難道不是'從T2'的T1 union select count(*)中選擇count(*)? – nvlass 2012-12-13 18:22:01

+0

不幸的是,沒有。這只是需要計數的聯合,所以如果他們有相同的計數,那將只有一行。 – crunkchitis 2013-04-05 22:49:36

+0

當你說*記錄大於兩個表中的任何一個時,它們沒有相同的數據*你的意思是如果表a有20行,而表b有20行,如果他們聯合產生超過20行然後表a和表b不一樣嗎? – gh0st 2015-08-25 16:22:41

1

請嘗試以下方法比較兩個表:

SELECT 'different' FROM DUAL WHERE EXISTS(
    SELECT * FROM (
     SELECT /*DISTINCT*/ +1 AS chk,a.c1,a.c2,a.c3 FROM a 
     UNION ALL 
     SELECT /*DISTINCT*/ +1 AS chk,b.c1,b.c2,b.c3 FROM b 
    ) c 
    GROUP BY c1,c2,c3 
    HAVING SUM(chk)<>2 
) 
UNION SELECT 'equal' FROM DUAL 
LIMIT 1; 
0

請嘗試以下方法來確定,如果兩個表是完全一樣的,當有任何形式的主鍵,還有內不重複的行一個表中,使用下面的邏輯:

步驟1 - 試驗重複上TABLEA行

如果SELECT DISTINCT * FROM TABLEA

具有相同的行數爲

SELECT * FROM TABLEA

然後進入下一個步驟,否則你無法使用此方法...

第2步 - 試驗重複在TABLEB行

如果SELECT DISTINCT * FROM TABLEB

具有相同的行數爲

SELECT * FROM TABLEB

然後進入下一個步驟,否則你無法使用此方法...

第3步 - INNER JOIN TABLEA到TABLEB每列

如果下面的查詢的行數具有相同的行數從步驟1和2中的行數,則該表是相同的:

SELECT 
* 

FROM 
TABLEA 

INNER JOIN TABLEA ON 
TABLEA.column1 = TABLEB.column1 
AND TABLEA.column2 = TABLEB.column2 
AND TABLEA.column3 = TABLEB.column3 
--etc...for every column 

注意,此方法d沒有必要測試不同的數據類型,並且可能不適用於不可連接的數據類型(如VARBINARY)

反饋歡迎!

相關問題