【问题标题】:Instead of MySQL ORDER BY RAND而不是 MySQL ORDER BY RAND
【发布时间】:2018-02-22 19:17:57
【问题描述】:

我使用这个查询:

SELECT f.id FROM articles f
JOIN ( SELECT RAND() * (SELECT MAX(id) FROM articles) AS max_id ) AS m
WHERE f.id >= m.max_id
ORDER BY f.id ASC
LIMIT 5

问题在于它返回了意外的行数。它可以是 1 行或 3 行或 5 行。但我正好需要 5 行。

【问题讨论】:

  • 你想达到什么目的?选择 5 个随机行?选择 5 个连续的行(按 id 排序,从随机位置开始)?
  • 我想随机选择 5 行

标签: mysql sql random sql-order-by


【解决方案1】:

您的查询可能存在的问题是它仅随机选择一条记录,而其余记录是连续的。如果你想真正随机选择所有5个,你必须一个一个地选择它们:

(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random = f.id) UNION ALL
(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random = f.id) UNION ALL
(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random = f.id) UNION ALL
(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random = f.id) UNION ALL
(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random = f.id)

如果 ID 是连续的且没有间隔,则此方法有效。如果有差距,则必须将等式更改为小于,并限制为一条记录:

(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random <= f.id LIMIT 1) UNION ALL
(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random <= f.id LIMIT 1) UNION ALL
(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random <= f.id LIMIT 1) UNION ALL
(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random <= f.id LIMIT 1) UNION ALL
(SELECT f.id FROM articles f INNER JOIN (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM articles) + 1) AS random) m ON m.random <= f.id LIMIT 1)

但是,就像 dnswlt 在他的answer 中提到的那样。更简单的经典解决方案适用于小表:

SELECT f.id
FROM articles f
ORDER BY RAND()
LIMIT 5

【讨论】:

  • 你的五个连接将返回 0 或 1 行,很可能是 0,除非所有对 RAND 的调用产生相同的值 :)
  • @dnswlt 当然。它需要这些子查询之间的联合。我不知道查询是如何结束的。我想我累了,复制/粘贴内部子查询而不是外部子查询,忘记添加联合。感谢您的来信。
【解决方案2】:

您的问题看起来与MySQL select 10 random rows from 600K rows fast 重复。

根据您的表中有多少行以及您愿意接受的响应时间,您可以先尝试经典变体:

SELECT f.id FROM articles f
ORDER BY RAND()
LIMIT 5

如果少于一百万,这可能就足够了。

否则你可以应用链接文章中描述的技巧,以及UNION ALL 5 个这样的查询,大致如下:

(SELECT r1.id
  FROM articles AS r1 JOIN
       (SELECT CEIL(RAND() *
                     (SELECT MAX(id)
                        FROM articles)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1)
 UNION ALL
 (SELECT r1.id
  FROM articles AS r1 JOIN
       (SELECT CEIL(RAND() *
                     (SELECT MAX(id)
                        FROM articles)) AS id)
        AS r2
 WHERE r1.id >= r2.id
 ORDER BY r1.id ASC
 LIMIT 1)
 UNION ALL
 ... (three more queries to retrieve 5 rows)

如果您的行数很少,则此解决方案中可能会出现重复。但是,如果您的行数很少,则无论如何都可以使用上面更简单的解决方案:)

我为第二个变体创建了SQL Fiddle。 HTH!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-28
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-09
    • 2012-04-18
    相关资源
    最近更新 更多