Наиболее эффективный способ разделения строк по имени и последующего переноса в один столбец для каждого имени - PullRequest
0 голосов
/ 06 июня 2019

Я использую стандартный SQL в Google Bigquery.Итак, у меня есть некоторые данные о метриках в этом формате:

Date        | metric_name  | metric_level
01/02/2019  | metric_one   | 1
02/03/2019  | metric_one   | 2
14/02/2019  | metric_two   | 6
17/02/2019  | metric_two   | 4
01/03/2019  | metric_three | 2
10/03/2019  | metric_three | 7

Я хочу получить их в этом формате, история дат возвращается на один год, а затем каждая метрика заполняется для каждой даты.Если у метрики нет данных на определенную дату, тогда она использует самую последнюю точку данных:

Date        | metric_one   | metric_two   | metric_three
..........
01/02/2019  | 1            | null         | null
02/02/2019  | 1            | null         | null
03/02/2019  | 1            | null         | null
...........
...........
13/02/2019  | 1            | null         | null
14/02/2019  | 1            | 6            | null
15/02/2019  | 1            | 6            | null
...........
...........
09/03/2019  | 2            | 4            | 2
10/03/2019  | 2            | 4            | 7
11/03/2019  | 2            | 4            | 7
...........

и т. Д.

Мне удалось написать некоторый код, который делает это,но я хочу знать, есть ли более эффективный способ сделать это.На самом деле существует более трех метрик, поэтому, если я смогу сделать его более эффективным, то это сэкономит много ресурсов в долгосрочной перспективе.

Это мой код

    WITH date_arr AS(

        SELECT 
        date

        FROM UNNEST(
            GENERATE_DATE_ARRAY(
                DATE_SUB(CURRENT_DATE(),INTERVAL 365 DAY), 
                CURRENT_DATE(), 
                INTERVAL 1 day
            )
        ) AS date

    ),

    metric_one_raw AS (

        SELECT 
        date,
        metric_level

        FROM database
        WHERE metric_name = 'metric_one'

    ),

    metric_one_gapless AS (

        SELECT
        d.date AS date,
        IFNULL(metric_level, LAST_VALUE(metric_level IGNORE NULLS) OVER(window_latest)) AS metric_one

        FROM date_arr d
        LEFT JOIN metric_one_raw i
        ON d.date = i.date
        WINDOW window_latest AS (ORDER BY d.date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

    ),

    metric_two_raw AS (

        SELECT 
        date,
        metric_level

        FROM database
        WHERE metric_name = 'metric_two'

    ),

    metric_two_gapless AS (

        SELECT
        d.date AS date,
        IFNULL(metric_level, LAST_VALUE(metric_level IGNORE NULLS) OVER(window_latest)) AS metric_two

        FROM date_arr d
        LEFT JOIN metric_two_raw i
        ON d.date = i.date
        WINDOW window_latest AS (ORDER BY d.date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

    ),

    metric_three_raw AS (

        SELECT 
        date,
        metric_level

        FROM database
        WHERE metric_name = 'metric_three'

    ),

    metric_three_gapless AS (

        SELECT
        d.date AS date,
        IFNULL(metric_level, LAST_VALUE(metric_level IGNORE NULLS) OVER(window_latest)) AS metric_three

        FROM date_arr d
        LEFT JOIN metric_three_raw i
        ON d.date = i.date
        WINDOW window_latest AS (ORDER BY d.date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

    )

    SELECT
    *
    FROM metric_one_gapless
    LEFT JOIN metric_two_gapless USING(date)
    LEFT JOIN metric_three_gapless USING(date)

Надеюсь, это имеет смысл.Заранее спасибо!

1 Ответ

0 голосов
/ 06 июня 2019

Вы можете сделать следующее:

  • Создать даты
  • Используйте cross join, чтобы получить все строки
  • Используйте left join, чтобы принестив ваших данных
  • Используйте last_value() для заполнения NULL значений.

В другой базе данных я бы предпочел lag(ignore nulls), но BigQuery не поддерживает это.

Итак:

select d, m.metric,
       coalesce(mm.metric_level,
                last_value(mm.metric_level ignore nulls) over (partition by m.metric order by d)
               ) as metric_level
from (select distinct metric from metrics) m cross join
     unnest(gnerate_date_array(date_sub(current_date(), interval 1 year), interval 1 day) d left join
     metrics mm
     on mm.metric = m.metric and mm.date = d;
...