用其他表中的随机值替换值。神谕

时间:2016-01-28 16:56:55

标签: sql oracle

我想用另一个表中的随机名更新表中的名称。表Users中有真实的用户名。表tmp_users中有名称。我想用tmp_users表中的随机名更新Users表中的所有名称。我们的想法是用假客户匿名化真实的生产数据。 tmp_users表中的条目较少,因此我认为我无法关联id。

我遇到的问题是所有用户都设置为相同的名称。

一些示例数据:

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
...

我想为Users表中的每一行分配一个随机名称。所有行的名称不同。我喜欢这样的事情:

Mulan
Cinderella
Belle
Elsa
Jasmine
Tinker Bell
...

知道如何做到这一点?我正在使用Oracle Database 11g Express Edition 11.2.0.2.0。使用游标很容易,但我试图弄清楚如何使用set操作。

更新:

我现在已经在两个不同的Oracle版本上进行了测试。相关子查询解决方案不适用于Oracle Database 11g Express Edition 11.2.0.2.0。 但它有时在Oracle Database 11g企业版11.2.0.4.0上有效。在一张桌子上它一直在工作,在另一张桌子上它永远不会工作。

4 个答案:

答案 0 :(得分:2)

使用11.2.0.4测试以下作品,类似于@ VR46建议:

    mess = {'default': 'default', 'this': 'that'}
    jmess = json.dumps(mess)

    response = self.boto_client.publish(
        TopicArn=self.TopicArn,
        MessageStructure='json',
        Message=jmess
    )

答案 1 :(得分: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 ); 

答案 2 :(得分: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,你可以使用keep dense rank来代替:

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                                              
...

相关性必须是真实的;如果你的用户表中有空值,这会将它们更新为null,如果这是一个问题,你可以使用不同的条件。

根据评论,11.2.0.2中的dbms_random与11.2.0.3和11.2.0.4中sys_guid的问题似乎相同。如果您的用户表还有一个数字唯一/主键(例如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包含行&#34;在子查询中包含DBMS_RANDOM.VALUE可能会也可能不会起作用,具体取决于所选的优化和执行代码路径&#34;,这似乎是这里的问题。

你也可以尝试合并变体,例如(再次假设您可以使用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;

交叉连接可能会使这不切实际,具体取决于您在每个表中实际拥有的行数。

答案 3 :(得分: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-&gt; 10将被分配假名1 - > 10,而用户11将从假名#1开始。

USING查询有额外的测试字段。