2012-06-06 23 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

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