SQL 查询中的四分位数

Ham*_*mma 4 mysql sql percentile quantile

我有一个非常简单的表格:

CREATE TABLE IF NOT EXISTS LuxLog (
  Sensor TINYINT,
  Lux INT,
  PRIMARY KEY(Sensor)
)
Run Code Online (Sandbox Code Playgroud)

它包含来自不同传感器的数千个日志。

我希望所有传感器都有 Q1 和 Q3。

我可以对每个数据进行一次查询,但最好对所有传感器进行一次查询(从一次查询中获取 Q1 和 Q3)

我认为这将是一个相当简单的操作,因为四分位数被广泛使用并且是频率计算中的主要统计变量之一。事实是,我发现了大量过于复杂的解决方案,而我希望找到一些简洁明了的解决方案。

任何人都可以给我一个提示?

编辑:这是我在网上找到的一段代码,但它对我不起作用:

SELECT  SUBSTRING_INDEX(
        SUBSTRING_INDEX(
            GROUP_CONCAT(                 -- 1) make a sorted list of values
                Lux
                ORDER BY Lux
                SEPARATOR ','
            )
        ,   ','                           -- 2) cut at the comma
        ,   75/100 * COUNT(*)        --    at the position beyond the 90% portion
        )
    ,   ','                               -- 3) cut at the comma
    ,   -1                                --    right after the desired list entry
    )                 AS `75th Percentile`
    FROM    LuxLog
    WHERE   Sensor=12
    AND     Lux<>0
Run Code Online (Sandbox Code Playgroud)

我得到 1 作为返回值,而它应该是一个可以被 10 整除的数字(10,20,30.....1000)

小智 5

使用 NTILE 非常简单,但它是一个 Postgres 函数。你基本上只是做这样的事情:

SELECT value_you_are_NTILING,
    NTILE(4) OVER (ORDER BY value_you_are_NTILING DESC) AS tiles
FROM
(SELECT math_that_gives_you_the_value_you_are_NTILING_here AS value_you_are_NTILING FROM tablename);
Run Code Online (Sandbox Code Playgroud)

这是我在 SQLFiddle 上为您制作的一个简单示例:http ://sqlfiddle.com/#!15/7f05a/1

在 MySQL 中,您将使用 RANK...这是 SQLFiddle:http ://www.sqlfiddle.com/#!2/d5587 /1 (这来自下面链接的问题)

MySQL RANK() 的这种使用来自于 Stackoverflow 的回答: MySQL 中的 Rank function

寻找 Salman A 的答案。

  • 好吧,对于这项工作来说,`NTILE()` 的最大问题是 MySQL 没有它(问题被标记为 mysql)。 (2认同)
  • 这不是浪费时间。我在Mysql中添加了一个链接到RANK函数的讨论。这给了你你正在寻找的东西。 (2认同)
  • 我猜`NTILE` [已添加](https://dev.mysql.com/doc/refman/8.0/en/window-function-descriptions.html#function_ntile) 到`MySQL 8` (2认同)

Pho*_*rze 5

请参阅 SqlFiddle:http : //sqlfiddle.com/#!9/accca6/2/6注意:对于 sqlfiddle,我生成了 100 行,1 到 100 之间的每个整数都有一行,但它是一个随机顺序(完成在excel中)。

这是代码:

SET @number_of_rows := (SELECT COUNT(*) FROM LuxLog);
SET @quartile := (ROUND(@number_of_rows*0.25));
SET @sql_q1 := (CONCAT('(SELECT "Q1" AS quartile_name , Lux, Sensor FROM LuxLog ORDER BY Lux DESC LIMIT 1 OFFSET ', @quartile,')'));
SET @sql_q3 := (CONCAT('( SELECT "Q3" AS quartile_name , Lux, Sensor FROM LuxLog ORDER BY Lux ASC LIMIT 1 OFFSET ', @quartile,');'));
SET @sql := (CONCAT(@sql_q1,' UNION ',@sql_q3));
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;
Run Code Online (Sandbox Code Playgroud)

编辑 :

SET @current_sensor := 101;
SET @quartile := (ROUND((SELECT COUNT(*) FROM LuxLog WHERE Sensor = @current_sensor)*0.25));
SET @sql_q1 := (CONCAT('(SELECT "Q1" AS quartile_name , Lux, Sensor FROM LuxLog WHERE Sensor=', @current_sensor,' ORDER BY Lux DESC LIMIT 1 OFFSET ', @quartile,')'));
SET @sql_q3 := (CONCAT('( SELECT "Q3" AS quartile_name , Lux, Sensor FROM LuxLog WHERE Sensor=', @current_sensor,' ORDER BY Lux ASC LIMIT 1 OFFSET ', @quartile,');'));
SET @sql := (CONCAT(@sql_q1,' UNION ',@sql_q3));
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;
Run Code Online (Sandbox Code Playgroud)

基本推理如下:对于四分位数 1,我们希望从顶部获得 25%,因此我们想知道有多少行,即:

SET @number_of_rows := (SELECT COUNT(*) FROM LuxLog);
Run Code Online (Sandbox Code Playgroud)

现在我们知道了行数,我们想知道其中的 25% 是多少,就是这一行:

SET @quartile := (ROUND(@number_of_rows*0.25));
Run Code Online (Sandbox Code Playgroud)

然后要找到一个四分位数,我们要按 Lux 对 LuxLog 表进行排序,然后获取行号“@quartile”,为此我们将 OFFSET 设置为 @quartile 表示我们要从行开始选择number @quartile 并且我们说 limit 1 表示我们只想检索一行。那是 :

SET @sql_q1 := (CONCAT('(SELECT "Q1" AS quartile_name , Lux, Sensor FROM LuxLog ORDER BY Lux DESC LIMIT 1 OFFSET ', @quartile,')'));
Run Code Online (Sandbox Code Playgroud)

我们对另一个四分位数(几乎)做同样的事情,但不是从顶部开始(从较高的值到较低的值),而是从底部开始(它解释了 ASC)。

但是现在我们只有字符串存储在变量@sql_q1 和@sql_q3 中,所以连接它们,我们合并查询的结果,准备查询并执行它。