3

我有两个具有相同列的表。如果发生更改,则将其记录下来,table2然后我进行比较table1table2查看它们是否不同。如果它们不同,我断定发生了变化,我想在结果表中显示它。

例如:

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显示相关值。

有任何想法吗?

4

5 回答 5

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 来做,你可以用 UNIONS 来做,比如:

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 
.......
于 2012-06-06T18:26:11.903 回答
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
于 2012-06-06T18:07:54.303 回答
1

这是您的解决方案重写为单个 SELECT 语句(或者,如果您愿意,@ganders 的重写以支持同一行中的多个更改):

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
    …
  )
于 2012-06-09T21:10:41.123 回答
1

经过进一步的头脑风暴后,我得出结论,ganders 解决方案只需稍加改进即可更好地工作。改进是一个while循环和一个计数变量。我们需要这样做,以防一次更改多列而不仅仅是一列。但是,它也会导致输出 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
于 2012-06-07T17:45:20.957 回答
0

我使用name在 t2.name = t1.name 上添加了一个连接 @T2 t2到您的查询中。假设它可以用来链接两个表之间的记录。

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)
于 2012-06-06T18:26:54.867 回答