5-й процентиль MySQL (MariaDB) - PullRequest
       51

5-й процентиль MySQL (MariaDB)

2 голосов
/ 25 января 2020

Я пытаюсь найти 95-й процентиль (и самую высокую покупку) цены товара, используя заказ в моей таблице строк ~ 300k.

Мне удалось найти 95-й процентиль и самая высокая покупка для одного предмета с этим кодом:

 SELECT type_id,
       Max(price) AS buy,
       Min(price) AS '95th% buy'
FROM   (SELECT *,
               ( Row_number()
                   OVER (
                     partition BY type_id
                     ORDER BY price DESC) ) AS rownr
        FROM   orderbuffertest AS rownr
        WHERE  is_buy_order = 1
        ORDER  BY ( Row_number()
                      OVER (
                        partition BY type_id
                        ORDER BY price DESC) ) ASC) AS t1
WHERE  t1.type_id = 44992
       AND t1.rownr < (SELECT Count(*)
                       FROM   orderbuffertest
                       WHERE  is_buy_order = 1
                              AND type_id = 44992) * 0.05;  

Однако, сейчас я пытаюсь GROUP BY type_id, и это портит все мои ценности.

У кого-нибудь есть идея? как GROUP BY type_id этот запрос? Может быть, даже способы улучшить оригинальный?

Заранее благодарю,

TheJozzle

Ps. Вот ссылка на мою базу данных, если вы хотите поэкспериментировать с ней: https://gofile.io/?c=Ga6ODr

1 Ответ

2 голосов
/ 25 января 2020

Этот запрос должен дать вам результаты, которые вы хотите. Он выделяет ROW_NUMBER на price, а также считает все строки для каждого type_id и типа заказа (is_buy_order) в CTE, а затем выбирает цену MAX в качестве цены buy (для * 1007). *), а минимальная цена для строк> = 95-й процентиль как цена 95-го процентиля. Если в 95-м процентиле нет строк, отличных от самой высокой цены, возвращается вторая по величине цена. Аналогичные логики c применимы к генерации цен sell и 95th%sell:

WITH prices AS (
  SELECT type_id, price, is_buy_order,
         ROW_NUMBER() OVER (PARTITION BY type_id, is_buy_order ORDER BY price DESC) AS rownr,
         COUNT(*) OVER (PARTITION BY type_id, is_buy_order) AS num_rows
  FROM   orderbuffertest
)
SELECT type_id,
       MAX(CASE WHEN is_buy_order = 1 THEN price END) AS buy,
       COALESCE(MIN(CASE WHEN is_buy_order = 1 AND 100.0 * (rownr - 1) / num_rows <= 5 AND rownr != 1 THEN price END), 
                MAX(CASE WHEN is_buy_order = 1 AND rownr = 2 THEN price END)) AS `95th%buy`,
       MIN(CASE WHEN is_buy_order = 0 THEN price END) AS sell,
       COALESCE(MAX(CASE WHEN is_buy_order = 0 AND 100.0 * rownr / num_rows >= 95 AND rownr != num_rows THEN price END), 
                MAX(CASE WHEN is_buy_order = 0 AND rownr = num_rows - 1 THEN price END)) AS `95th%sell`
FROM prices
GROUP BY type_id

Если вы по какой-то причине не можете использовать CTE, вы можете написать CTE как подзапрос:

SELECT type_id,
       MAX(CASE WHEN is_buy_order = 1 THEN price END) AS buy,
       COALESCE(MIN(CASE WHEN is_buy_order = 1 AND 100.0 * (rownr - 1) / num_rows <= 5 AND rownr != 1 THEN price END), 
                MAX(CASE WHEN is_buy_order = 1 AND rownr = 2 THEN price END)) AS `95th%buy`,
       MIN(CASE WHEN is_buy_order = 0 THEN price END) AS sell,
       COALESCE(MAX(CASE WHEN is_buy_order = 0 AND 100.0 * rownr / num_rows >= 95 AND rownr != num_rows THEN price END), 
                MAX(CASE WHEN is_buy_order = 0 AND rownr = num_rows - 1 THEN price END)) AS `95th%sell`
FROM (
  SELECT type_id, price, is_buy_order,
         ROW_NUMBER() OVER (PARTITION BY type_id, is_buy_order ORDER BY price DESC) AS rownr,
         COUNT(*) OVER (PARTITION BY type_id, is_buy_order) AS num_rows
  FROM   orderbuffertest
) prices
GROUP BY type_id

Демонстрация на dbfiddle

...