【问题标题】:ORDER BY RAND() for multiple columns (shuffle content of each column vertically)ORDER BY RAND() 用于多列(垂直排列每列的内容)
【发布时间】:2016-08-16 12:23:52
【问题描述】:

我正在寻找一个 mysql 解决方案,让几列从该列输出一个随机字段。

我现在的查询只随机选择整行,但不随机化分隔的列。

$sql = "SELECT col1, col2, col3, col4 FROM table ORDER BY RAND() limit 4";

我尝试了子查询,但我不熟悉,所以如果有人可以帮助...

【问题讨论】:

  • 只需从 PHP 中的结果中随机选择一列。
  • 此表是否有某种 id 字段?
  • 没关系,即使有一个我想不出一个理智的解决方案;并且实际上有一种预感,不同列中的值可能应该存储在单独的表中。
  • 我有一个 id 列是
  • 在阅读了您关于不想随机播放列而是垂直随机播放列内容的评论后,我更新了我的答案(底部查询)。

标签: php mysql random subquery multiple-columns


【解决方案1】:

试试这个:

SELECT CASE rnd
          WHEN 1 THEN col1
          WHEN 2 THEN col2
          WHEN 3 THEN col3
          WHEN 4 THEN col4       
       END AS col          
FROM (       
  SELECT col1, col2, col3, col4,
         FLOOR(RAND() * 4) + 1 AS rnd
  FROM mytable 
ORDER BY RAND() ) AS t

表达式FLOOR(RAND() * 4) + 1 生成一个介于 1 和 4(含)之间的随机数。外部查询使用此数字随机选择表的 4 列之一。

Demo here

编辑:

如果你想 shuffle 列,你可以使用以下查询:

SELECT CASE FIND_IN_SET(1, rnd)
          WHEN 1 THEN col1
          WHEN 2 THEN col2
          WHEN 3 THEN col3
          WHEN 4 THEN col4
       END AS c1,
       CASE FIND_IN_SET(2, rnd)
          WHEN 1 THEN col1
          WHEN 2 THEN col2
          WHEN 3 THEN col3
          WHEN 4 THEN col4
       END AS c2,
       CASE FIND_IN_SET(3, rnd)
          WHEN 1 THEN col1
          WHEN 2 THEN col2
          WHEN 3 THEN col3
          WHEN 4 THEN col4
       END AS c3,
       CASE FIND_IN_SET(4, rnd)
          WHEN 1 THEN col1
          WHEN 2 THEN col2
          WHEN 3 THEN col3
          WHEN 4 THEN col4
       END AS c4
FROM (  
  SELECT col1, col2, col3, col4, 
         (SELECT GROUP_CONCAT(i ORDER BY RAND()) 
          FROM (SELECT 1 AS i UNION ALL SELECT 2 UNION ALL 
                SELECT 3 UNION ALL SELECT 4) t) AS  rnd
  FROM mytable) AS t

Demo here

【讨论】:

  • 查看 fiddle 中的示例我猜它对我不起作用,因为我正在构建一个句子,所以我有几个字符串,并且列代表解析句子的一部分。我实际上需要将文件列垂直打乱,但不与其他列打乱
【解决方案2】:

如果每个结果行都必须是独立的,那么除了选择 16 个随机行之外别无他法(4x4 结果表中的每个单元格一次)。

SELECT 
  (SELECT col1 FROM `table` ORDER BY RAND() LIMIT 1) AS col1,
  (SELECT col2 FROM `table` ORDER BY RAND() LIMIT 1) AS col2,
  (SELECT col3 FROM `table` ORDER BY RAND() LIMIT 1) AS col3,
  (SELECT col4 FROM `table` ORDER BY RAND() LIMIT 1) AS col4
FROM `table`
LIMIT 4

【讨论】:

  • 是的,这就是解决方案。 !!
【解决方案3】:

我认为如果你也随机化 PHP 中的列会更简单,但作为一个有趣的挑战,我想我会像下面那样做。 它会给你随机的 4 行并随机化/随机排列列值。

首先它只是 GROUP_CONCAT 值 1,2,3,4 但随机化顺序..然后使用 FIND_IN_SET 提取数字的索引..然后使用 ELT() 函数根据这些索引选择 col 值。

