【问题标题】:How to shuffle a column in MySql如何在 MySql 中洗牌
【发布时间】:2013-09-02 08:07:17
【问题描述】:

在没有找到任何符合我需要的东西后,我编写了这段代码来不断地打乱 mysql 中列的值。有没有更好的方法来做到这一点?

**Original table:**
+----+-----------+
| id | fname     |
+----+-----------+
|  1 | mike      |
|  2 | ricky     |
|  3 | jane      |
|  4 | august    |
|  6 | dave      |
|  9 | Jérôme    |
+----+-----------+

**Possible output:**
+----+-----------+
| id | fname     |
+----+-----------+
|  1 | dave      |
|  2 | jane      |
|  3 | mike      |
|  4 | ricky     |
|  6 | Jérôme    |
|  9 | august    |
+----+-----------+

DROP TEMPORARY TABLE IF EXISTS shuffle1;
DROP TEMPORARY TABLE IF EXISTS shuffle2;
CREATE TEMPORARY TABLE shuffle1 (id int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (id), original_values varchar(255), key original_values(original_values) );
CREATE TEMPORARY TABLE shuffle2 (id int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (id), original_ids int(11), key original_ids(original_ids) );
INSERT INTO shuffle1 (id, original_values) SELECT NULL, table1.fname FROM table1 ORDER BY rand();
INSERT INTO shuffle2 (id, original_ids) SELECT NULL, table1.id FROM table1;
UPDATE table1 SET table1.fname = (SELECT shuffle1.original_values FROM shuffle1 JOIN shuffle2 ON shuffle2.id = shuffle1.id WHERE table1.id = shuffle2.original_ids);

【问题讨论】:

  • 你的目标是什么?
  • 数据清理:假设您有一个生产表,其中包含您的客户列表,其中包含两列 - first_name 和 last_name,您想在测试环境中使用它,但此信息很敏感。改组其中一列可以维护所有原始值和用户的隐私。
  • 你可能会做的是复制整个数据库,然后打乱某些列的值,用随机数据替换它们。至少可以说,您在这里所做的事情相当令人困惑。
  • 这是一种方法 - 但对于大量数据来说速度非常慢。但保留原始值而不是随机化数据的真正好处是,您知道您的测试涵盖了您的实际情况(例如特殊字符等),而不是基于开发人员做出的假设的一些随机数据。
  • 我不确定您何时说要保留初始值隐藏敏感信息。数据要么在数据库中,要么不在。如果您将数据库转储发送给开发人员,请确保随机数据在结构上与真实数据等效。也就是说,使字符概率与实际数据中的相似,字符串长度也在等效分布曲线中。

标签: mysql shuffle


【解决方案1】:

如果您不介意某些表格数据无法处理(取决于表格大小,预计 50% 的行无法处理),这里有一个解决方案:

原表

id  name
1   Some
2   Body
3   Once
4   Told
5   Me
6   The
7   World
8   Is
9   Gonna
10  Roll
11  Me
12  I 
13  Ain't
14  The 
15  Shapest
16  Tool
17  In
18  The
19  Shed
20  She
21  was
22  looking
23  kind
24  of
25  dumb
26  with
27  her
28  finger
29  and
30  her
31  thumb

查询:

SELECT new_id, name FROM (
    SELECT  new_id, name FROM (
        SELECT new_meme.id as new_id, original_meme.id as original_id, original_meme.name FROM meme original_meme
        JOIN meme new_meme ON new_meme.id <>  original_meme.id
        ORDER BY RAND()
    ) layer1
    GROUP BY layer1.new_id
) layer2 GROUP BY name

结果(当然每次运行都不同)

1   I 
2   In
3   Gonna
4   Ain't
5   The
6   her
7   finger
8   Some
9   dumb
10  She
15  Me
16  with
17  Told
18  and
19  World
21  Roll
22  The 
25  Tool
26  Shed
27  Is
28  Me
29  Sharpest
31  The

注意:您可能会发现查询很慢,这是因为两次加入表,所以如果数据大小为1000,则需要处理1000 * 1000。

您可以通过将ON new_meme.id &lt;&gt; original_meme.id 更改为ON new_meme.id BETWEEN original_meme.id - 5 AND original_meme.id +5 来控制查询的速度(5 可以更改),但它会降低随机性并且不适用于非数字id

【讨论】:

    【解决方案2】:
    UPDATE table1 SET fname=(SELECT t.fname FROM(SELECT fname FROM table1) t ORDER BY RAND() LIMIT 1)
    

    【讨论】:

    • 这不是洗牌代码,因为它不能保证原始列中的所有值都会显示在结果中。所有原始值都需要在那里,只是顺序不同。
    猜你喜欢
    • 1970-01-01
    • 2022-06-28
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多