1

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

当前(随机)选择:

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,所有数字都会发生变化。

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

更抽象

从我的数据(AD)开始。k是密钥,r是当前使用的随机数:

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

在每一行中使用kr进行一些计算,我想得到类似的东西:

    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 不能两次选择相同的数据,但仍然是随机的。

4

3 回答 3

1

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

因此,听起来您只需要存储种子号并每次都使用它来获得相同的随机数集。

关于兰德的 MSDN 文章

于 2013-10-24T14:11:19.400 回答
1

You could try and implement the Multiply-With-Carry PseudoRandomNumberGenerator. The C version goes like this (source: 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 */
}

In SQL, you could create a table Random, with two columns to contain w and z, and one ID column to identify each session. Perhaps your vendor supports variables and you need not bother with the table.

Nonetheless, even if we use a table, we immediately run into trouble cause ANSI SQL doesn't support unsigned INTs. In SQL Server I could switch to BIGINT, unsure if your vendor supports that.

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

Initialize a new session, say number 3, by inserting 1 into z and the seed into w:

INSERT INTO Random (ID, w, z) VALUES (3, 8921, 1);

Then each time you wish to generate a new random number, do the computations:

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

(Note how I have replaced bitwise operands with div and mod operations and how, after computing, you need to mod 4294967296 to stay within the proper 32 bits unsigned int range.)

And select the new value:

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

SQLFiddle demo

于 2013-10-24T18:19:47.583 回答
0

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

Oracle dbms_random 可以用种子初始化:http ://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_random.htm#i998255

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

MySql First call to 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

于 2013-10-24T14:18:53.807 回答