【问题标题】:How to JOIN the same table with itself using ORDER BY RAND()?如何使用 ORDER BY RAND() 加入同一个表?
【发布时间】:2019-10-23 16:43:33
【问题描述】:

我想获得一张桌子的id 与其自身的随机组合。

SELECT id FROM t1
SELECT id as id2 FROM t1 ORDER BY RAND()
SELECT id as id3 FROM t1 ORDER BY RAND()

我怎样才能JOIN这些查询得到

SELECT id,id2,id3

1    random_id    random_id
2    random_id    random_id
3    random_id    random_id
4    random_id    random_id
5    random_id    random_id

换句话说,JOINing 将这三个 SELECTs 并排放置有什么意义。

创建一个唯一的组合是有益的,但是使用上面的查询ORDER BY RAND() 可以重复相同的idid2id3。前一种情况是理想的,但后者对我来说足够了。

【问题讨论】:

  • id1 和 id2 呢?它们在每一列中是唯一的吗?
  • “随机”是什么意思? id 可以重复列吗?或者你想要一个随机排列?
  • @forpas 不一定是唯一的,因为我们已经通过 RAND() 创建了列表,相同的 id 可以出现在 id2id3 中。当然,拥有一个唯一的集合是有好处的,但如果它只是一个随机值,它仍然对我有用。
  • @GordonLinoff 我更新了问题以澄清问题。

标签: mysql sql join select


【解决方案1】:

如果您使用的是 MySQL 8+,那么ROW_NUMBER 可能在这里工作:

WITH cte AS (
    SELECT id,
        ROW_NUMBER() OVER (ORDER BY id) rn1,
        ROW_NUMBER() OVER (ORDER BY RAND(UNIX_TIMESTAMP())) rn2,
        ROW_NUMBER() OVER (ORDER BY RAND(UNIX_TIMESTAMP()+1)) rn3
    FROM t1
)

SELECT
    t1.id,
    t2.id AS id2,
    t3.id AS id3
FROM cte t1
INNER JOIN cte t2
    ON t1.rn1 = t2.rn2
INNER JOIN cte t3
    ON t1.rn1 = t3.rn3;

下面的演示来自一个示例表,其中包含从 1 到 10 的 id 值。

Demo

【讨论】:

  • 您使用 unix 时间戳播种 rand() 是否有原因?
  • 不幸的是,我仍然使用 MySQL 5.7,但它是未来的好方法。
【解决方案2】:

如果您真的想要随机,则允许重复。这表明:

select t.*,
       (select t2.id
        from t t2
        order by rand()
        limit 1
       ) as id2,
       (select t3.id
        from t t3
        order by rand()
        limit 1
       ) as id3
from t;

如果您想在旧版本的 MySQL 中进行排列,那么变量很方便:

select t.id, t1.id, t2.id
from (select t.id, (@rn := @rn + 1) as seqnum
      from t cross join
           (select @rn := 0) params
     ) t join
     (select t.id, (@rn1 := @rn1 + 1) as seqnum
      from (select t.* from t order by rand()) t cross join
           (select @rn1 := 0) params
     ) t1
     using (seqnum) join
     (select t.id, (@rn2 := @rn2 + 1) as seqnum
      from (select t.* from t order by rand()) t cross join
           (select @rn2 := 0) params
     ) t2 
     using (seqnum);

在 MySQL 8+ 中,Tim 的答案是最好的方法。

Here 是一个数据库小提琴

【讨论】:

  • 这是我的第一次尝试,但它非常昂贵,因为每一行都应该重复子查询。
  • 顺便说一下,作为迈向(不完整)独特组合的一步,我们可以在第一种方法中添加WHERE t2.id<>t.id
  • @Googlebot 。 . .第一个可以调整,这样 ids 就不会重复。没有重复的排列有点棘手。
【解决方案3】:

对于这个从 1n 的顺序 id 的示例数据,这个使用字符串函数的查询将起作用,并将在 id2id3 列中返回所有如果 id 一次:

select t1.id, 
  find_in_set(t1.id, t2.ids2) id2, 
  find_in_set(t1.id, t3.ids3) id3
from tablename t1 
cross join (
  select group_concat(id order by rand()) ids2
  from tablename
) t2
cross join (
  select group_concat(id order by rand()) ids3
  from tablename
) t3

请参阅demo
结果(喜欢):

| id  | id2 | id3 |
| --- | --- | --- |
| 1   | 5   | 4   |
| 2   | 2   | 5   |
| 3   | 1   | 2   |
| 4   | 4   | 3   |
| 5   | 3   | 1   |

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    • 2012-12-28
    • 1970-01-01
    • 2011-02-09
    • 2022-01-23
    相关资源
    最近更新 更多