#sql #google-bigquery
#sql #google-bigquery
Вопрос:
Я объединяю две таблицы.
В первой таблице у меня есть некоторые элементы, начинающиеся в определенное время. Во второй таблице у меня есть значения и временные метки для каждой минуты между временем начала и окончания каждого элемента.
Первая таблица
UniqueID Items start_time
123 one 10:00 AM
456 two 11:00 AM
789 three 11:30 AM
Вторая таблица
UniqueID Items time_hit value
123 one 10:00 AM x
123 one 10:05 AM x
123 one 10:10 AM x
123 one 10:30 AM x
456 two 11:00 AM x
456 two 11:15 AM x
789 three 11:30 AM x
Итак, при объединении двух таблиц у меня есть это:
UniqueID Items start_time time_hit value
123 one 10:00 AM 10:00 AM x
123 null null 10:05 AM x
123 null null 10:10 AM x
123 null null 10:30 AM x
456 two 11:00 AM 11:00 AM x
456 null null 11:15 AM x
789 three 11:30 AM 11:30 AM x
Я хотел бы заменить эти null
значения значениями из ненулевой предшествующей строки…
Таким образом, ожидаемый результат
UniqueID Items start_time time_hit value
123 one 10:00 AM 10:00 AM x
123 one 10:00 AM 10:05 AM x
123 one 10:00 AM 10:10 AM x
123 one 10:00 AM 10:30 AM x
456 two 11:00 AM 11:00 AM x
456 two 11:00 AM 11:15 AM x
789 three 11:30 AM 11:30 AM x
Я безуспешно пытался создать свое соединение, используя следующую функцию:
FIRST_VALUE(Items IGNORE NULLS) OVER (
PARTITION BY time_hit ORDER BY time_hit
ROWS BETWEEN CURRENT ROW AND
UNBOUNDED FOLLOWING) AS test
Мой вопрос был немного не таким. Я обнаружил, что UniqueID были несовместимы, поэтому у меня были эти нулевые значения в моем выводе. Таким образом, проверенный ответ является хорошим вариантом для заполнения нулевых значений при объединении двух таблиц, и одна из ваших таблиц содержит больше уникальных строк, чем другая.
Комментарии:
1. Пожалуйста, укажите ожидаемый результат. Вы также имеете в виду «следующую строку, содержащую
not null
значения»?2. Дайте мне знать, если это понятнее
Ответ №1:
Вы могли бы использовать first_value
(но last_value
это также сработало бы и в этом сценарии). Часть импорта заключается в указании rows between unbounded preceding and current row
для установки границ окна.
Ответ обновлен, чтобы отразить обновленный вопрос, и предпочтение для first_value
select
first_value(t1.UniqueId ignore nulls) over (partition by t2.UniqueId
order by t2.time_hit
rows between unbounded preceding and current row) as UniqueId,
first_value(t1.items ignore nulls) over (partition by t2.UniqueId
order by t2.time_hit
rows between unbounded preceding and current row) as Items,
first_value(t1.start_time ignore nulls) over (partition by t2.UniqueId
order by t2.time_hit
rows between unbounded preceding and current row) as start_time,
t2.time_hit,
t2.item_value
from table2 t2
left join table1 t1 on t1.start_time = t2.time_hit
order by t2.time_hit;
Результат
| UNIQUEID | ITEMS | START_TIME | TIME_HIT | ITEM_VALUE |
|----------|-------|------------|----------|------------|
| 123 | one | 10:00:00 | 10:00:00 | x |
| 123 | one | 10:00:00 | 10:05:00 | x |
| 123 | one | 10:00:00 | 10:10:00 | x |
| 123 | one | 10:00:00 | 10:30:00 | x |
| 456 | two | 11:00:00 | 11:00:00 | x |
| 456 | two | 11:00:00 | 11:15:00 | x |
| 789 | three | 11:30:00 | 11:30:00 | x |
Примечание: Мне пришлось использовать Oracle в SQL Fiddle (поэтому мне пришлось изменить типы данных и имя столбца). Но это должно работать для вашей базы данных.
Комментарии:
1. таким образом, точно такая же функция, которую я использовал, за исключением того, что это last_value вместо first_value … верно?
2. Функции из одного семейства, но имеют разные функции. Смотрите cloud.google.com/bigquery/docs/reference/standard-sql /…
3. В этой ситуации сработало бы либо
first_value
, либоlast_value
, посколькуNULL
s удалены, и в окне существует только одна строка. Значения задаютсяrows between unbounded preceding and current row
условием. Надеюсь, это имеет смысл.4. Лучше разбивать на
UniqueID
для повышения производительности, если это соответствуетItems
значению.
Ответ №2:
Одним из альтернативных решений было бы использовать NOT EXISTS
предложение в качестве JOIN
условия с соответствующим подзапросом, который гарантирует, что мы имеем отношение к соответствующей записи.
SELECT t1.items, t1.start_time, t2.time_hit, t2.value
FROM table1 t1
INNER JOIN table2 t2
ON t1.items = t2.items
AND t1.start_time <= t2.time_hit
AND NOT EXISTS (
SELECT 1 FROM table1 t10
WHERE
t10.items = t2.items
AND t10.start_time <= t2.time_hit
AND t10.start_time > t1.start_time
)
| items | start_time | time_hit | value |
| ----- | ---------- | -------- | ----- |
| one | 10:00:00 | 10:00:00 | x |
| one | 10:00:00 | 10:05:00 | x |
| one | 10:00:00 | 10:10:00 | x |
| one | 10:00:00 | 10:30:00 | x |
| two | 11:00:00 | 11:00:00 | x |
| two | 11:00:00 | 11:15:00 | x |
| three | 11:30:00 | 11:30:00 | x |
Альтернативное решение, позволяющее избежать использования EXISTS
при JOIN
условии (не допускается в большом запросе): просто переместите это условие в WHERE
предложение.
SELECT t1.items, t1.start_time, t2.time_hit, t2.value
FROM table1 t1
INNER JOIN table2 t2
ON t1.items = t2.items
AND t1.start_time <= t2.time_hit
WHERE NOT EXISTS (
SELECT 1 FROM table1 t10
WHERE
t10.items = t2.items
AND t10.start_time <= t2.time_hit
AND t10.start_time > t1.start_time
)
Комментарии:
1. У меня следующая ошибка
EXISTS subquery is not supported inside join predicate.
2. @SimonBreton: хорошо… Обновил мой ответ альтернативным запросом (функционально эквивалентным предыдущему запросу, но без usihng
EXISTS
в качествеJOIN
условия)3. Хорошо, я могу запустить запрос (ошибки больше нет), но это не работает. На самом деле я использую уникальный идентификатор для объединения двух таблиц. Может ли это повлиять на ваше решение?
4. @SimonBreton: что ж, мой запрос, похоже, выполняется нормально и возвращает ожидаемый результат, учитывая предоставленные вами образцы данных… Я вижу, что вы отредактировали свой пост, чтобы добавить
UniqueID
столбец: это не очень хорошая практика в SO. Возможно, вы захотите задать новый вопрос, предоставив дополнительные пояснения к вашей цели и другим образцам данных / ожидаемому результату.5. Я думаю, вы правы, мой вопрос недостаточно ясен. Я использую простое левое соединение, и у меня есть эти нулевые значения. Но, основываясь на вашей реакции; мне действительно интересно, не просто ли что-то не так с моим соединением. Я открою новый вопрос. Спасибо. Тем не менее, ответ от @bruceskyaus работает.
Ответ №3:
Я предполагаю, что вы ожидаете вывода с использованием INNER JOIN. Но не уверен, почему вы использовали FIRST_VALUE.
SELECT I.Item, I.Start_Time, ID.Time_hit, ID.Value
FROM Items I
INNER JOIN ItemDetails ID
ON I.Items = ID.Items
Пожалуйста, объясните, ищете ли вы какие-либо конкретные причины для рассмотрения этого подхода.
Комментарии:
1. Я думаю, мой вопрос недостаточно ясен… да, я использовал внутреннее объединение для объединения двух таблиц … все еще у меня есть эти значения null. Пожалуйста, дайте мне знать, как я могу уточнить. Спасибо.