Google BigQuery: из таблицы дней получите таблицу со всеми днями года - PullRequest
0 голосов
/ 09 марта 2019

У меня есть эта (примерная) таблица:

+------------+-------------------+-----------+
|    Date    |       User        | Attribute |
+------------+-------------------+-----------+
| 2019-01-01 | user1@example.com | apple     |
| 2019-02-01 | user2@example.com | pear      |
| 2019-03-01 | user1@example.com | carrot    |
| 2019-03-01 | user2@example.com | orange    |
+------------+-------------------+-----------+

Мне нужно создать полную перестановку всех пар (дата + пользователь), заполнив все пропущенные дни 2019 года (с attribute какnull).

Как и в моем примере, у меня есть 2 разных пользователя:

  • user1@example.com
  • user2@example.com

Результирующая таблица должна быть:

+------------+-------------------+-----------+
|    Date    |       User        | Attribute |
+------------+-------------------+-----------+
| 2019-01-01 | user1@example.com | apple     |
| ...        | user1@example.com | null      |
| 2019-03-01 | user1@example.com | carrot    |
| ...        | user1@example.com | null      |
| 2019-12-31 | user1@example.com | null      |
| 2019-01-01 | user2@example.com | null      |
| ...        | user2@example.com | null      |
| 2019-02-01 | user2@example.com | pear      |
| ...        | user2@example.com | null      |
| 2019-03-01 | user2@example.com | orange    |
| ...        | user2@example.com | null      |
| 2019-12-31 | user2@example.com | null      |
+------------+-------------------+-----------+

... подразумевает, что существует строка для каждого отдельного дня года, а attribute имеет значение, когда исходная таблицапредоставляет фактическое значение, в противном случае используется null.

В качестве первого шага, чтобы создать все перестановки (дата + пользователь), о которых я думал, используя таблицу bigquery-public-data.utility_eu.date_greg, используя CROSS JOIN, чтобы создать всенеобходимые строки.

Вот пример таблицы, которая будет использоваться:

#standardSQL
WITH sample AS (
  SELECT DATE('2019-01-01') date, 'user1@example.com' user, 'apple' attribute
  UNION ALL
  SELECT DATE('2019-02-01'), 'user2@example.com', 'pear'
  UNION ALL
  SELECT DATE('2019-03-01'), 'user1@example.com', 'carrot'
  UNION ALL
  SELECT DATE('2019-03-01'), 'user2@example.com', 'orange'
)

И вот первый запрос, который я попытался:

SELECT d.date,s.* EXCEPT(date)
FROM sample s
  CROSS JOIN `bigquery-public-data.utility_eu.date_greg` d 
WHERE d.year = 2019
ORDER BY date,user

Но это слишком много, потому чтотакже значения attribute используются внутри объединения, и я получаю значение, реплицируемое на все дни, которые не связаны с исходным.

Я думаю, что мне нужно что-то вроде DISTINCT, чтобы получить только уникальные (дата + пользователь) пары, и только потом связывать значение attribute, если оно есть.

Это первоеЯ нашел рабочее решение:

distinct_couples AS (
  SELECT DISTINCT d.date,s.user
  FROM sample s CROSS JOIN `bigquery-public-data.utility_eu.date_greg` d 
  WHERE d.year = 2019
)

SELECT d.*, s.attribute
FROM distinct_couples d
  LEFT JOIN sample s USING(date,user)
ORDER BY date,user

Но я делаю соединение с sample дважды (сначала в таблице временных данных, а затем в основном запросе), поэтому я пытаюсь понять, можно ли оптимизировать.

Есть ли у вас какие-либо предложения о том, как заставить это работать?Спасибо

1 Ответ

2 голосов
/ 09 марта 2019

Ниже для BigQuery Standard SQL

#standardSQL
WITH users AS (
  SELECT DISTINCT user
  FROM `project.dataset.sample`
)
SELECT d.date, u.user, s.attribute
FROM `bigquery-public-data.utility_eu.date_greg` d  
CROSS JOIN users u
LEFT JOIN `project.dataset.sample` s
ON s.date = d.date
AND s.user = u.user
WHERE d.year = 2019

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

#standardSQL
WITH users AS (
  SELECT DISTINCT user
  FROM `project.dataset.sample`
), dates AS (
  SELECT `date` 
  FROM UNNEST(GENERATE_DATE_ARRAY('2019-01-01', '2019-12-31')) `date`
)
SELECT d.date, u.user, s.attribute
FROM dates d  
CROSS JOIN users u
LEFT JOIN `project.dataset.sample` s
ON s.date = d.date
AND s.user = u.user
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...