SELECT 
       ELT(FIND_IN_SET(1,rand_indexes),col1,col2,col3,col4) as col1,
       ELT(FIND_IN_SET(2,rand_indexes),col1,col2,col3,col4) as col2,
       ELT(FIND_IN_SET(3,rand_indexes),col1,col2,col3,col4) as col3,
       ELT(FIND_IN_SET(4,rand_indexes),col1,col2,col3,col4) as col4
FROM 
  (SELECT col1,col2,col3,col4,
     (SELECT GROUP_CONCAT(i ORDER BY RAND()) as indexes FROM
       (SELECT 1 as i UNION SELECT 2 UNION SELECT 3 UNION SELECT 4)indexes
      )as rand_indexes
   FROM `table`
   )T1 
ORDER BY RAND() limit 4

sqlfiddle

更新如果您想像评论中提到的那样垂直随机排列您的列,那么您可以使用此查询。 它基本上以随机顺序选择第一列 4 行,然后与第二列的 4 个随机行连接,依此类推...

SELECT T1.col1,T2.col2,T3.col3,T4.col4
FROM
  (SELECT col1,@order1:=@order1+1 as i 
   FROM (SELECT col1 FROM `table` ORDER BY RAND() LIMIT 4) O1,(SELECT @order1:=0) initialize )T1
  INNER JOIN
  (SELECT col2,@order2:=@order2+1 as i 
   FROM (SELECT col2 FROM `table` ORDER BY RAND() LIMIT 4) O1,(SELECT @order2:=0) initialize )T2
  ON T1.i = T2.i
  INNER JOIN
  (SELECT col3,@order3:=@order3+1 as i 
   FROM (SELECT col3 FROM `table` ORDER BY RAND() LIMIT 4) O1,(SELECT @order3:=0) initialize )T3
  ON T1.i = T3.i
  INNER JOIN
  (SELECT col4,@order4:=@order4+1 as i 
   FROM (SELECT col4 FROM `table` ORDER BY RAND() LIMIT 4) O1,(SELECT @order4:=0) initialize )T4
  ON T1.i = T4.i

sqlfiddle shuffle columns vertically

【讨论】:

  • 在看到@Giorgos Betsos 的答案 FIND_IN_SET 在这里很好用后,我已经更新了我的答案。
  • 在阅读了您关于不想随机播放列而是垂直随机播放列内容的评论后,我更新了我的答案(底部查询)。
【解决方案4】:

这个可以,但是我猜我确定它不是表现很好:

select * from
    (select col1 from table order by rand()) as a, 
    (select col2 from table order by rand()) as b,
    (select col3 from table order by rand()) as c,
    (select col4 from table order by rand()) as d
order by rand()
limit 4;

它对所有 4 个表进行交叉连接(给出 n^4 行),然后获取其中的前 4 行。

更新因为OP询问了a/b/c/d的目的:

ab 等只是 4 个子查询的(随机选择的)别名,可以视为(临时)表名。 它们是引用子查询的语法所必需的。在这个特定的例子中,它们是无用的,但 MySQL(可能还有其他系统)需要它们。

在上面的语句中,列名已经是唯一的,但是考虑一下列名不是唯一的情况并且您想对列执行一些操作,如下所示:

select concat(a.col1, ' ', c.col1), b.col2, d.col2 from
    (select col1 from table order by rand()) as a, 
    (select col2 from table order by rand()) as b,
    (select col1 from table order by rand()) as c,
    (select col2 from table order by rand()) as d
where b.col2 > d.col2
order by rand()
limit 4;

那么这些别名 ad真的需要区分例如col1 来自第一个和第三个子选择。

但是,@PaulSpiegel 的 answer 比我的要好,因为我错过了子查询中的 limit 1

【讨论】:

  • 实际上,您不需要内部的order by 子句,因为外部的子句无论如何都会随机化所有可能的组合。
  • 我不确定。通常select col1 from table 在发布两次时会以相同的顺序给出结果,尽管不能依赖这一点。所以我认为如果没有任何order by,这(通常)会以相同的顺序给出相同的 n^4 行,而外部order by 只是打乱行的顺序,而不是列中的顺序。
  • 因为它是一个交叉连接,它给出了所有可能的组合,其中你选择了 4 个随机组合。内部随机化仍应产生相同的 n^4 组合,只是顺序不同。由于您在不需要的外部随机化。
  • 我想试试这个建议,但我不确定如何解释 as a/b/c/d/ 部分。我的目标是使用单独的文本字符串读取 cols 并将它们连接起来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-16
  • 2019-06-26
相关资源
最近更新 更多