2016-12-07 62 views
2

如何有效地將大型(1m至5m記錄)表的內容洗牌?該列已知具有唯一值,但您可以假設爲此目的刪除了所有約束。我的頭痛主要是因爲我正在更新我正在選擇的同一列。我的目標是用PL/SQL來做到這一點,以便我可以通過編程方式執行其他操作,例如記錄日誌或更新其他表。在行之間隨機播放一列

**Original table:** 
+----+-----------+ 
| id | fname  | 
+----+-----------+ 
| 1 | mike  | 
| 2 | ricky  | 
| 3 | jane  | 
| 4 | august | 
| 6 | dave  | 
| 9 | Jérôme | 
+----+-----------+ 

**Possible output:** 
+----+-----------+ 
| id | fname  | 
+----+-----------+ 
| 1 | dave  | 
| 2 | jane  | 
| 3 | mike  | 
| 4 | ricky  | 
| 6 | Jérôme | 
| 9 | august | 
+----+-----------+ 

我最新的嘗試已經創建使用over (order by dbms_random.value)遊標並嘗試做一個合併或更新也許是基於ROWNUM。也許我可以通過創建一個臨時表來排序修改自我約束?我相當有信心甲骨文有一些奇特的方式來做到這一點,但我的SQL能力受限於基本的CRUD命令。

完整的解決方案是在這裏,根據戈登的回答是:

merge into t 
using (
select t.id, t2.name 
from (select t.*, rownum as seqnum 
     from t 
    ) t join 
    (select t.*, row_number() over (order by dbms_random.value) as seqnum 
     from t 
    ) t2 
    on t.seqnum = t2.seqnum 
) src 
on (t.id = src.id) 
when matched then update set t.name = src.name; 

回答

2

你可以做一個自連接,使用隨機行號:

select t.id, t2.name 
from (select t.*, row_number() over (order by dbms_random.value) as seqnum 
     from t 
    ) t join 
    (select t.*, row_number() over (order by dbms_random.value) as seqnum 
     from t 
    ) t2 
    on t.seqnum = t2.seqnum; 

其實,你並不需要爲這兩個被隨機分配:

select t.id, t2.name 
from (select t.*, rownum as seqnum 
     from t 
    ) t join 
    (select t.*, row_number() over (order by dbms_random.value) as seqnum 
     from t 
    ) t2 
    on t.seqnum = t2.seqnum; 
+0

感謝您的答覆,一個狡辯我是,T1應該只是爲t 。無論如何,我將如何從這個更新?我需要根據此查詢生成合並語句嗎? – user1

+0

我能夠使它與合併一起工作,再次感謝。我會在我的問題中發佈完整的解決方案。 – user1

1

這個答案直接回答(這是我的,所以我相信我被允許reus Ë吧): https://community.oracle.com/thread/3995265

準備

create table original_table (id number, name varchar2(30)); 

insert into original_table 
    select 1, 'mike' from dual union all 
    select 2, 'ricky' from dual union all 
    select 3, 'jane' from dual union all 
    select 4, 'august' from dual union all 
    select 6, 'dave' from dual union all 
    select 9, 'Jérôme' from dual 
; 

select * from original_table; 

ID NAME 
-- ------ 
1 mike 
2 ricky 
3 jane 
4 august 
6 dave 
9 Jérôme 

更新與置換名行:

merge into original_table o 
    using (
    with 
     helper (id, rn, rand_rn) as (
      select id, 
        row_number() over (order by id), 
        row_number() over (order by dbms_random.value()) 
      from original_table 
     ) 
    select ot.name, h2.id 
    from original_table ot inner join helper h1 on  ot.id = h1.id 
          inner join helper h2 on h1.rand_rn = h2.rn 
) p 
on (o.id = p.id) 
when matched then update set o.name = p.name 
; 

select * from original_table; 

ID NAME 
-- ------ 
1 ricky 
2 dave 
3 Jérôme 
4 jane 
6 august 
9 mike 
+0

這是一個很好的解決方案。我有同樣的問題,但我需要保證每個名字的性別:男性,女性和未知。我該如何將這個條件應用於這個解決方案?有什麼想法嗎? – milheiros

+0

@milheiros - 你是否有單獨的性別欄目,或者你需要從名字中猜出它? – mathguy