Проверка ЗАДЕРЖКИ и ОПЕРЕЖЕНИЯ до НУЛЯ при выполнении условия BigQuery

#google-bigquery

#google-bigquery

Вопрос:

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: я приношу свои извинения, если выражение этой проблемы слишком сложно. Я старался изо всех сил. У меня было действительно приблизительное представление о том, как это решить, поэтому я добавляю код ниже, хотя это не способствует решению моей проблемы. Спасибо.

У меня есть такая таблица:

введите описание изображения здесь

 WITH table1 AS (

  SELECT  '2020-12-01 00:00:06 UTC' Datetime,   NULL Column1,  'A0' Column2, 'x' Column3 UNION ALL
  SELECT  '2020-12-01 00:00:16 UTC',           'A1',           'A0',         'x'  UNION ALL
  SELECT  '2020-12-01 00:00:26 UTC',           'A1',           'A1',         'y'  UNION ALL
  SELECT  '2020-12-01 00:00:36 UTC',           'A1',           'A1',         'y'  UNION ALL
  SELECT  '2020-12-01 00:00:46 UTC',           'A1',           'A2',         'z'  UNION ALL
  SELECT  '2020-12-01 00:00:56 UTC',           'A1',           'A2',         'z'  UNION ALL
  SELECT  '2020-12-01 00:00:66 UTC',           NULL,           'A2',         'z'  UNION ALL
  SELECT  '2020-12-01 00:01:06 UTC',           NULL,           'A2',         'z'   
)  

select * from table1
 

Я хочу создать новый столбец и добавить каждое значение из Column3 на всю длину Column1, где NULLS являются границами, если условие (Column1 = Column2) было выполнено хотя бы один раз.

Подробное объяснение: я хочу сначала проверить условие Column1 = Column2; когда это верно, я хочу проверить значение в Column3. В моем случае это «y». Когда условие выполнено, я хочу выполнить ЗАДЕРЖКУ и ОПЕРЕЖЕНИЕ до НУЛЯ в столбце 1, а затем применить ‘y’ для всей длины A1 в столбце 1 к новому столбцу Column4. Если условие Column1 = Column2 не будет выполнено в первую очередь, в Column4 должно быть NULL .

Тогда выходная таблица будет:

введите описание изображения здесь

Я пробовал использовать приведенный ниже код, но, к сожалению, единственное, что он делает, это беспорядок.

 select *,
case when lag(Column1) over (partition by Column1 = Column2 order by DateTime) is null
             then Column3
     when lead(Column1) over (partition by Column1 = Column2 order by DateTime) is null
             then Column3
             else NULL
        end as Column4
from XX.YY.ZZ 
order by datetime
 

Ответ №1:

Вы можете решить это с помощью нескольких оконных функций.

Нужно сделать 2 вещи:
1- Получить значение из столбца 3, если столбец 1 = столбец 2 (простая часть :))
2- Найти группы столбцов 1 (острова)

Для первого довольно ясно, что я делаю:
IF(Column1 = Column2, Column3, NULL) Col4_temp,

Для второй проблемы, 1- я пытаюсь найти изменения в column1. Если значение Column1 отличается от предыдущей строки, я отмечаю его 1, в противном случае 0.

Чтобы иметь возможность это сделать, сначала я привожу значение из предыдущей строки с LAG(Column1) помощью . Если оно равно значению Column1, я возвращаю 0, в противном случае 1.

Если предыдущая строка равна NULL, это сравнение также возвращает NULL, поэтому я заполняю его с помощью COALESCE и также помечаю его как 1.

Весь код отслеживания изменений находится здесь:
COALESCE(IF(Lag(Column1) over wd = Column1, 0, 1), 1) as Col1_changes

На следующем шаге я суммирую общее количество изменений. Если изменений нет, это означает, что они находятся в одной группе.
sum(Col1_changes) over (order by Datetime) as Col1_Group

В Col1_Group вы можете видеть, что я сгруппировал Column1 на основе изменений. Наконец, я получаю максимальное значение внутри каждого Col1_Group и присваиваю его Column4.

Надеюсь, теперь все ясно 🙂 Если нет, я бы рекомендовал вам узнать больше о функциях окна.

Весь код здесь:

 WITH t1 AS (

  SELECT  '2020-12-01 00:00:06 UTC' Datetime,   NULL Column1,  'A0' Column2, 'x' Column3 UNION ALL
  SELECT  '2020-12-01 00:00:16 UTC',           'A1',           'A0',         'x'  UNION ALL
  SELECT  '2020-12-01 00:00:26 UTC',           'A1',           'A1',         'y'  UNION ALL
  SELECT  '2020-12-01 00:00:36 UTC',           'A1',           'A1',         'y'  UNION ALL
  SELECT  '2020-12-01 00:00:46 UTC',           'A1',           'A2',         'z'  UNION ALL
  SELECT  '2020-12-01 00:00:56 UTC',           'A1',           'A2',         'z'  UNION ALL
  SELECT  '2020-12-01 00:00:66 UTC',           NULL,           'A2',         'z'  UNION ALL
  SELECT  '2020-12-01 00:01:06 UTC',           NULL,           'A2',         'z'   
),
t2 AS
(
    select *, 
        IF(Column1 = Column2, Column3, NULL) Col4_temp,
        COALESCE(IF(Lag(Column1) over wd = Column1, 0, 1), 1) as Col1_changes
    from t1
    window wd as (order by Datetime)
),
t3 as
(
    select *,
        sum(Col1_changes) over (order by Datetime) as Col1_Group
    from t2
)
select *,
    MAX(Col4_temp) over (partition by Col1_Group) as Column4
from t3
 

Вывод запроса

Комментарии:

1. Большое спасибо за это! Я просмотрел код, но мне понадобится некоторое время, чтобы полностью понять его 🙂 Только одно; во 2-й строке в Column4 вместо y стоит NULL. Я безуспешно пытался исправить это, изменив ваш запрос. Не могли бы вы помочь мне решить?

2. Удивительно, это то, что я искал. Я очень благодарен за все объяснение. Я определенно многому научился в этом случае и вашем решении. Еще раз спасибо!:)