Подписчик Oracle SQL Developer - создание кросс-таблицы - PullRequest
0 голосов
/ 06 июля 2018

У меня есть таблица UPCALL_HISTORY, которая имеет 3 столбца: SUBSCRIBER_ID, START_DATE и END_DATE. Пусть количество уникальных подписчиков будет N.

Я хочу создать новую таблицу с 3 столбцами:

  1. SUBSCRIBER_ID: Все уникальные идентификаторы подписчиков повторяются 36 раз подряд.
  2. MONTHLY_CALENDAR_ID: для каждого SUBSCRIBER_ID в этом столбце будут указаны даты с июля 2015 года по июль 2018 года (36 месяцев).
  3. ACTIVE: этот столбец будет использоваться в качестве флага для каждого подписчика и наличия подписки в течение этого месяца. Эти данные подписки находятся в таблице под названием UPCALL_HISTORY.

Я довольно новичок в SQL, не имею большого опыта. Я хорош в Python, но кажется, что SQL не работает как Python.

Любые варианты запросов, которые могли бы помочь мне построить эту таблицу?

Пусть моя таблица UPCALL_HISTORY будет:

+---------------+------------+------------+
| SUBSCRIBER_ID | START_DATE |  END_DATE  |
+---------------+------------+------------+
|           119 | 01/07/2015 | 01/08/2015 |
|           120 | 01/08/2015 | 01/09/2015 |
|           121 | 01/09/2015 | 01/10/2015 |
+---------------+------------+------------+

Я хочу таблицу, которая выглядит следующим образом:

+---------------+------------+--------+
| SUBSCRIBER_ID |   MON_CA   | ACTIVE |
+---------------+------------+--------+
| 119           | 01/07/2015 |      1 |
| *             | 01/08/2015 |      0 |
| *             | 01/09/2015 |      0 |
| (36 times)    | 01/10/2015 |      0 |
| *             | *          |      0 |
| 119           | 01/07/2018 |      0 |
+---------------+------------+--------+

, которое продолжается для 120 и 121

РЕДАКТИРОВАТЬ: Добавлен пример

Ответы [ 4 ]

0 голосов
/ 11 июля 2018

Я также считаю, что это может быть примером для CROSS JOIN. Все, что мне нужно было сделать, это создать небольшую таблицу со всеми датами, а затем CROSS JOIN с таблицей подписчиков.

Пример: https://www.essentialsql.com/cross-join-introduction/

0 голосов
/ 06 июля 2018

Если вы находитесь на 12c, вы можете использовать встроенный просмотр всех месяцев с cross apply, чтобы получить комбинации из них со всеми идентификаторами:

select uh.subscriber_id, m.month,
  case when trunc(uh.start_date, 'MM') <= m.month
      and (uh.end_date is null or uh.end_date >= add_months(m.month, 1))
    then 1 else 0 end as active
from upcall_history uh
cross apply (
  select add_months(trunc(sysdate, 'MM'), - level) as month
  from dual
  connect by level <= 36
) m
order by uh.subscriber_id, m.month;

Я сделал это скользящим 36-месячным окном до текущего месяца, но вы можете на самом деле хотеть фиксированные даты, как в вопросе.

С примерами данных из CTE:

with upcall_history (subscriber_id, start_date, end_date) as (
  select 1, date '2015-09-04', '2015-12-15' from dual
  union all select 2, date '2017-12-04', '2018-05-15' from dual
)

, который генерирует 72 строки:

SUBSCRIBER_ID MONTH          ACTIVE
------------- ---------- ----------
            1 2015-07-01          0
            1 2015-08-01          0
            1 2015-09-01          1
            1 2015-10-01          1
            1 2015-11-01          1
            1 2015-12-01          0
            1 2016-01-01          0
...
            2 2017-11-01          0
            2 2017-12-01          1
            2 2018-01-01          1
            2 2018-02-01          1
            2 2018-03-01          1
            2 2018-04-01          1
            2 2018-05-01          0
            2 2018-06-01          0

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


Если вы не на 12c, то cross apply недоступен - вы получите «ORA-00905: отсутствует ключевое слово».

Вы можете получить один и тот же результат с двумя CTE (один, чтобы получить все месяцы, другой, чтобы получить все идентификаторы), перекрестно соединенными, а затем внешне соединенными с вашими фактическими данными:

with m (month) as (
  select add_months(trunc(sysdate, 'MM'), - level)
  from dual
  connect by level <= 36
),
i (subscriber_id) as (
  select distinct subscriber_id
  from upcall_history
)
select i.subscriber_id, m.month,
  case when uh.subscriber_id is null then 0 else 1 end as active
