2016-01-28 41 views
3

我想用另一個表中的隨機名更新表中的名稱。表Users中有真實的用戶名。在表tmp_users中有名字。我想用tmp_users表中的隨機名更新Users表中的所有名稱。這個想法是用假客戶匿名實際生產數據。在tmp_users表中有更少的條目,所以我不認爲我可以關聯一個id。用其他表中的隨機值替換值。 Oracle

我遇到的問題是所有用戶都設置爲相同的名稱。

一些樣本數據:

create table users 
(
    name varchar2(50) 
); 

create table tmp_users 
(
    name varchar2(50) 
); 

insert into users values ('Cora'); 
insert into users values ('Rayna'); 
insert into users values ('Heidi'); 
insert into users values ('Gilda'); 
insert into users values ('Dorothy'); 
insert into users values ('Elena'); 
insert into users values ('Providencia'); 
insert into users values ('Louetta'); 
insert into users values ('Portia'); 
insert into users values ('Rodrick'); 
insert into users values ('Rocco'); 
insert into users values ('Nelson'); 
insert into users values ('Derrick'); 
insert into users values ('Everett'); 
insert into users values ('Nisha'); 
insert into users values ('Amy'); 
insert into users values ('Hyun'); 
insert into users values ('Brendon'); 
insert into users values ('Gabriela'); 
insert into users values ('Melina'); 

insert into tmp_users values ('Snow White'); 
insert into tmp_users values ('Cinderella'); 
insert into tmp_users values ('Aurora'); 
insert into tmp_users values ('Ariel'); 
insert into tmp_users values ('Belle'); 
insert into tmp_users values ('Jasmine'); 
insert into tmp_users values ('Pocahontas'); 
insert into tmp_users values ('Mulan'); 
insert into tmp_users values ('Tinker Bell'); 
insert into tmp_users values ('Anna'); 
insert into tmp_users values ('Elsa'); 

--Wrong, sets all users to the same random name 
update users set name = (select name from (select name from tmp_users order by sys_guid()) where rownum = 1); 

--Wrong, sets all users to the same random name 
update users set name = (select name from (select name from tmp_users order by dbms_random.value) where rownum = 1); 

做這件事時:

select * from users; 

結果我得到的是這樣的事情,這是我不想要的。

Cinderella 
Cinderella 
Cinderella 
Cinderella 
Cinderella 
... 

我想爲用戶表中的每一行分配一個隨機名稱。與所有行不同。我想這樣的東西:

Mulan 
Cinderella 
Belle 
Elsa 
Jasmine 
Tinker Bell 
... 

任何想法如何做到這一點?我正在使用Oracle數據庫11g速成版11.2.0.2.0。使用遊標很容易,但我試圖弄清楚如何用set操作來完成它。

更新:

現在我已經測試了兩種不同的Oracle版本。相關的子查詢解決方案在Oracle數據庫11g速成版11.2.0.2.0上不起作用。 但它有時在Oracle數據庫11g企業版11.2.0.4.0上有效。在一張桌子上它一直工作,在另一張桌子上它永遠不會工作。

回答

1

我覺得子查詢相關會拉隨機的名字從子查詢

UPDATE users 
SET name = (SELECT name 
       FROM (SELECT name 
         FROM tmp_users tu 
         ORDER BY Sys_guid()) 
       WHERE ROWNUM = 1 
       AND users.name <> name); 
+0

WHERE(users.name ='A' OR 1 = 1)? –

+0

我不太關注關聯邏輯,但它給出了這個錯誤:「SQL錯誤:ORA-00904:」USERS「。」NAME「:無效標識符」 – johanrex

+0

@ user1073476 - 不確定如何在Oracle中執行此操作。但想法是將子查詢與更新表 –

1

你需要一定的相關性,如@ VR46建議;但sys_guid()對此不起作用(無論如何,在11gR2中;我認爲優化程序僅僅出於某種原因在這種情況下評估一次)。您可以使用,雖然DBMS_RANDOM.VALUE:

update users u set name = (
    select name from (
    select name from tmp_users order by dbms_random.value 
) 
    where rownum = 1 and u.name is not null 
); 

NAME            
-------------------------------------------------- 
Jasmine           
Tinker Bell          
Ariel            
Elsa            
Elsa            
Elsa            
Belle            
Snow White           
... 

如果你不想aubquery你可以使用保持密集的排名,而不是:

