【问题标题】:Select TOP X (or bottom) percent for numeric values in MySQL为 MySQL 中的数值选择 TOP X(或底部)百分比
【发布时间】:2011-06-12 02:12:07
【问题描述】:

我想知道是否有任何函数可以在 MySQL 中用于从包含数值的列中选择 TOP X(或底部)百分比。

基本上,我有一列包含价格列表,我只想返回价格前 10 个百分位的那些字段。有什么建议?

【问题讨论】:

  • 如果只有 MySQL 支持分析 -- NTILE 专门针对这种情况,但是 ROW_NUMBER、DENSE_RANK、LEAD 和 LAG... 您的查询必须计算派生表/内联视图中的百分位数才能过滤/按它订购。

标签: sql mysql select


【解决方案1】:

更新:来自更多知名人士here 对主题的深思熟虑的解释。尽管如此,MySQL 中似乎仍然没有 嵌入式 函数来计算百分位数。

试试:

SELECT * FROM prices WHERE price >= (SELECT 0.9 * max(price) FROM prices)

SELECT price FROM prices p1 WHERE
(SELECT count(*) FROM prices p2 WHERE p2.price >= p1.price) <=
     (SELECT 0.1 * count(*) FROM prices)
);

这将给出价格 P1,其中 Price 表中具有 price >= P1 的记录数将是总数量的十分之一Price 表中的记录。 之后:

SELECT * FROM prices WHERE price >= (SELECT price FROM prices p1 WHERE
(SELECT count(*) FROM prices p2 WHERE p2.price >= p1.price) <=
     (SELECT 0.1 * count(*) FROM prices)
);

将返回所有需要的记录。

注意:我没有检查此查询的性能,我认为使用临时表/变量的解决方案一定更有效。

【讨论】:

  • 这不是“第 90 个百分位”的意思...您的查询将选择价格为最高价商品 90% 的行。
  • @Matthew 你是对的。我试图弄清楚有什么不同:)
  • @Victor 90% percentile 表示“超过 90% 的值”
  • 看起来这将导致 3 次扫描...对我来说似乎有点低效。
  • 我也在回答中反映了这一点)
【解决方案2】:

编辑 - 新答案

已回复Convert SQL Server query to MySQL

Select *
from
(
    SELECT tbl.*, @counter := @counter +1 counter
    FROM (select @counter:=0) initvar, tbl
    ORDER BY ordcolumn
) X
where counter <= (50/100 * @counter);
ORDER BY ordcolumn


旧答案

对于 MySQL,您可以计算所需的批处理大小,然后限制该记录数

SELECT @rows := ROUND(COUNT(*) * 10/100) FROM table;
PREPARE STMT FROM ‘SELECT * FROM tbl ORDER BY price LIMIT ?’;
EXECUTE STMT USING @rows;

对于最低百分比,只需反向排序

SELECT @rows := ROUND(COUNT(*) * 10/100) FROM table;
PREPARE STMT FROM ‘SELECT * FROM tbl ORDER BY price DESC LIMIT ?’;
EXECUTE STMT USING @rows;

糟糕,也许 DESC 属于第一个查询,但你明白了。

注意 对于 SQL Server,TOP N PERCENT 子句肯定有帮助

select top 10 PERCENT *
FROM TBL
ORDER BY price

【讨论】:

  • 巧妙的技巧,但这不是按价格计算前 10% 的行,而不是价格前 10 个百分位数中的所有行(这似乎是问题所要求的接受的答案;虽然有点模棱两可)
  • 确实很好。 @tardate 只需按 DESC 排序即可将 50/100 更改为 10/100 ..
  • 回到旧答案!不推荐在 SELECT 内分配 @variables。您已经找到了造成这种情况的原因之一。
【解决方案3】:

仅供参考(我知道这个问题已经有几年了),这也可以通过其他更清洁的方式来完成。

SELECT * FROM product_table WHERE price >= (SELECT price FROM product_table 
ORDER BY price DESC LIMIT 1 OFFSET (SELECT 0.1 * COUNT(*) FROM product_table));

我在一个非常大的数据库上运行了一个类似的查询,它运行得非常快。

【讨论】:

  • 谢谢,这正好派上用场了。 “LIMIT 1”的目的是什么?这不是将结果限制为仅从 OFFSET 值开始的 1 吗?
  • 限制 1 将为您提供 90% 的准确值。
  • 这个答案有 MySQL 版本吗?我似乎无法从 select 语句中获取偏移量,(SELECT 0.1 * COUNT(*) FROM product_table)
  • 我面前没有安装 MySQL,但你可以子查询计数吗?基本上,select 0.1 * a.count from (select count(*) from product_table) a;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-21
  • 2016-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多