以可重复的方式混洗数据(能够再次获得相同的“随机”顺序)

时间:2013-10-24 14:02:08

标签: sql math random shuffle

这与大多数“随机顺序”问题相反。 我想以随机顺序从数据库中选择数据。但我希望能够重复某些选择,再次获得相同的订单。

当前(随机)选择:

SELECT custId, rand() as random from
(
    SELECT DISTINCT custId FROM dummy
)

使用它,每个键/行都会得到一个随机数。以随机顺序排序这些提升结果。

但是我想重复这个选择,再次获得相同的顺序。我的想法是每个会话计算一次随机数(r)(例如“4”)并使用这个数字以某种方式对数据进行混洗。

我的第一个想法:

SELECT custId, custId * 4 as random from
(
    SELECT DISTINCT custId FROM dummy
)

(在现实生活中“4”会像4005226664240702)

这会导致每行的编号不同,但每次运行时都会有相同的编号。通过将“r”更改为5,所有数字都将改变。

问题是:这里的乘法是不够的。它只是增加数字但保持顺序相同。因此我需要一些其他类型的算术功能。

更抽象

从我的数据开始(A-D)。 k 是关键, r 是当前使用的随机数:

    k    r
A = 1    4
B = 2    4
C = 3    4
D = 4    4

使用 k r 进行一些计算,我希望得到类似的每一行:

    k    r
A = 1    4    --> 12
B = 2    4    --> 13
C = 3    4    --> 11
D = 4    4    --> 10

数字可以是他们想要的任何数字,但是当我命令他们升序时,我希望获得与初始数字不同的顺序。在这种情况下,D,C,A,B,E。

将r设置为7应该会产生不同的顺序(C,A,B,D):

    k    r
A = 1    7    --> 56
B = 2    7    --> 78
C = 3    7    --> 23
D = 4    7    --> 80

每次使用r = 7都会产生相同的数字=>同样的顺序。

我正在寻找一个用k和r进行计算的数学函数。播种RAND()函数不合适,因为我们支持的某些数据库不支持

请注意,r已经是随机生成的数字


背景

一个表 - 两个数据消费者。一个消费者将随机获得5%的表,另一个消费者将获得另外95%的消费者。他们不只是获取数据而是生成SQL。所以有两个SQL不能两次选择相同的数据,但仍然是随机的。

3 个答案:

答案 0 :(得分:1)

不确定这是否适用于非SQL Server,但通常在使用RAND()函数时,您可以指定种子。每次指定相同的种子时,随机化都是相同的。

所以,听起来你只需要存储种子编号,并每次使用它来获得相同的随机数。

MSDN Article on RAND

答案 1 :(得分:1)

您可以尝试实现Multiply-With-Carry PseudoRandomNumberGenerator。 C版就像这样(来源:Wikipedia):

m_w = <choose-initializer>;    /* must not be zero, nor 0x464fffff */
m_z = <choose-initializer>;    /* must not be zero, nor 0x9068ffff */

uint get_random()
{
    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);
    return (m_z << 16) + m_w;  /* 32-bit result */
}

在SQL中,您可以创建一个表Random,其中包含两列以包含wz,以及一个ID列来标识每个会话。也许您的供应商支持变量,您无需担心表格。

尽管如此,即使我们使用表,我们也会立即遇到麻烦,因为ANSI SQL不支持无符号的INT。在SQL Server中,我可以切换到BIGINT,不确定您的供应商是否支持。

CREATE TABLE Random (ID INT, [w] BIGINT, [z] BIGINT)

通过在z中插入1并将种子插入w:

来初始化一个新的会话,比如说3
INSERT INTO Random (ID, w, z) VALUES (3, 8921, 1);

然后,每次要生成新的随机数时,请执行以下计算:

UPDATE Random
SET
  z = (36969 * (z % 65536) + z / 65536) % 4294967296,
  w = (18000 * (w % 65536) + w / 65536) % 4294967296
WHERE ID = 3

(注意我如何用div和mod操作替换按位操作数以及如何在计算之后,你需要将mod 4294967296保持在正确的32位无符号int范围内。)

然后选择新值:

SELECT(z * 65536 + w) % 4294967296
FROM Random
WHERE ID = 3

SQLFiddle demo

答案 2 :(得分:0)

每个供应商都以自己的方式解决了这个问题。创建自己的实现很困难,因为很难生成随机数。

<强>的Oracle 可以使用种子http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_random.htm#i998255

初始化dbms_random

SQL Server 第一次调用RAND()可以提供种子:http://technet.microsoft.com/en-us/library/ms177610.aspx

<强> MySQL的 第一次调用RAND()可以提供种子:http://dev.mysql.com/doc/refman/4.1/en/mathematical-functions.html#function_rand

<强> PostgreSQL的 使用SET SEED或SELECT setseed():http://www.postgresql.org/docs/8.3/static/sql-set.html