update users u set name = (
    select max(name) keep (dense_rank first order by dbms_random.value) 
    from tmp_users 
    where u.name is not null 
); 

NAME            
-------------------------------------------------- 
Mulan            
Anna            
Snow White           
Elsa            
Tinker Bell          
Belle            
Belle            
Elsa            
... 

只是必須是真實的相關性;如果你的用戶表中有空值,它會將它們更新爲空,如果這是一個問題,你可以使用不同的條件。

從看來你似乎有同樣的問題,在11.2.0.2 dbms_random,因爲我有sys_guid在11.2.0.3和11.2.0.4。如果您的用戶表中還包含數字唯一/主鍵(如ID),則可以將其用於關聯並將其傳遞到value函數,該函數可能會影響,但我沒有合適的實例來測試反對:

update users u set name = (
    select max(name) keep (dense_rank first order by dbms_random.value(0, u.id)) 
    from tmp_users 
); 

MOS注意420779.1包括行「包括DBMS_RANDOM。子查詢中的VALUE可能會或可能不會工作,這取決於所選擇的優化和執行代碼路徑「,這似乎是這裏的問題。

您也可以嘗試使用合併的變體,例如(再次假設您可以使用一個ID ):

merge into users u 
using (
    select u.id, max(tu.name) keep (dense_rank first 
    order by dbms_random.value(0, u.id)) as name 
    from users u 
    cross join tmp_users tu 
    group by u.id 
) tu 
on (tu.id = u.id) 
when matched then update set u.name = tu.name; 

的交叉連接可以使這種不切實際的,雖然,這取決於你確實有每個表中的行數

+0

你試過這些例子嗎?從我能看到的都產生相同的錯誤結果。 – johanrex

+0

@ user1073476 - 我做到了。兩者都產生隨機值,在11.2.0.4.7中。哪個版本不適用於? –

+0

我正在使用Oracle數據庫11g快速版11.2.0.2.0。當我執行「從用戶中選擇*」時,所有用戶都具有相同的名稱。 – johanrex

2

測試與11.2.0.4下面的作品,類似於@ VR46建議。 :

SQL> UPDATE users u 
    2  SET name = (SELECT name 
    3     FROM (SELECT NAME, 
    4        row_number() over(ORDER BY dbms_random.value) rn 
    5       FROM tmp_users) tu 
    6     WHERE u.name IS NOT NULL 
    7       AND rn = 1); 
20 rows updated 

SQL> select * from users; 
NAME 
-------------------------------------------------- 
Ariel 
Aurora 
Belle 
Ariel 
Anna 
Mulan 
Aurora 
Ariel 
Mulan 
Tinker Bell 
Mulan 
Ariel 
Aurora 
Pocahontas 
Pocahontas 
Aurora 
Snow White 
Mulan 
Aurora 
Anna 
20 rows selected 
+0

我在Oracle數據庫11g速成版11.2.0.2.0上遇到了錯誤的行爲。用戶表中的所有名稱都具有相同的名稱。當我單獨運行內部select時,它可以正常工作,但是當它用作相關子查詢時,它不會。也許這只是因爲@Alex Poole提供了有關MOS註釋420779.1的一些提示,這在我的版本中已經被打破。我自己無法訪問Oracle支持,所以我不知道它究竟是什麼意思。 – johanrex

1

另外還有一個方法,它使用ROWID和模量:

MERGE into users_tab u 
USING (
    select 
     actual.row_id as actual_rowid, 
     actual.rnum actual_rnum, 
     actual.name actual_name, 
     fake.rnum fake_rnum, 
     fake.name fake_name, 
     mod(actual.rnum, fake_count.cnt) modulus 
    from 
    (
    select rownum rnum, name, rowid as row_id 
    from users_tab 
    ) actual, 
    (
    select rownum-1 rnum, name 
    from (select distinct name from tmp_users_tab) 
    ) fake, 
    (select count(distinct name) cnt from tmp_users_tab) fake_count 
    where mod(actual.rnum, fake_count.cnt) = fake.rnum 
) x 
ON (x.actual_rowid = u.rowid) 
WHEN MATCHED THEN UPDATE 
    set name = x.fake_name; 

不知道如何,這將在一個非常龐大的用戶表執行,但是。它不是隨機的,而是遵循一系列假名稱。因此,如果您有10個虛假名稱,用戶中的記錄1-> 10將被分配虛假名稱1-> 10,並且用戶11將以假名稱#1重新開始。

USING查詢具有用於測試的額外字段。

相關問題