Обновить таблицу через соединение без ключевого отношения

Что у меня есть:

Две таблицы A и B.

A: Col1 Col2 Col3 Col1_Transformed Col2_Transformed

B: Col1 Col2 Col3

У них точно такие же столбцы, за исключением некоторых измененных данных, ни у одного из них нет первичного ключа, уникального поля или чего-то еще (это крайний случай, который мне нужно обработать).

Таблица A содержит только часть данных из таблицы B. Допустим, я читаю таблицу B партиями по 10000 строк, затем изменяю данные и записываю их в таблицу A (столбцы * _Transform).

Что мне нужно:

Мне нужно обновить таблицу B, используя данные из таблицы A. Будет легко иметь первичный ключ или какой-либо столбец идентификаторов:

UPDATE target
SET  target.Col1 = source.__Col1
FROM B target
join A as source 
ON  target.Id = source.Id  

Но у меня их нет.

Следующее естественное предположение - использовать естественный ключ, сформированный из Col1 Col2 Col3.

UPDATE target
SET  target.Col1 = source.__Col1
FROM B target
join A as source 
ON  target.Col1 = source.Col1  AND 
    target.Col2 = source.Col2  AND 
    target.Col3 = source.Col3 

Это не сработает, причина в возможном сравнении значения NULL. Если target.Col1 или source.Col1 имеет значение NULL, то вся запись исключается из обновления.

Предположение № 3 (используя номер строки):

Я хочу добавить row_number в таблицу A, это будет мой ключ.

A: row_numb Col1 Col2 Col3 Col1_Transformed Col2_Transformed

И чем просто присоединиться к таблице B:

UPDATE target
SET  target.Col1 = source.__Col1
FROM B target
join A as source 
ON  ROW_NUMBER() OVER(ORDER BY target.Col1,target.Col2,target.Col3) = source.ROW_NUMB  

Bur row_nubmer нельзя использовать в предложении соединения.

Есть идеи, как это сделать?


person makambi    schedule 17.11.2014    source источник
comment
Ваш вопрос непонятен. Кажется, вы хотите добавить увеличивающееся целое число в таблицу B? Можете ли вы просто добавить новый столбец и установить для свойства identity значение true?   -  person Sean Lange    schedule 17.11.2014
comment
Вы можете использовать Coalesce в опции # 2 или использовать общее табличное выражение и Row_number для # 3   -  person sqlhdv    schedule 17.11.2014
comment
@ sean-lange, я не могу изменить таблицу B. Никаких изменений в существующей схеме, таблица A - это просто временная таблица #A.   -  person makambi    schedule 17.11.2014
comment
@sqlhdv, хотя про Coalesce. Не знаю, как это сделать с CTE в 3-м случае, вы можете показать пример?   -  person makambi    schedule 17.11.2014


Ответы (2)


Похоже, вы хотите, чтобы NULL соответствовал объединениям, вы можете сделать это:

UPDATE target
SET  target.Col1 = source.__Col1
FROM B target
join A as source 
ON  (target.Col1 = source.Col1 OR (target.Col1 IS NULL AND source.Col1 IS NULL)) AND -- most reliable way to do it
    ISNULL(target.Col2,'-1') = ISNULL(source.Col2,'-1')  AND -- less reliable but more concise, replace -1 by any data that cannot be in the tables
     (target.Col3 = source.Col3 OR (target.Col3 IS NULL AND source.Col3 IS NULL)) 
person jazzytomato    schedule 17.11.2014
comment
Да, я думал об ISNULL и COALESCE. Похоже, остановлюсь на самом надежном. Спасибо. - person makambi; 17.11.2014

Модификация вашего запроса с ISNULL

UPDATE target
SET  target.Col1 = source.__Col1
FROM B target
join A as source 
ON  IsNull(target.Col1,'') = IsNUll(source.Col1,'')  
    AND IsNull(target.Col2,'') = IsNull(source.Col2,'')  
    AND IsNull(target.Col3,'') = IsNull(source.Col3,'') 

CTE пример:

;With CTETableA 
AS
(
Select Col1,Col2,Col3,Col1_Transformed,Col2_Transformed
       ROW_NUMBER() OVER(ORDER BY Col1,Col2,Col3) id
       from A
),
CTETableB
As
(
Select Col1,Col2,Col3,ROW_NUMBER() OVER(ORDER BY Col1,Col2,Col3) id
       from B
)

UPDATE target
SET  target.Col1 = source.Col1
FROM CTETableB target
join CTETableA as source 
ON  target.Id = source.Id  

Insert into B(Col1)
Select Col1 from CTETableB 
person Rajesh    schedule 18.11.2014