关于如何生成随机记录-如何解决每次RND的结果都一样的问题?


Posted on November 20, 2007


问题:

 
关于如何生成随机记录(二)
如何从指定表中随机抽取一定量的记录?
sql server 中 select top 10 * from 表 order by newid(); 在access中如何实现?
为什么我每次 select top ?? ... from... rnd(id) 的结果都一样呢?

 

 

方法一:

 在ACCESS环境中用rnd函数解决,非常简单

 

以下查询展示了如何从表中随机抽取10条记录

SELECT top 10 表1.*, Rnd(id) AS bb FROM 表1 ORDER BY Rnd(id)


其中 Rnd(id) AS bb 只是为了说明其原理,完全可以去掉。
另外, Rnd(id) 其中的id只是为了提供一个种子,可以利用其他任何数值来完成

id字段是自动编号字段,你也可以用其他字段代替,只要能生成数值就行,比如我用姓名字段

SELECT top 10 表1.*, Rnd(len(姓名)) AS bb FROM 表1 ORDER BY Rnd(len(姓名))

示例下载: http://access911.net/down/eg/eg_rnd.rar (9KB)


有网友说每次 RND 得到的结果都一样,那是因为没有使用 Randomize 语句来初始化随机数生成器。

Randomize 语句
初始化随机数生成器。

 

语法

Randomize [number]

可选的 number 参数是 Variant 或任何有效的数值表达式。

说明

Randomize 用 number 将 Rnd 函数的随机数生成器初始化,该随机数生成器给 number 一个新的种子值。如果省略 number,则用系统计时器返回的值作为新的种子值。

如果没有使用 Randomize,则(无参数的)Rnd 函数使用第一次调用 Rnd 函数的种子值。

注意 若想得到重复的随机数序列,在使用具有数值参数的 Randomize 之前直接调用具有负参数值的 Rnd。使用具有同样 number 值的 Randomize 是不会得到重复的随机数序列的。

 

 


方法二:

 在ASP、VB中无法使用上述方法,可以参考使用adodb.recordset.recordcount 属性以及 adodb.recordset.AbsolutePosition 以及 RND 函数来解决问题。

 

Function RndID()
    Dim rs As New ADODB.Recordset
    Dim strsql As String
    strsql = "select * from 1"
    rs.CursorLocation = adUseClient
    rs.Open strsql, CurrentProject.Connection, 2, 3
    '在Access中可以使用 CurrentProject.Connection,
    '其他语言中可以用 ADODB.CONNECTION对象。
    
    Dim i As Long
    Dim lngCount As Long
    Dim lngRnd As Long
    lngCount = rs.RecordCount
    '一下取前10条随机记录
    For i = 1 To 10
        lngRnd = Int((lngCount * Rnd) + 1)
        rs.AbsolutePosition = lngRnd
        Debug.Print rs("id")
    Next
End Function

AbsolutePosition 属性
指示 Recordset 对象的当前记录的序号位置。

 

设置和返回值
设置或返回从 1 到 Recordset 对象 (PageCount) 中的记录数的 Long 值,或者返回一个 PositionEnum 值。

说明
要设置 AbsolutePosition 属性,ADO 要求您正在使用的 OLE DB 提供者实现 IRowsetLocate 接口。

访问用仅向前或动态游标打开的 Recordset 的 AbsolutePosition 属性将产生错误 adErrFeatureNotAvailable。使用其他游标类型时,只要提供者支持 IRowsetScroll 接口,就会返回正确的位置。如果提供者不支持 IRowsetScroll 接口,该属性将被设置为 adPosUnknown。要确定您的提供者是否支持 IRowsetScroll,请参阅提供者的文档。

使用 AbsolutePosition 属性根据在 Recordset 对象中的序号位置移动到某一记录,或确定当前记录的序号位置。提供者必须支持相应的功能才能使用此属性。

与 AbsolutePage 属性一样,AbsolutePosition 也是从 1 开始,并且当前记录是 Recordset 的第一个记录时等于 1。可以通过 RecordCount 属性获取 Recordset 对象中记录的总数目。

设置 AbsolutePosition 属性时,即使该属性指向当前缓存中的记录,ADO 也将使用以用户指定的记录开始的新记录组来重载缓存。CacheSize 属性决定此记录组的大小。

注意   不应将 AbsolutePosition 属性作为替代的记录编号使用。删除前面的记录时,给定记录的位置将发生更改。如果重新查询或重新打开 Recordset 对象,则无法保证给定的记录会有相同的 AbsolutePosition。书签仍然是保持和返回给定位置的建议方式,并且是跨越 Recordset 对象的所有类型定位的唯一方式。
请参阅
Visual Basic 范例 | Visual C++ 范例 | Visual J++ 范例

AbsolutePage 属性 | RecordCount 属性

适用于:Recordset 对象

 

 

 


方法三:

 用当前 TIME 做种子生成随机数。如果时间重复最终还是重复,没有从根本上解决问题,说白了还是种子的问题。要不重复就要彻底解决种子的问题,如果能取得毫秒级时间就基本能解决了

 

或者建议在组织 SQL 语句的时候有意插入一个 VB 函数生成的随机值作为种子也可以

......
    Dim sql 
    Dim r 
    Randomize
    r = Rnd
    sql = "select top 1 * from tb order by rnd(" & r & "-id)"
......


标签:N/A

 

在线学习答案查询入口
微信扫码联系
微信扫码联系