BigQuery Count Два диапазона дат перекрываются - PullRequest
0 голосов
/ 08 апреля 2020

Я решил эту проблему, загрузив все данные и перебрав их в Python, но мне интересно, есть ли способ сделать это в BigQuery.

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

begin_date, end_date
'2016-02-19', '2016-02-19'
'2016-02-20', '2016-02-25'
'2016-02-21', '2016-02-25'
'2016-02-22', NULL

Нам нужно количество строк для каждой даты, где begin_date <= date <= end_date. Для любого заданного значения c достаточно просто выбрать счет: </p>

SELECT COUNT(*) FROM `table` WHERE begin_date <= '2016-12-19' AND (end_date >= '2016-12-19' OR end_date IS NULL)

Так что, если я сделаю это вручную для каждого интересующего меня значения, желаемый результат может выглядеть следующим образом:

begin_date, count
2016-02-19, 1
2016-02-20, 1
2016-02-21, 2
2016-02-22, 3
2016-02-23, 3
2016-02-24, 3
2016-02-25, 3
2016-02-26, 1
etc.

Достаточно просто создать список дат для перебора:

WITH dates AS (SELECT * FROM UNNEST(GENERATE_DATE_ARRAY('2018-10-01', '2020-09-30', INTERVAL 1 DAY)) AS example)

Теперь я борюсь с применением приведенного выше предложения WHERE для всех этих дат. Я вижу, как работает раздел с диапазоном при сопоставлении с одним столбцом ( как здесь ), но мне нужно сопоставить как begin_date, так и end_date.

Я думал, что смогу сделать это с это:

SELECT
  status_begin_date,
  (SELECT COUNT(1) FROM UNNEST(ends) AS e WHERE (e >= status_begin_date OR e IS NULL)) AS cnt
FROM (
  SELECT
    status_begin_date,
    ARRAY_AGG(status_end_date) OVER(ORDER BY status_begin_date) AS ends
  FROM `table`
)
ORDER BY status_begin_date

Взято из здесь . Это работает на небольшом примере, приведенном в ответе StackOverflow, но я получаю ошибку ресурса при использовании его в моей таблице с несколькими сотнями миллионов строк: enter image description here Существует ли масштабируемое решение в BigQuery?

Ответы [ 2 ]

2 голосов
/ 09 апреля 2020

Ниже для BigQuery Standard SQL и не использует неэффективный подход курсора и скорее использует classi c sql, установленный на основе

#standardSQL
WITH dates AS (
  SELECT day 
  FROM (SELECT MIN(begin_date) min_date, MAX(end_date) max_date FROM `table`), 
  UNNEST(GENERATE_DATE_ARRAY(min_date, CURRENT_DATE(), INTERVAL 1 DAY)) AS day
)
SELECT day, COUNT(*) 
FROM dates 
JOIN `table` 
ON begin_date <= day AND (end_date >= day OR end_date IS NULL)
GROUP BY day

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

#standardSQL
WITH `table` AS (
  SELECT DATE '2016-02-19' begin_date, DATE '2016-02-19' end_date UNION ALL
  SELECT '2016-02-20', '2016-02-25' UNION ALL
  SELECT '2016-02-21', '2016-02-25' UNION ALL
  SELECT '2016-02-22', NULL
), dates AS (
  SELECT day 
  FROM (SELECT MIN(begin_date) min_date, MAX(end_date) max_date FROM `table`), 
  UNNEST(GENERATE_DATE_ARRAY(min_date, max_date, INTERVAL 1 DAY)) AS day
)
SELECT day, COUNT(*) 
FROM dates 
JOIN `table` 
ON begin_date <= day AND (end_date >= day OR end_date IS NULL)
GROUP BY day
-- ORDER BY day  

с результатом

Row day         f0_  
1   2016-02-19  1    
2   2016-02-20  1    
3   2016-02-21  2    
4   2016-02-22  3    
5   2016-02-23  3    
6   2016-02-24  3    
7   2016-02-25  3    
0 голосов
/ 08 апреля 2020

Этот неприятный код работал:

DECLARE dates ARRAY <DATE>;
DECLARE x INT64 DEFAULT 0;
DECLARE results ARRAY <INT64>;
DECLARE results_dates ARRAY <DATE>;
DECLARE result INT64;
DECLARE date DATE;
SET dates = GENERATE_DATE_ARRAY('2016-02-17', '2019-05-13', INTERVAL 1 DAY);
LOOP
  SET date = dates[OFFSET(x)];
  SET result = (SELECT COUNT(*) FROM `table` WHERE begin_date <= date AND (end_date >= date OR end_date IS NULL));
  SET results = ARRAY_CONCAT(results, [result]);
  SET results_dates = ARRAY_CONCAT(results_dates, [date]);
  SET x = x + 1;
  IF x >= ARRAY_LENGTH(dates) THEN
    LEAVE;
  END IF;
END LOOP;
SELECT date, count_subscribers
FROM UNNEST(results_dates) AS date WITH OFFSET 
JOIN UNNEST(results) AS count_subscribers WITH OFFSET
USING(OFFSET)

Время выполнения 1,5 часа, что лучше, чем мой код Python (7 часов), но код BigQuery не распараллеливается, тогда как Python код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...