2012-06-06 21 views
3

我有兩個具有相同列的表。如果發生變化,則記錄在table2中,然後我將table1table2進行比較,看看它們是否不同。如果他們不同,我認爲這是一個變化,我想在我的結果表中顯示。顯示在WHERE子句中找到的正確條件

例如:

SELECT t1.name, t1.age, t1.profession, column_changed, old_value, new_value 
FROM table1 t1, table2 t2 
WHERE t1.column1<>t2.column1 
    OR t1.column2<>t2.column2 
    OR t1.column3<>t2.column3 

當然這個查詢是不正確的。我想column_changed,old_value,new_value顯示相關的值。

任何想法?

+0

如何table1得到更新?請提供一些測試數據/方案以幫助我們理解。 – ganders

+0

我不認爲這是相關的。如果我錯了,請解釋原因。 –

+0

是的,我重新讀你的問題。見下面的答案。 – ganders

回答

1

進一步頭腦風暴之後我已經得出結論,公鵝解決方案可有輕微的改良效果更好。改進是一個while循環和一個count變量。我們需要這樣做,以防萬一有多個列被更改,而不僅僅是一個。但是,它會導致輸出NULL,所以你可以刪除它們。下面是修改後的查詢:

WHILE @count<3 
BEGIN 
    Select t1.name, t1.age, t1.profession,  
    case when t1.column1 <> t2.column1 and @count = 1 then 'column1 changed'   
     when t1.column2 <> t2.column2 @count = 2 then 'column2 changed'   
     -- and so on...   
    end as [column_changed],  
    case when t1.column1 <> t2.column1 @count = 1 then t1.column1   
     when t1.column2 <> t2.column2 @count = 2 then t1.column2   
     -- and so on...   
    end as [old_value],  
    case when t1.column1 <> t2.column1 @count = 1 then t2.column1   
     when t1.column2 <> t2.column2 @count = 2 then t2.column2   
     -- and so on...   
    end as [new_value] 
    From table1 t1, table2 t2 
    Where t1.column1 <> t2.column1 Or t1.column2 <> t2.column2 Or t1.column3 <> t2.column3 
    SET @counter = @counter + 1 
END 
1

試試這個:

Select t1.name, t1.age, t1.profession, 
    case when t1.column1 <> t2.column1 then 'column1 changed' 
     when t1.column2 <> t2.column2 then 'column2 changed' 
     -- and so on... 
     end as [column_changed], 
    case when t1.column1 <> t2.column1 then t1.column1 
     when t1.column2 <> t2.column2 then t1.column2 
     -- and so on... 
     end as [old_value], 
    case when t1.column1 <> t2.column1 then t2.column1 
     when t1.column2 <> t2.column2 then t2.column2 
     -- and so on... 
     end as [new_value] 
From table1 t1, table2 t2 
Where t1.column1 <> t2.column1 
Or t1.column2 <> t2.column2 
Or t1.column3 <> t2.column3 
2

沒有年齡,姓名,職業構成主鍵(或至少一個唯一的鑰匙?):

如果是這樣,你可以這樣做:

SELECT 
    t1.name, t1.age, t1.profession, 
    t1.column1 as t1column1, t2.column1 as t2column1, 
    t1.column2 as t1column2, t2.column2 as t2column2, 
FROM 
    table1 t1, table2 t2 
WHERE 
    (t1.name = t2.name and t1.age = t2.age and t1.profession = t2.profession) and 
    (
    t1.column1<>t2.column1  
    OR t1.column2<>t2.column2  
    OR t1.column3<>t2.column3) 

當然,這需要一個在兩個表中都相同的唯一鍵。另外,我清楚地更改了查詢的結果,以顯示所有列,而不是僅顯示已更改的列。在單個T-SQL查詢中識別出那樣的變化是尷尬的(但可能),所以我的建議是像這樣返回它,根據您的使用情況,應用程序/表示層可以處理查找哪列更改或只是掃描它的眼睛。

如果你真的想這樣做在T-SQL,您可以與工會做到這一點,如:

SELECT 
    t1.name, t1.age, t1.profession, 
    'column1' as ColumnChanged, 
    t1.column1 as oldValue, 
    t2.column1 as newValue 
FROM 
    table1 t1, table2 t2 
WHERE 
    (t1.name = t2.name and t1.age = t2.age and t1.profession = t2.profession) and 
    t1.column1<>t2.column1 
UNION ALL #better peformance than UNION, which would enforce uniqueness 
SELECT 
    t1.name, t1.age, t1.profession, 
    'column2' as ColumnChanged, 
    t1.column2 as oldValue, 
    t2.column2 as newValue 
FROM 
    table1 t1, table2 t2 
WHERE 
    (t1.name = t2.name and t1.age = t2.age and t1.profession = t2.profession) and 
    t1.column2<>t2.column2 
....... 
+2

case語句允許在不需要使用多個select語句進行聯合的情況下完成此操作。 – ganders

+1

你是對的,但有兩個原因,我不會去使用case語句。首先,如果多個列已經改變,它只會給你改變的第一列。工會會給你所有的改變。第二,就我個人的觀點而言,他們比聯盟更難閱讀(儘管可能會更短)。另外,除非你想查看ColumnX的每一行,否則你仍然需要在某個地方進行唯一鍵比較...... – TimothyAWiseman

+0

你說得很對。我想過使用CASE語句,但要進行所有更改(如果兩列更改而不是一個)將需要多個嵌套CASE,因此UNION ALL在這裏可能更好。 –

0

我加了一個加入@ T2 T2上t2.name = t1.name到您的查詢使用名稱列。假定它可以用來鏈接兩個表之間的記錄。

select 
    t1.name, t1.age, t1.profession, 
    column_change = 
     case when t1.column1 <> t2.column1 then 'column1' 
      when t1.column2 <> t2.column2 then 'column2' 
      when t1.column3 <> t2.column3 then 'column3' 
     end, 
    old_value = 
     case when t1.column1 <> t2.column1 then t1.column1 
      when t1.column2 <> t2.column2 then t1.column2 
      when t1.column3 <> t2.column3 then t1.column3 
     end, 
    new_value = 
     case when t1.column1 <> t2.column1 then t2.column1 
      when t1.column2 <> t2.column2 then t2.column2 
      when t1.column3 <> t2.column3 then t2.column3 
     end 
from @T1 t1 
    join @T2 t2 on t2.name = t1.name 
where 
    (t1.column1 <> t2.column1 
    or t1.column2 <> t2.column2 
    or t1.column3 <> t2.column3) 
1

這裏是你的解決方案改寫爲一個單一的SELECT語句(或者,如果你喜歡,@公鵝的改寫,以支持在同一行中一些變化):

SELECT 
    x.column_changed, 
    t1.column1 AS old_value, 
    t2.column1 AS new_value 
FROM table1 t1 
    INNER JOIN table2 t2 ON t1.name = t2.name 
    INNER JOIN (
    SELECT 'column1' UNION ALL 
    SELECT 'column2' UNION ALL 
    … 
) x (column_changed) ON (
    x.column_changed = 'column1' AND t1.column1 <> t2.column1 OR 
    x.column_changed = 'column2' AND t1.column2 <> t2.column2 OR 
    … 
) 
+0

你不認爲它比案件陳述更復雜? –

+0

事實上,不,我不認爲這比在解決方案中使用兩個CASE表達式更復雜。但即使我這樣做了,那不是我的觀點。我只是想提出一個使用純粹基於集合的方法的解決方案。 –

+0

好吧,那麼很好,先生好:) –