Обновление между двумя таблицами, когда между ними нет связи - PullRequest
1 голос
/ 11 октября 2011

Мне нужен оператор SQL, который заполняет нулевые значения из второго столбца таблицы # T1 значениями из # T2 (C1).

Нет внешнего ключа или совпадения между столбцами этих двух таблиц.

Пример:

T1 (C1, T2C1)
A1, 1
A2, null
A3, null
A4, 4
A5, null
-------------
T2 (C1)
a
b

После обновления T1 будет выглядеть так:

A1, 1
A2, a
A3, b
A4, 4
A5, null

Я нашел два подхода:

Использование CTE

create table #T1 (C1 varchar(10), T2C1 varchar(10))
create table #T2 (C1 varchar(10))

insert into #T1 values ('A1', '1')
insert into #T1 values ('A2', null)
insert into #T1 values ('A3', null)
insert into #T1 values ('A4', '4')
insert into #T1 values ('A5', null)

insert into #T2 values ('a')
insert into #T2 values ('b')

;with t2 as
(
select C1, row_number() over (order by C1) as Index2
from #T2
)
,t1 as
(
select T2C1, row_number() over (order by C1) as Index1   
from #T1
where T2C1 is null
)
update t1
set t1.T2C1 = t2.C1
from t2
where t1.Index1 = t2.Index2

select * from #T1

drop table #T1
drop table #T2

с производными таблицами

create table #T1 (C1 varchar(10), T2C1 varchar(10))
create table #T2 (C1 varchar(10))

insert into #T1 values ('A1', '1')
insert into #T1 values ('A2', null)
insert into #T1 values ('A3', null)
insert into #T1 values ('A4', '4')
insert into #T1 values ('A5', null)

insert into #T2 values ('a')
insert into #T2 values ('b')

update #T1
set T2C1 = cj.C1
from #T1
join (select T2C1, row_number() over (order by C1) as Index1, C1
   from #T1
   where T2C1 is null) ci on ci.C1 = #T1.C1
join (select C1, row_number() over (order by C1) as Index2
  from #T2) cj on ci.Index1 = cj.Index2

select * from #T1

drop table #T1
drop table #T2

У меня вопрос, могу ли я достичь этого без использования оконных функций и без курсоров?

Обновление
@Damien_The_Unbeliever правильно указывает на то, что выполнить такого рода обновление невозможно без определения порядка в таблицах, на самом деле я думаю, что в точности сказано, что нет правильной идентификации и связи строк из целевой таблицы.
@ Богдан Sahlean нашел другой способ, используя переменные таблицы и столбец IDENTITY, и я доволен этим решением, это другой способ Тем не менее, в реальном приложении я все еще буду использовать функции управления окнами
Спасибо всем

Ответы [ 3 ]

1 голос
/ 11 октября 2011

1. Я предполагаю, что у вас есть pk в целевой таблице (# T1).

2. Вместо ROW_NUMBER это решение использует IDENTITY(1,1) столбцы и две табличные переменные.

3. Я не тестировал это решение.

DECLARE @t2_count INT = (SELECT COUNT(*) FROM #T2);

DECLARE @Target TABLE
(
     MyId INT IDENTITY(1,1) PRIMARY KEY
    ,T1_pk INT NOT NULL UNIQUE
);
INSERT  @Target (T1_pk)
SELECT  TOP(@t2_count) pk
FROM    #T1 
WHERE   T2C1 IS NULL;

DECLARE @Source TABLE
(
     MyId INT IDENTITY(1,1) PRIMARY KEY
    ,C1 VARCHAR(10) NOT NULL
);
INSERT  @Source (C1)
SELECT  C1
FROM    #T2;

UPDATE  #T1
SET     T2C1 = src.C1
FROM    #T1 t
INNER JOIN @Target trg ON t.pk = trg.T1_pk 
INNER JOIN @Source src ON trg.MyId = src.MyId;
0 голосов
/ 02 июня 2013

Я бы использовал CTE вместе с ROW_NUMBER :

WITH cte_t1 AS
(
  SELECT
   T2C1
  ,ROW_NUMBER() OVER (ORDER BY C1) AS id
  FROM T1
  WHERE T2C1 IS NULL
)
,cte_t2 AS
(
  SELECT 
   C1
  ,ROW_NUMBER() OVER (ORDER BY C1) AS id
  FROM T2
)
UPDATE t1
  SET t1.T2C1 = t2.C1
  FROM cte_t1 AS t1
  INNER JOIN cte_t2 AS t2
    ON t1.id = t2.id
;

ROW_NUMBER создает идентификатор на основе порядка, в котором находятся столбцы (который япредполагается, что вы ищете, но учтите, что в SQL нет порядка, вместо этого этот запрос основан на физическом порядке записей, что не очень хорошая идея, но, похоже, это то, с чем вы имеете дело).Затем мы присоединяемся к этому идентификатору и обновляем записи в T1 значениями в T2.

Я поместил это решение на SQL Fiddle .

Если вы можете посмотреть насоздайте новые таблицы с идентификаторами определенного типа, связывающими их вместе, тогда вам не придется полагаться на физический порядок записей.

0 голосов
/ 11 октября 2011

Я согласен с Дэмиеном, в любом случае, когда вы будете полагаться на движок и исходить из предположения, что таблица упорядочена по столбцу C1 (который зависит только от БД, и вы не можете полагаться на это), вы можете выпустить обновление оператор, который обновит все строки

declare @a int
set @a = 0

update #t1
set t2c1 = @a,
@a = @a+1

Но я бы этого не сделал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...