2017-03-27 35 views

回答

4

的一種方法是使用幾個公共表表達式與ROW_NUMBER()NEWID()

創建和填充示例表(保存我們這一步在你未來的問題):

DECLARE @T1 as table 
(
    col1 char(1) 
) 

DECLARE @T2 as table 
(
    col1 char(1) 
) 


INSERT INTO @T1 VALUES 
(NULL), (''), (' '), 
(NULL), (''), (' '), 
(NULL), (''), (' '), 
(NULL), (''), (' ') 


INSERT INTO @T2 VALUES 
('a'), ('b'), ('c'), 
('d'), ('e'), ('f'), 
('g'), ('h'), ('i') 

公用表表達式:

;WITH CTE1 AS 
(
    SELECT Col1, 
      ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) rn 
    FROM @T1 
), CTE2 AS 
(
    SELECT t2.Col1, 
      ROW_NUMBER() OVER(ORDER BY NEWID()) rn 
    FROM @T2 t2 
    CROSS JOIN @T1 -- Note: the cross join here is to get at least the same amount of records as there are in @T1 
) 

更新語句:

UPDATE t1 
SET col1 = t2.Col1 
FROM CTE1 t1 
INNER JOIN CTE2 t2 ON t1.rn = t2.rn 

You can see a live demo on rextester

+0

有趣的是,與表變量OP的查詢工作,太。優化器似乎將表變量視爲與真實表變量完全不同。另一方面,您的查詢與兩者都可以正常工作。 –

2

只是回答問題的這部分(此更新分配相同的隨機選擇值的每一行進行更新。)請參見下面的演示腳本..

我稀少。 100行(連續整數)都表1和表2和我執行以下腳本,相同你有一個..

Table1 has 1 to 100 
table2 has 20 to 100 

現在我下面SCR執行IPT,它按照你應該爲每一行

update t1 
set t1.id=(select top 1 id from #t2 Order By newid()) 
from #t1 t1 

更新隨機值現在,你除,每行被分配一個隨機value..below是輸出我得到

id 
75 
75 
75 
.... 

整個表是用相同的值更新,但隨機,該值將被改變每次你執行更新

爲什麼SQL服務器選擇做this.Lets看執行計劃

enter image description here

該計劃是簡單的嵌套循環,但SQL選擇使用Lazy spool來存儲數據。

現在,如果仔細觀察,在此計劃中,還有兩個屬性Rebind和Rewind。下面是看重他們有

enter image description here

重新綁定意味着 - 多少次,SQL必須去主表和填充這個卷軸(在這種情況下),因爲該數據已經改變

退意思是 - SQL服務器多少次,選擇使用這個假脫機本身,不用觸摸主表

SQLserver選擇在你的情況下做99個倒退,並選擇只使用懶惰假脫機數據,因爲數據hasn沒有改變,因爲你寫你的查詢的方式

現在,如果你改寫了你的更新像下面,你會得到你所期待所期望的行爲,因爲這些值是相關

update t1 
set t1.id=(select top 1 id from #t2 t2 where t1.id=t2.id Order By newid()) 
from #t1 t1 

上面的查詢結果在下面的執行計劃

enter image description here

您也可以觀察到由於相關性而導致重新綁定的人數

enter image description here

演示腳本:

drop table if exists #t1; 
drop table if exists #t2; 

create table #t1 
(id int 
) 

create table #t2 
(id int 
) 


insert into #t1 
select top 100 * from numbers 
order by n 

insert into #t2 
select top 100 * from numbers where n>20 
order by n 

update t1 
set t1.id=(select top 1 id from #t2 t2 where t1.id=t2.id Order By newid()) 
from #t1 t1 


select * from #t1