这个帖子引起的疑问:
http://community.csdn.net/Expert/topic/4832/4832629.xml?temp=.4810602想知道,类似的需求应该怎么实现比较好

解决方案 »

  1.   

    1. 首先是随机到底怎么产生... 像JAVA,C#,SQL里的Random产生的数字是固定的(每次RUN都是这些数字)
    解决这个问题,想来想去,至于取秒的小数部分,够随机!
    select to_char(current_timestamp(6),'YYYY-MM-DD hh24:mi:ssxff') from dual;
    查询结果:
    2006-06-21 17:51:41.245732, 取后面的245732;
    这6个数字够权威,够随机了吧~2. 其次,怎么选择题目?  (比如试题表是 EXAM)
    先取总数~ 
    select count(1) from EXAM;
    得到结果:
    150000  (假设题库有15万题)
    将上面得到的 245732 / 1000000 * 150000 = 368598, 那么新得到的368598就是随机选中的题目.3. 上面两步基本可以解决了随机选题的问题,但不能解决试题还有级别,不同级别之间,选中概率不同的问题:
    解决方法如下:
    例:level 1选中率为 50%
    例:level 2选中率为 30%
    例:level 3选中率为 10%
    例:level 4选中率为 7%
    例:level 5选中率为 3%
    一共要选多少题是已知的,例如要选100题出来.
    那么可以得到需要选出 50题(1级) 30题(2级) 10题(3级) 7题(4级) 3题(5级);4. 
    select count(1) from EXAM where level=1;
    select count(1) from EXAM where level=2;
    select count(1) from EXAM where level=3;
    select count(1) from EXAM where level=4;
    select count(1) from EXAM where level=5;
    得到所有级别的试题数的结果:(假设结果如下)
    100000
    30000
    10000
    5000
    5000  ,
    好了, 现在的问题就转变成,怎样在100000题1级试题中选出50题, 30000题2级试题中选出30题 .......5. 将步骤4中的问题用步骤1,2来解, 完事~
    (有不足之处~ 请指出!  这个过程需要代码和SQL结合来完成, 下一个SQL就能完成的人实在...高)
      

  2.   

    刚想到上面的提供的解决方案有个小小的漏洞,
    那就是取秒的小数部分,可能取的两次是相同(这个...1000000分之一的概率)或则调整后值相同.
    那就会产生两次选一样的题~ 不过解决这个问题应该很easy吧~ 选中一题就往随便哪张表里塞条记录,说明这题已经被用啦,以后不能再用
      

  3.   

    to sozdream():
    1. select to_char(current_timestamp(6),'YYYY-MM-DD hh24:mi:ssxff') from dual;
       小数部分并不是随机数,而是一个确定的时间;所以产生的并不是一个水平分布的随机数;
    2. 245732 / 1000000 * 150000 = 368598, 那么新得到的368598就是随机选中的题目.
       由于产生的245732 并不是水平分布的随机数,那么通过它计算出选中题号的概率就不是 1/总题数,那么就无法保证后面的level 1选中率为 50%等
      

  4.   

    呵呵,可以用dbms_random实现
    想知道用数据库实现和用程序实现两者的优劣
      

  5.   

    通过数据库实现和程序实现的比较
    1、通过数据库实现
    Oracle可以通过我在
    http://community.csdn.net/Expert/topic/4832/4832629.xml?temp=.4810602
    中给出的方法来实现
    select ID,name,star_level from (select ID,name,star_level,round(dbms_random.value(1,15))-star_level t from tbl_A) where t<=0select ID,name,star_level from (select ID,name,star_level,mod(abs(dbms_random.random),15)-star_level t from tbl_A) where t<=0select ID,name,star_level from (select ID,name,star_level from tbl_A order by dbms_random.value*(1+star_level/k) desc) where rownum<5select * from table sample(k) 也可以实现取k%的记录用数据库做可以直接将需要的数据取出。不同的数据库需要用不同的函数处理2、通过程序实现
    需要先将数据全部取出,然后再随机取出需要的数据。算法不依赖于数据库
      

  6.   

    通过程序实现不需要全部取出数据吧。取出count,然后产生1-count的随机数 R ,选择第R条记录不就行了吗?取出全部数据,太不划算了。呵呵
      

  7.   

    上次有人讲dbms_random产生的是伪随机数。
    但是我想只要是通过算法实现的随机数应该都差不多吧。个人认为放在程序里比较好,比较灵活,适当减轻数据库负担。
      

  8.   

    可以这么理解么:
    1. 数据库的话,只需要一次就可以取得所需要的数据集;
    2. 通过程序实现
       1)不是特别清楚 waterfirer(水清) 所说的需要先将数据全部取出,然后再随机取出需要的数据应该怎么做,再次麻烦 waterfirer(水清) 解释一下
       2)我的理解是如果需要随机取得确定level的题N道,那么,需要建立一个数组,记录已经被取出的题的序号,根据N进行循环,每次循环随机生成一个随机数,然后检查数组中是否已经存在该随机数对应的题目序号,如果不存在,那么把随机数生成的题目序号放入数组;如果存在,继续循环,直至取得N个题目序号;最后按照数组去数据库一次性取得记录;(前提:按照随机数生成题目序号在数据库中一定存在)
    想法不是特别完善
    欢迎大家拍砖,多多指点
      

  9.   

    to waterfirer(水清):
    select * from table sample(k) 也可以实现取k%的记录
    尝试了一下,好象取得记录的条数不总是确定的
    SQL> select count(1) from t1;  COUNT(1)
    ----------
           100
    SQL> select * from t1 sample(10);     MONTH      MONEY
    ---------- ----------
            19         19
            22         22
            25         25
            35         35
            70         70
            78         78
            84         84
            87         87
            91         91已选择9行。SQL> select * from t1 sample(10);     MONTH      MONEY
    ---------- ----------
             3          3
             4          4
            26         26
            35         35
            41         41
            43         43
            82         82
            86         86已选择8行。SQL> select * from t1 sample(10);     MONTH      MONEY
    ---------- ----------
             3          3
             4          4
            26         26
            35         35
            41         41
            43         43
            82         82
            86         86已选择8行。SQL> select * from t1 sample(10);     MONTH      MONEY
    ---------- ----------
             3          3
             4          4
            26         26
            35         35
            41         41
            43         43
            82         82
            86         86已选择8行。SQL> select * from t1 sample(10);     MONTH      MONEY
    ---------- ----------
             3          3
             9          9
            13         13
            30         30
            33         33
            35         35
            44         44
            51         51
            65         65
            74         74
            90         90     MONTH      MONEY
    ---------- ----------
            93         93已选择12行。SQL> select * from t1 sample(10);     MONTH      MONEY
    ---------- ----------
             3          3
             9          9
            13         13
            30         30
            33         33
            35         35
            44         44
            51         51
            65         65
            74         74
            90         90     MONTH      MONEY
    ---------- ----------
            93         93已选择12行。SQL> select * from t1 sample(10);     MONTH      MONEY
    ---------- ----------
            10         10
            17         17
            20         20
            56         56
            73         73
            94         94已选择6行。