0

我有一个包含日期、id 和值的表,每个日期大约有 1000 个 id 行。我需要按日期计算每行的百分位数。我将以下代码用于单个日期的百分位排名,但是对于超过 10 年的每日数据,按日期运行的效率非常低。似乎它应该能够在 MySQL 中制定,但我无法使其工作。

Date   ID    Value
date1  01    -7.2
date1  02     0.6
date2  01     1.2
date2  02     3.8

SELECT c.id, c.value, ROUND( (
(@rank - rank) / @rank ) *100, 2) AS rank
FROM (
SELECT * , @prev := @curr , @curr := a.value, 
@nxtRnk := @nxtRnk + 1,
@rank := IF( @prev = @curr , @rank , @nxtRnk ) AS rank
FROM (
SELECT id, value
FROM temp
WHERE date = '2013-06-28'
) AS a, (

SELECT @curr := NULL , @prev := NULL , @rank :=0, @nxtRnk :=0
) AS b
ORDER BY value DESC
) AS c

所以基本上我想选择 DISTINCT(date),然后为每个日期执行上面的 SELECT,在 INSERT INTO table2(...) 之前将结果写入 table2。

谢谢你的帮助,休

4

2 回答 2

0

我终于通过使用临时表开发了一个可接受的解决方案。也许不是最佳解决方案,但它可以在大约 5 秒内在一百万 + 记录表上工作。

我的临时表 (t1) 包含日期和日期的行数。

上面第三个select改为SELECT t1.date, t1.cnt, id, value FROM t1 LEFT JOIN temp ON(t1.date = temp.date)

此外,上面第一个 SELECT 中的计算已更改为使用 c.cnt 而不是 @rank,并创建了一个 @prevDate 变量来重置日期更改时的排名计数。

感谢任何看到这个并试图找到解决方案的人。

于 2013-07-03T21:14:17.273 回答
0

我试图解决这个问题很长一段时间,然后我找到了以下答案。老实说辉煌。即使对于大表也非常快(我使用它的表包含大约 5 百万条记录并且需要几秒钟)。

SELECT 
    CAST(SUBSTRING_INDEX(SUBSTRING_INDEX( GROUP_CONCAT(field_name ORDER BY 
    field_name SEPARATOR ','), ',', 95/100 * COUNT(*) + 1), ',', -1) AS DECIMAL) 
    AS 95th Per 
FROM table_name;

正如您可以想象的那样,只需将 table_name 和 field_name 替换为您的表和列的名称。

欲了解更多信息,请查看Roland Bouman的原帖

于 2017-08-17T12:13:43.757 回答