2012-06-06 3 views
3

У меня есть две таблицы, которые имеют одинаковые столбцы. Если происходит изменение, оно записывается в table2, а затем я сравниваю table1 с table2 и вижу, отличаются ли они. Если они разные, я пришел к выводу, что произошли изменения, и я хотел бы показать это в моей итоговой таблице.Отображение правильного условия, найденного в предложении 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

Как таблица1 обновляется? Просьба предоставить некоторые тестовые данные/сценарии, которые помогут нам понять. – 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 case позволяют сделать это без необходимости объединения с несколькими операторами выбора. – ganders

+1

Вы правы, но есть две причины, по которым я не стал бы использовать аргументы case. Во-первых, это приведет к изменению первого столбца, если изменилось более одного столбца. UNIONS предоставит вам все изменения. Во-вторых, что, по моему личному мнению, их труднее читать, чем СОЮЗ (хотя он может быть короче).Кроме того, если вы не хотите рассматривать 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 
    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

ну, а потом много хорошего хорошего сэр :) –

Смежные вопросы