from m
cross join i
left join upcall_history uh
on uh.subscriber_id = i.subscriber_id
and trunc(uh.start_date, 'MM') <= m.month
and (uh.end_date is null or uh.end_date >= add_months(m.month, 1))
order by i.subscriber_id, m.month;
0 голосов
/ 06 июля 2018

Вы можете сделать это в 11g, используя разделенные внешние соединения, например:

WITH upcall_history AS (SELECT 119 subscriber_id, to_date('01/07/2015', 'dd/mm/yyyy') start_date, to_date('01/08/2015', 'dd/mm/yyyy') end_date FROM dual UNION ALL
                        SELECT 120 subscriber_id, to_date('01/08/2015', 'dd/mm/yyyy') start_date, to_date('01/09/2015', 'dd/mm/yyyy') end_date FROM dual UNION ALL
                        SELECT 121 subscriber_id, to_date('01/09/2015', 'dd/mm/yyyy') start_date, to_date('01/10/2015', 'dd/mm/yyyy') end_date FROM dual),
              mnths AS (SELECT add_months(TRUNC(SYSDATE, 'mm'), + 1 - LEVEL) mnth
                        FROM   dual
                        CONNECT BY LEVEL <= 12 * 3 + 1)
SELECT uh.subscriber_id,
       m.mnth,
       CASE WHEN mnth BETWEEN start_date AND end_date - 1 THEN 1 ELSE 0 END active
FROM   mnths m
       LEFT OUTER JOIN upcall_history uh PARTITION BY (uh.subscriber_id) ON (1=1)
ORDER BY uh.subscriber_id,
         m.mnth;

SUBSCRIBER_ID MNTH            ACTIVE
------------- ----------- ----------
          119 01/07/2015           1
          119 01/08/2015           0
          119 01/09/2015           0
          119 01/10/2015           0
          <snip>
          119 01/06/2018           0
          119 01/07/2018           0
          --
          120 01/07/2015           0
          120 01/08/2015           1
          120 01/09/2015           0
          120 01/10/2015           0
          <snip>
          120 01/06/2018           0
          120 01/07/2018           0
          --
          121 01/07/2015           0
          121 01/08/2015           0
          121 01/09/2015           1
          121 01/10/2015           0
          <snip>
          121 01/06/2018           0
          121 01/07/2018           0

N.B. Я предположил кое-что о ваших датах начала / окончания и о том, что является активным; надеюсь, вам будет достаточно легко настроить выражение case, чтобы оно соответствовало логике, которая лучше всего подходит для вашей ситуации.

0 голосов
/ 06 июля 2018

Вот как я понял вопрос.

Пример таблицы и несколько строк:

SQL> create table upcall_history
  2    (subscriber_id number,
  3     start_date    date,
  4     end_date      date);

Table created.

SQL> insert into upcall_history
  2    select 1, date '2015-12-25', date '2016-01-13' from dual union
  3    select 1, date '2017-07-10', date '2017-07-11' from dual union
  4    select 2, date '2018-01-01', date '2018-04-24' from dual;

3 rows created.

Создание новой таблицы .Для отдельных SUBSCRIBER_ID's создается 36 фиксированных «ежемесячных» строк (как вы указали).

SQL> create table new_table as
  2    select
  3      x.subscriber_id,
  4      add_months(date '2015-07-01', column_value - 1) monthly_calendar_id,
  5      0 active
  6    from (select distinct subscriber_id from upcall_history) x,
  7         table(cast(multiset(select level from dual
  8                             connect by level <= 36
  9                            ) as sys.odcinumberlist));

Table created.

Обновите ACTIVE значение столбца до «1» для строк, MONTHLY_CALENDAR_ID которых содержится в START_DATE и END_DATE таблицы UPCALL_HISTORY.

SQL> merge into new_table n
  2    using (select subscriber_id, start_date, end_date from upcall_history) x
  3    on (    n.subscriber_id = x.subscriber_id
  4        and n.monthly_calendar_id between trunc(x.start_date, 'mm')
  5                                      and trunc(x.end_date, 'mm')
  6       )
  7  when matched then
  8    update set n.active = 1;

7 rows merged.

SQL>

Результат (только ACTIVE = 1):

SQL> select * from new_table
  2  where active = 1
  3  order by subscriber_id, monthly_calendar_id;

SUBSCRIBER_ID MONTHLY_CA     ACTIVE
------------- ---------- ----------
            1 2015-12-01          1
            1 2016-01-01          1
            1 2017-07-01          1
            2 2018-01-01          1
            2 2018-02-01          1
            2 2018-03-01          1
            2 2018-04-01          1

7 rows selected.

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