Генерация полного ряда дат, когда несколько рядов дат должны быть представлены в одной таблице - PullRequest
1 голос
/ 05 января 2020

Мы собираем данные о программных инструментах, используемых в нашей команде. Одна таблица, которую мы используем для представления использования инструмента в нашей команде, просто подсчитывает, сколько раз этот инструмент запускался за день в команде:

SELECT
  day 
  , num_launches
  , tool_name
FROM
  dataset.by_tool_by_day
ORDER BY day ASC
 ;

Дает вам:

| day         | num_launches | tool_name |
|-------------|--------------|-----------|
| 2019-12-20  | 1            | Tool A    |
| 2019-12-20  | 11           | Tool B    |
| 2019-12-20  | 30           | Tool C    |
| 2019-12-21  | 14           | Tool B    |
| 2019-12-22  | 19           | Tool C    |
| 2019-12-23  | 7            | Tool A    |
| 2019-12-23  | 4            | Tool B    |
| 2019-12-23  | 17           | Tool C    |

Проблема в том случае, если в определенный день не было ни одного запуска инструмента, в таблице нет записи, представляющей 0 запусков инструмента в этот день. В приведенном выше примере не было запусков Инструмента A от 21.12.2009. Отсутствие записи 0 запусков повреждает визуализацию этих данных (например, в столбчатой ​​диаграмме), поскольку дни с запусками 0 не представлены.

Я не могу придумать запрос, который использует таблицу календаря для создать "0 запусков" для каждого инструмента в таблице by_tool_by_day. Это легко сделать, если все записи в таблице относятся к одному инструменту. Но я не могу сделать это, если есть несколько инструментов, а следовательно, и несколько рядов дат, которые должны быть «завершены».

Ответы [ 2 ]

2 голосов
/ 05 января 2020
#standardSQL

WITH 

DATES AS (
  SELECT 
    gen_date 
  FROM 
    UNNEST(GENERATE_DATE_ARRAY(DATE '2019-12-01', DATE '2019-12-23', INTERVAL 1 DAY)) AS gen_date
),

TOOLS AS (
  SELECT 'ToolA' tool_name UNION ALL
  SELECT 'ToolB' tool_name UNION ALL
  SELECT 'ToolC' tool_name 
),

AGG AS (
  SELECT DATE '2019-12-20' day,  1 num_launches, 'ToolA' tool_name UNION ALL
  SELECT DATE '2019-12-20', 11, 'ToolB' UNION ALL
  SELECT DATE '2019-12-20', 30, 'ToolC' UNION ALL
  SELECT DATE '2019-12-21', 14, 'ToolB' UNION ALL
  SELECT DATE '2019-12-22', 19, 'ToolC' UNION ALL
  SELECT DATE '2019-12-23',  7, 'ToolA' UNION ALL
  SELECT DATE '2019-12-23',  4, 'ToolB' UNION ALL
  SELECT DATE '2019-12-23', 17, 'ToolC'
)

SELECT
  D.gen_date AS day,
  T.tool_name,
  IFNULL(A.num_launches, 0) AS num_launches
FROM
  DATES D
CROSS JOIN 
  TOOLS T
LEFT JOIN
  AGG A
ON
  T.tool_name = A.tool_name 
  AND D.gen_date=A.day
ORDER BY
  D.gen_date

Дайте мне знать, работает ли он у вас?

0 голосов
/ 06 января 2020

Я пытался загрузить те же данные, которые вы показывали здесь на BigQuery

Как вы можете видеть ниже, сначала мы должны создать массив дат для дней, которые вы хотите заполнить. Вы можете изменить диапазон дат для нужного вам времени.

Затем мы создаем вспомогательную временную таблицу, выполняя перекрестное соединение между сгенерированными нами датами и всеми различными именами инструментов.

Наконец, мы можем выбрать день, название инструмента и количество запусков (используя IFNULL для обработки определенных c случаев, когда запусков такого инструмента в такую ​​дату нет). Мы выполняем LEFT JOIN из вспомогательной таблицы, чтобы сохранить все даты и названия инструментов.

WITH
date_range AS (
  SELECT
    dates
  FROM
    UNNEST(GENERATE_DATE_ARRAY(DATE '2019-12-01', DATE '2019-12-31', INTERVAL 1 DAY)) AS dates ),
aux AS(
  SELECT
    date_range.dates AS day,
    tool_name,
  FROM
    date_range
  CROSS JOIN (
    SELECT
      DISTINCT tool_name
    FROM
      `deploy.tools`) t )
SELECT
  aux.day,
  aux.tool_name,
  IFNULL(t.num_launches,
    0) AS num_launches
FROM
  aux
LEFT JOIN
  `deploy.tools` t
ON
  aux.day = t.day
  AND aux.tool_name = t.tool_name
ORDER BY
  aux.day,
  aux.tool_name
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...