我试图在名表中“洗牌”last_names值。我想使用一个子选择查询,随机化名称的顺序,并相应地更新它们。我想出于混淆的原因这样做,但希望它仍然看起来像一个真实的数据集。
下面的语句返回“ORA-01427:单行子查询返回多行”
我该如何做到这一点?
UPDATE schema.names set last_name = (
SELECT *
FROM (
SELECT last_name
FROM schema.names
ORDER BY DBMS_RANDOM.RANDOM))
答案 0 :(得分:2)
这是一个混淆名称的查询:
select n.*, n2.name as new_name
from (select n.*, row_number() over (order by dbms_random.random) as seqnum
from schema.names n
) n join
(select n.*, row_number() over (order by dbms_random.random) as seqnum
from schema.names n
) n2
on n.seqnum = n2.seqnum;
假设您有一个主键,可以将其合并到merge
中:
merge into schema.names n
using (select n.*, n2.name as new_name
from (select n.*, row_number() over (order by dbms_random.random) as seqnum
from schema.names n
) n join
(select n.*, row_number() over (order by dbms_random.random) as seqnum
from schema.names n
) n2
on n.seqnum = n2.seqnum
) nn
on n.? = nn.?
when matched then update
set n.name = nn.new_name;
答案 1 :(得分:0)
编辑:以下PL / SQL块使用Gordon的答案中的查询来驱动循环。
设定:
create table demo
( name_original varchar2(10)
, name_new varchar2(10) );
-- Two columns initially the same so we can check the results:
insert into demo
select column_value, column_value
from table(sys.dbms_debug_vc2coll('Jim','James','Joe','Jenny','Jane','Jacky'));
代码:
begin
for r in (
select n.rowid as rwd
, n.name_original
, n2.name_new as name_shuffled
from ( select n.*, row_number() over(order by dbms_random.value) as seqnum
from demo n ) n
join
( select n.*, row_number() over(order by dbms_random.value) as seqnum
from demo n ) n2
on n.seqnum = n2.seqnum
)
loop
update demo set name_new = r.name_shuffled
where rowid = r.rwd;
end loop;
end;
我的原始答案如下,对OP没有特别的帮助,但我认为无论如何它在技术上都很有趣:
优化器意识到不需要执行一次不相关的单行子查询,因此您可以查找一个值并应用于所有行。可能有一个提示可以防止这种情况,但我无法快速查找(no_merge
,no_unnest
和rule
没有效果)。
以下工作(Oracle 12.1),但只是强加了新旧名称必须不同的附加规则,使其成为优化器必须为每行评估的相关子查询。 (它还会生成重复项,因为每次随机查找都是独立的,因此对您来说可能没用。)
update demo d set name_new =
( select name_new
from demo d2
where d2.name_new <> d.name_new
order by dbms_random.random
fetch first row only );
select * from demo;
NAME_ORIGINAL NAME_NEW
------------- ----------
Jim Jenny
James Jane
Joe Jacky
Jenny Jane
Jane Jacky
Jacky Jim
冒着偏离主题的风险,请注意添加谓词where d2.name_new <> d.name_new
如何更改执行计划:
Plan hash value: 1813657616
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | | 0 |00:00:00.01 | 27 |
| 1 | UPDATE | DEMO | 1 | | 0 |00:00:00.01 | 27 |
| 2 | TABLE ACCESS STORAGE FULL | DEMO | 1 | 82 | 6 |00:00:00.01 | 7 |
|* 3 | VIEW | | 1 | 1 | 1 |00:00:00.01 | 7 |
|* 4 | WINDOW SORT PUSHED RANK | | 1 | 82 | 1 |00:00:00.01 | 7 |
| 5 | TABLE ACCESS STORAGE FULL| DEMO | 1 | 82 | 6 |00:00:00.01 | 7 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("from$_subquery$_003"."rowlimit_$$_rownumber"<=1)
4 - filter(ROW_NUMBER() OVER ( ORDER BY "DBMS_RANDOM"."RANDOM"())<=1)
到此:
Plan hash value: 1813657616
--------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 1 | | 0 |00:00:00.01 | 62 | | | |
| 1 | UPDATE | DEMO | 1 | | 0 |00:00:00.01 | 62 | | | |
| 2 | TABLE ACCESS STORAGE FULL | DEMO | 1 | 82 | 6 |00:00:00.01 | 7 | 1025K| 1025K| |
|* 3 | VIEW | | 6 | 1 | 6 |00:00:00.01 | 42 | | | |
|* 4 | WINDOW SORT PUSHED RANK | | 6 | 4 | 6 |00:00:00.01 | 42 | 2048 | 2048 | 2048 (0)|
|* 5 | TABLE ACCESS STORAGE FULL| DEMO | 6 | 4 | 30 |00:00:00.01 | 42 | 1025K| 1025K| |
--------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - filter("from$_subquery$_003"."rowlimit_$$_rownumber"<=1)
4 - filter(ROW_NUMBER() OVER ( ORDER BY "DBMS_RANDOM"."RANDOM"())<=1)
5 - filter("D2"."NAME_NEW"<>:B1)
这是一个相同的执行计划(计划哈希值1813657616)的一个巧妙的例子,做两个相当不同的事情,如果你想要其中一个。
(如果有一个提示做同样的事情,它会做一个改变结果的提示的简洁例子。)