Quartiles in SQL query

前端 未结 6 2075
面向向阳花
面向向阳花 2020-12-11 07:44

I have a very simple table like that:

CREATE TABLE IF NOT EXISTS LuxLog (
  Sensor TINYINT,
  Lux INT,
  PRIMARY KEY(Sensor)
)

It contains

6条回答
  •  离开以前
    2020-12-11 07:57

    See SqlFiddle : http://sqlfiddle.com/#!9/accca6/2/6 Note : for the sqlfiddle I've generated 100 rows, each integer between 1 and 100 has a row, but it is a random order (done in excel).

    Here is the code :

    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;
    

    EDIT :

    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;
    

    Underlying reasoning is as follows : For quartile 1 we want to get 25% from the top so we want to know how much rows there are, that's :

    SET @number_of_rows := (SELECT COUNT(*) FROM LuxLog);
    

    Now that we know the number of rows, we want to know what is 25% of that, it is this line :

    SET @quartile := (ROUND(@number_of_rows*0.25));
    

    Then to find a quartile we want to order the LuxLog table by Lux, then to get the row number "@quartile", in order to do that we set the OFFSET to @quartile to say that we want to start our select from the row number @quartile and we say limit 1 to say that we want to retrieve only one row. That's :

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

    We do (almost) the same for the other quartile, but rather than starting from the top (from higher values to lower) we start from the bottom (it explains the ASC).

    But for now we just have strings stored in the variables @sql_q1 and @sql_q3, so the concatenate them, we union the results of the queries, we prepare the query and execute it.

提交回复
热议问题