как объединить таблицы в случаях, когда ни одна из функций (a) в b

#sql #monetdb #monetdblite

#sql #monetdb #monetdblite

Вопрос:

Скажем, в MonetDB (в частности, встроенная версия из пакета R «MonetDBLite») У меня есть таблица «события», содержащая идентификационные коды объектов и даты начала и окончания события в формате:

 | id  | start_date  | end_date   |
| 1   | 2010-01-01  | 2010-03-30 |
| 1   | 2010-04-01  | 2010-06-30 |
| 2   | 2018-04-01  | 2018-06-30 |
| ... | ...         | ...        |
  

Таблица содержит примерно 80 миллионов строк событий, относящихся примерно к 2,5 миллионам уникальных объектов (значения идентификаторов). Даты, похоже, хорошо совпадают с календарными кварталами, но я не проверял их тщательно, поэтому предполагаю, что они могут быть произвольными. Однако я, по крайней мере, проверил их на предмет end_date> start_date .

Я хочу создать таблицу «nonevent_qtrs», в которой перечислены календарные кварталы, в которых идентификатор не записан, например:

 | id  | last_doq   |
| 1   | 2010-09-30 |
| 1   | 2010-12-31 |
| ... | ...        |
| 1   | 2018-06-30 |
| 2   | 2010-03-30 |
| ... | ...        |
  

(doq = день квартала)

Если масштаб события охватывает любые дни квартала (включая первую и последнюю даты), то я хочу, чтобы оно считалось произошедшим в этом квартале.

Чтобы помочь с этим, я создал «календарную таблицу»; таблица кварталов «qtrs», охватывающая весь диапазон дат, присутствующих в «событиях», и формата:

 | first_doq  | last_doq   |
| 2010-01-01 | 2010-03-30 |
| 2010-04-01 | 2010-06-30 |
| ...        | ...        |
  

И попытался использовать неравномерное слияние следующим образом:

 create table nonevents
as select
    id,
    last_doq
from
    events
    full outer join
    qtrs
on
    start_date > last_doq or
    end_date < first_doq
group by
    id,
    last_doq
  

Но это а) ужасно неэффективно и б) определенно неправильно, поскольку большинство идентификаторов указаны как не связанные с событиями для всех кварталов.

Как я могу создать таблицу «nonevent_qtrs», которую я описал, которая содержит список кварталов, для которых каждый идентификатор не имел событий?

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

 | id  | last_doq   | event |
| 1   | 2010-01-31 | 1     |
| ... | ...        | ...   |
| 1   | 2018-06-30 | 0     |
| ... | ...        | ...   |
  

Но, хотя это более полезно, это может быть невозможно из-за размера используемых данных. Широкий формат:

 | id  | 2010-01-31 | ... | 2018-06-30 |
| 1   | 1          | ... | 0          |
| 2   | 0          | ... | 1          |
| ... | ...        | ... | ...        |
  

также было бы удобно, но поскольку MonetDB является хранилищем столбцов, я не уверен, является ли это более или менее эффективным.

Ответ №1:

Позвольте мне предположить, что у вас есть таблица кварталов с датой начала квартала и датой окончания. Вам действительно нужно это, если вы хотите, чтобы кварталы, которые не существуют. В конце концов, как далеко назад во времени или вперед во времени вы хотите вернуться?

Затем вы можете сгенерировать все комбинации id / quarter и отфильтровать те, которые существуют:

 select i.id, q.*
from (select distinct id from events) i cross join
     quarters q left join
     events e
     on e.id = i.id and
        e.start_date <= q.quarter_end and
        e.end_date >= q.quarter_start
where e.id is null;
  

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

1. Похоже, что это работает, и я ясно вижу логику запроса. Итоговая таблица содержит около 56 миллионов строк, так что не так плохо, как я опасался.