2011-10-11 63 views
1

我需要一个SQL语句,它使用来自#T2(C1)的值填充#T1表的第二列的空值。当它们之间没有关系时,两个表之间的更新

这两个表的列之间没有外键或匹配。

样品:

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正确指出,要做到这种更新是不可能不定义对表进行排序,其实我觉得确切的说是不正确识别和目标表链接行。
@Bogdan Sahlean已经找到另一种方式,使用表变量和IDENTITY列,这是我很高兴与此解决方案,这是另一种方式 然而,在实际应用中我还是会使用窗口函数
感谢所有

+0

表格没有固有的排序,而您正试图强加一个。没有窗口函数或游标,我不明白你会怎么做。 –

+0

我与这个事实生活在一起,也许我错过了一些东西,我知道这些表格之间的唯一连接将是一个笛卡尔产品,N x M,其中M> 1 –

回答

1

1.我想你在目标表(#T1)中有一个pk

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

稍作修改,它是一个工作解决方案 –

0

我同意达米安,无论如何,当你将依赖引擎,并建立一个前提,该表是由C1列(仅取决于数据库,你不能依靠它)订购的,你可以发布更新声明将更新所有行

declare @a int 
set @a = 0 

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

但我不会这么做。

+0

它的顺序并不重要。在实际应用中,情况是这样的:我有一个CSV文件中的条形码列表,我使用批量插入将它放在表格中。然后对于每个产品库存,还没有条码(这里为空条件),我分配一个条形码。条码分配的顺序无关紧要,唯一的条件是保持列表的唯一性。 –

0

我会用一个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没有订单,而是这个查询依赖于记录的物理顺序,这不是一个好主意,但它看起来就是你正在处理的)。然后我们加入这个标识符,并用T2中的值更新T1中的记录。

我已将此解决方案置于SQL Fiddle

如果您可以查看创建具有某种类型的标识符的新表,并将它们链接在一起,那么您将不必依赖记录的物理顺序。

+0

请检查Damian发表的评论。我在桌上没有特定的顺序。顺序是他们身体如何在桌上。 –