如何让 MySQL 以随机顺序自动递增?

Mic*_*wan 5 mysql order-by auto-increment random

我有一个表,其中包含进入其他表的几个键(其中每个键由多列组成)。我想为每个键创建一个新列,该列将是一个整数,以便该值i表示该ith键的出现(但我希望该排序是随机的)。我想也许某种自动增量会起作用,但我有多个键,因此需要多列(我相信只允许一个自动增量)。

我想出的解决方案似乎不起作用。首先,我创建了一个新表来存储我感兴趣的列,以及一个额外的列rnd. 我rnd稍后会ORDER BY rand()在需要实际列而不是函数的上下文中使用。这是我如何完成第一点:

SET @rnd = 0;
INSERT INTO new_table SELECT col1, ..., colN, @rnd := @rnd+1 FROM original_table ORDER BY rand();
Run Code Online (Sandbox Code Playgroud)

接下来,我将根据键添加一个自动增量,并使用rnd我刚刚创建的列。在ALTER TABLE...ORDER BY不通过函数(如允许排序rand()),所以这就是为什么我需要创建的rnd第一列:

ALTER TABLE new_table ADD first_index INT UNSIGNED NOT NULL AUTO_INCREMENT, ADD KEY(col1, col2, first_index), ORDER BY rnd;
Run Code Online (Sandbox Code Playgroud)

然后我会删除自动增量状态并为每个键重复:

ALTER TABLE new_table MODIFY COLUMN first_index INT UNSIGNED NOT NULL;
Run Code Online (Sandbox Code Playgroud)

起初,这似乎奏效了。然而,仔细检查后,似乎没有遵守随机排序。索引列的创建顺序与原始表碰巧使用的顺序相同。当我经历了几个非常尴尬的步骤以确保随机排序时,我感到相当沮丧,而这甚至不起作用。为什么我的解决方案不起作用,有没有更优雅的方法来做到这一点?

编辑:显然我不清楚我在找什么,所以我会尝试一个简单的例子:

Col1   Col2   <other columns>
1997   A
1997   B
2001   B
1997   A
2001   B
1997   A
2001   A
1997   B
Run Code Online (Sandbox Code Playgroud)

上述排序反映了既不是真正可预测的也不是真正随机的原始排序。添加我的rnd列并按它排序后,我会有这样的事情:

Col1   Col2   <other columns>   rnd
1997   B                        1
2001   A                        2
1997   B                        3
2001   B                        4
1997   A                        5
1997   A                        6
1997   A                        7
2001   B                        8
Run Code Online (Sandbox Code Playgroud)

然后我会得到这样的第一个索引:

Col1   Col2   <other columns>   rnd    first_index
1997   B                        1      1
2001   A                        2      1
1997   B                        3      2
2001   B                        4      1
1997   A                        5      1
1997   A                        6      2
1997   A                        7      3
2001   B                        8      2
Run Code Online (Sandbox Code Playgroud)

所以 1997 年 B 出现了 2 次,因此这些值从 1-2 编号,而 1997 年 A 出现了 3 次,因此这些值行编号为 1-3。我使用了ORDER BY rnd1997-A 的哪一行被分配了索引 1,哪一行得到了 2,哪一行得到了 3(当然,在初始分配之后这将是确定性的)。

编辑:我将添加另一个示例,因为我的目标似乎不清楚。MySQL 文档显示了一种几乎可以到达的方法:

CREATE TABLE animals (
    grp ENUM('fish','mammal','bird') NOT NULL,
    id MEDIUMINT NOT NULL AUTO_INCREMENT,
    name CHAR(30) NOT NULL,
    PRIMARY KEY (grp,id)
) ENGINE=MyISAM;

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;
Run Code Online (Sandbox Code Playgroud)

这将创建一个表,虽然不是我想要的,但它很接近:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+
Run Code Online (Sandbox Code Playgroud)

这很接近,但我认为这对我不起作用至少有两个原因。首先,我需要在现有表上执行此操作,而不是在我正在创建的表上执行此操作。其次,我不想仅仅因为它在底层表中dog首先出现在mammal组中。有一次,我想随机化该顺序。从那时起,排序将是确定性的,但我希望它首先是随机的。

如果你想知道我想要这样做的动机,这里有一个问题解释了我想用这个做什么。另请注意,解决方案应在 MySQL 中。

goo*_*orj 2

这就是我要做的。我希望我正确理解了你的问题。这是一种解决方法,也许不是很优雅:

  • 创建一个随机字段,然后创建一个 AUTO_INCRMENT 字段(“ID”)作为主键的单个字段,按 RND 等排序
  • 为 Col1/2 的每个组合创建一个带有 MIN(ID) 的临时表(首先,但随机):

SELECT
  MIN(ID) AS MIN_ID, Col1, Col2 
FROM 
  table 
GROUP BY 
 Col1, Col2
Run Code Online (Sandbox Code Playgroud)
  • 添加第二个 INT 字段作为first_index
  • 更新表,将first_index设置为自增字段的最小值与运行值的差:

UPDATE 
  table t, temp_table tmp
SET 
  t.first_index = (t.ID - tmp.MIN_ID) + 1
WHERE 
  t.Col1=tmp.Col1 AND t.Col2=tmp.Col2 
Run Code Online (Sandbox Code Playgroud)
  • 可以选择删除随机和 ID 字段,并添加一个新的 PK,其中包含三个字段 Col1/Col2/first_index (自动递增)以进行后续插入