Bigquery Standard SQL - получите медиану за последние 30 дней - PullRequest
0 голосов
/ 05 апреля 2019

Мой стол выглядит так:

документ:

+-----+-------------+-------------------------+
| dId | score       | datetime                |
+-----+-------------+-------------------------+
| A   | 100.0       | 2019-03-08 16:17:34.043 |
| B   | 80.5        | 2019-02-15 16:17:34.043 |
| C   | 70.1        | 2019-03-08 16:17:34.043 |
+-----+-------------+-------------------------+

Я хочу получить средний балл за последние 30 дней.

Мой текущий запрос:

SELECT
  PERCENTILE_CONT(CASE
      WHEN d.datetime >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 day) THEN 1
      ELSE 0 END) OVER(....) AS Median
FROM
  `document` d

Как я могу это сделать?

Ответы [ 2 ]

1 голос
/ 05 апреля 2019

Ниже для BigQuery Standard SQL

#standardSQL
CREATE TEMP FUNCTION Median(arr ARRAY<INT64>) AS (
  IF(MOD(ARRAY_LENGTH(arr), 2) = 1, arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))],
      (arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2) - 1)] + arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))]) / 2)
);
SELECT Median(ARRAY_AGG(score ORDER BY score)) Median
FROM `project.dataset.document`
WHERE DATE(dt) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)

Вы можете общаться, поиграть с выше, используя пример данных из вашего вопроса, как в примере ниже

#standardSQL
CREATE TEMP FUNCTION Median(arr ARRAY<INT64>) AS (
  IF(MOD(ARRAY_LENGTH(arr), 2) = 1, arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))],
      (arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2) - 1)] + arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))]) / 2)
);
WITH `project.dataset.document` AS (
  SELECT 'A' dId, 100 score, DATETIME '2019-03-08 16:17:34.043' dt UNION ALL 
  SELECT 'B', 80, '2019-02-15 16:17:34.043' UNION ALL 
  SELECT 'C', 70, '2019-03-08 16:17:34.043'     
)
SELECT Median(ARRAY_AGG(score ORDER BY score)) Median
FROM `project.dataset.document`
WHERE DATE(dt) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)

с результатом

Row Median   
1   85.0     

Обратите внимание, что вы можете использовать CREATE TEMP FUNCTION Median(arr ANY TYPE) AS (..., чтобы сделать его более универсальным и принять любой тип последовательности

Обновление

Ниже приведен пример работы с NUMERIC

#standardSQL
CREATE TEMP FUNCTION Median(arr ANY TYPE) AS (
  IF(MOD(ARRAY_LENGTH(arr), 2) = 1, arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))],
      (arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2) - 1)] + arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))]) / 2)
);
WITH `project.dataset.document` AS (
  SELECT 'A' dId, CAST(100.0 AS numeric) score, DATETIME '2019-03-08 16:17:34.043' datetime UNION ALL 
  SELECT 'B', 80.5, '2019-02-15 16:17:34.043' UNION ALL 
  SELECT 'C', 70.1, '2019-03-08 16:17:34.043'     
)
SELECT Median(ARRAY_AGG(CAST(score AS FLOAT64) ORDER BY score)) Median
FROM `project.dataset.document`
WHERE DATE(datetime) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)

Обновление

Хорошо. Обнаружена причина внутренней ошибки - из-за упорядочения по числовому значению
Итак, окончательная версия:

#standardSQL
CREATE TEMP FUNCTION Median(arr ANY TYPE) AS (
  IF(MOD(ARRAY_LENGTH(arr), 2) = 1, arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))],
      (arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2) - 1)] + arr[OFFSET(DIV(ARRAY_LENGTH(arr), 2))]) / 2)
);
WITH `project.dataset.document` AS (
  SELECT 'A' dId, CAST(100.0 AS numeric) score, DATETIME '2019-03-08 16:17:34.043' datetime UNION ALL 
  SELECT 'B', 80.5, '2019-02-15 16:17:34.043' UNION ALL 
  SELECT 'C', 70.1, '2019-03-08 16:17:34.043'     
)
SELECT Median(ARRAY_AGG(score ORDER BY CAST(score AS FLOAT64))) Median
FROM `project.dataset.document`
WHERE DATE(datetime) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
0 голосов
/ 08 апреля 2019

Вы можете сделать это с PERCENTILE_CONT.Просто найдите 0.5 PERCENTILE_CONT всех результатов, отфильтрованных за последний месяц, с помощью предложения WHERE.если вы хотите получить его в отдельном виде.Вот запрос ...

SELECT
  PERCENTILE_CONT(score, 0.5) OVER() AS Median
FROM
  `document` d
WHERE
   d.datetime >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 day)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...