最近在做公司的车联网服务系统,碰到一个需求,需要从数据库中获取随机的n条记录。我参照了《SQL COOKBOOK》中提供的解决方案,现记笔记如下,分享给大家。
解决方案
使用DBMS支持的内置函数来产生随机数值。在ORDER BY字句中使用该函数,对记录进行随机排序,然后,使用ROWNUM限制返回的行(顺序随机)的数目。
探索步骤
1.查找满足条件的行
- select ename,job,sal from emp where sal>2000
查询结果如下:
2.使用ORACLE支持的内置函数对记录进行排序
- select ename,job,sal from emp where sal>2000 order by dbms_random.value
(每次生成的记录排序不同)
3.限制返回的行的数目
- select * from
- (
- select ename,job,sal from emp where sal>2000 order by dbms_random.value
- ) t
- where rownum<=5;
(每次生成的记录及排序不同)
拓展知识
1.关于ROWNUM
许多数据库提供一些语句,比如FETCH FIRST和LIMIT,让用户指定从查询中返回的行数,Oracle的做法则不同,必须使用ROWNUM函数来得到每行的行号(从1开始递增数值)。
在使用ROWNUM<=5来返回前5行时,会发生下面的操作:
- Oracle执行查询
- Oracle获取第1个符合条件的行,将它叫做第1行。
- 有5行了吗?如果没有,那么Oracle就再返回行,因为它要满足行号小于等于5的条件,如果到了5行,那么,Oracle将不再返回行。
- Oracle获取下一行,并递增行号(从2,到3,再到4,等等)。
- 返回第3步。
可以看到,Oracle的ROWNUM数值是在获取每行之后才赋予的,这非常重要,是一个关键点。比如说,许多Oracle开发人员想通过指定ROWNUM=5来返回第5行,这是错误的做法。下面说明使用ROWNUM=5会发生什么:
- Oracle执行查询。
- Oracle获取第一个符合条件的行,将它叫做第1行。
- 有5行了吗?如果没有,那么Oracle就丢弃这些行,因为它不满足条件。如果到了5行,那么,Oracle就返回该行。但是,答案是,永远也不会有"到了5行"的情况发生。
- Oracle获取下一行,这是第一行。原因是,从查询中返回的必须是编号为1的行。
- 转向第3步。
仔细看看这个过程,可以知道使用ROWNUM=5来返回第5行失败的原因。如果不返回第1行到第4行的话,就不会有第5行。
ROWNUM=1确实是返回第1行,这似乎与前面的说明矛盾了。原因是,ROWNUM=1返回第1行,不管表中是否有行,Oracle都会尝试至少取1行。请仔细看前面叙述的过程,将5换成1,就可以理解指定ROWNUM=1作为条件来返回1行为什么是可行的了。
如果要获取指定行数范围内的记录,可以采用分页查询的方式。
2.关于DBMS_RANDOM
一个简单的示例,如下图所示:
- --DBMS_RANDOM
- --该包提供了内置的随机数生成器,可以用于快速生成随机数。
- --1.INITALIZE 该过程用于初始化DBMS_RANDOM包。在初始化DBMS_RANDOM包时,必须要提供随机数种子
- --2.SEED 该过程用于复位随机数种子
- --3.RANDOM 该过程用于生成随机数
- --4.TERMINATE 该过程用于关闭DBMS_RANDOM包
- --随机数使用示例
- DECLARE
- num INT;
- seed NUMBER:=10000000;
- BEGIN
- dbms_random.initialize(seed);
- FOR i IN 1..10 LOOP
- num:=abs(dbms_random.random()/seed);
- dbms_output.put_line(num);
- END LOOP;
- dbms_random.terminate;
- END;