【SQL】使用SQL語句完成20個護士隨機分配到兩個醫院的任務

secooler發表於2010-04-28
今天被問到有關如果將20個人隨機的分配到兩個組的問題,現將實現方法分享在此,供參考。

1.問題需求
有20個護士,需要隨機取出10位護士分配到A醫院,剩下的10位護士分配到B醫院。
為了單位的分配公平,必須是隨機生成這個結果。

2.問題解析
該問題轉換為最淺顯的解釋就是,對給出的1-20連續的數字,任意打亂,將打亂的結果排成一列。前10人就去A醫院,後10人就去B醫院。

3.模型化這個問題
create table name_list (name varchar2(30));
insert into name_list values ('secooler1');
insert into name_list values ('secooler2');
insert into name_list values ('secooler3');
insert into name_list values ('secooler4');
insert into name_list values ('secooler5');
insert into name_list values ('secooler6');
insert into name_list values ('secooler7');
insert into name_list values ('secooler8');
insert into name_list values ('secooler9');
insert into name_list values ('secooler10');
insert into name_list values ('secooler11');
insert into name_list values ('secooler12');
insert into name_list values ('secooler13');
insert into name_list values ('secooler14');
insert into name_list values ('secooler15');
insert into name_list values ('secooler16');
insert into name_list values ('secooler17');
insert into name_list values ('secooler18');
insert into name_list values ('secooler19');
insert into name_list values ('secooler20');
commit;

sec@ora10g> select * from name_list;

NAME
------------------------------
secooler1
secooler2
secooler3
secooler4
secooler5
secooler6
secooler7
secooler8
secooler9
secooler10
secooler11
secooler12
secooler13
secooler14
secooler15
secooler16
secooler17
secooler18
secooler19
secooler20

20 rows selected.

4.方案一
使用Oracle的隨機函式實現這個需求最簡單直觀。
方法如下:
在將name_list表打亂之前的內容如下:
sec@ora10g> select rownum, t.* from (select * from name_list) t;

    ROWNUM NAME
---------- ------------------------------
         1 secooler1
         2 secooler2
         3 secooler3
         4 secooler4
         5 secooler5
         6 secooler6
         7 secooler7
         8 secooler8
         9 secooler9
        10 secooler10
        11 secooler11
        12 secooler12
        13 secooler13
        14 secooler14
        15 secooler15
        16 secooler16
        17 secooler17
        18 secooler18
        19 secooler19
        20 secooler20

20 rows selected.

我們使用隨機數dbms_random.random對name_list表進行打亂後輸出。
sec@ora10g> select rownum, t.* from (select * from name_list order by dbms_random.random) t;

    ROWNUM NAME
---------- ------------------------------
         1 secooler10
         2 secooler9
         3 secooler19
         4 secooler7
         5 secooler3
         6 secooler4
         7 secooler15
         8 secooler16
         9 secooler18
        10 secooler12
        11 secooler1
        12 secooler5
        13 secooler13
        14 secooler14
        15 secooler6
        16 secooler17
        17 secooler2
        18 secooler11
        19 secooler8
        20 secooler20

20 rows selected.

每次執行這個條語句都可以完成一次打亂的需求,自行測試,不贅述。

原理:對非常大的隨機數進行排序以達到順序打亂的目的。

5.方案二
基於第一種方法,只要我們在name_list表中新增一列隨機數列,然後再按照這一列進行排序即可。
sec@ora10g> alter table name_list add random number;

Table altered.

sec@ora10g> update name_list set random=dbms_random.random;

20 rows updated.

sec@ora10g> commit;

Commit complete.

sec@ora10g> select * from name_list;

NAME                               RANDOM
------------------------------ ----------
secooler1                      -1.645E+09
secooler2                      1441099457
secooler3                      -1.133E+09
secooler4                       600418771
secooler5                      1277685516
secooler6                      -177083719
secooler7                      -599498736
secooler8                       352353250
secooler9                       107600398
secooler10                      718837634
secooler11                     -830730584
secooler12                      906134037
secooler13                     -1.082E+09
secooler14                       11469174
secooler15                     -452139368
secooler16                     -2.119E+09
secooler17                      760306608
secooler18                      158227683
secooler19                       21379248
secooler20                     1617624650

20 rows selected.

sec@ora10g> select rownum, t.* from (select name from name_list order by random) t;

    ROWNUM NAME
---------- ------------------------------
         1 secooler16
         2 secooler1
         3 secooler3
         4 secooler13
         5 secooler11
         6 secooler7
         7 secooler15
         8 secooler6
         9 secooler14
        10 secooler19
        11 secooler9
        12 secooler18
        13 secooler8
        14 secooler4
        15 secooler10
        16 secooler17
        17 secooler12
        18 secooler5
        19 secooler2
        20 secooler20

20 rows selected.

OK,這樣,我們就完成了一次資料打亂的動作。

6.方案三
基於上面新增輔助欄位的方法,我們可以大膽的將這種方法推廣到Excel中。
我們可以使用Excel的“=rand()”方法生成隨機數,然後按照這個隨機數列進行排序及可完成資料隨機打亂功能。
在此基礎上可以錄製一段“宏”,使得這個過程可以自動化完成,這樣每次執行宏都會獲得一個新的隨機排列,甚是方便。
這個方案任何人都可以完成,畢竟Office軟體還是很普及的。

7.方案四
這裡只給出思路,不做具體實現。
思路:構造另外一個表T,從表name_list中隨機取出一條記錄插入到表T中,同時將name_list中的該條記錄刪除;再從表name_list中隨機取出一條記錄插入到表T中,同時將name_list中的該條記錄刪除,按照這個方法迴圈下去,直到所有資料均插入到T表中,此時T表就是一個打亂後的結果。

8.方案五
如果想用“牛刀”完成這個需求,也可以透過編寫一段小程式或小指令碼來完成(注意在編寫過程中注意選取的內容不可以重複)。

9.小結
往往一個需求拿到手中後,解決方案不止一個,這時,我們就需要認真的甄別那種方案的代價最低。關鍵是快速的轉換問題需求為我們熟識技術點。
本例中使用SQL的隨機函式排序方法最簡單,使用Excel方法最實用,使用程式或指令碼方法較複雜,各取所需最重要。

Good luck.

secooler
10.04.28

-- The End --

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/519536/viewspace-661592/,如需轉載,請註明出處,否則將追究法律責任。

相關文章