ORACLE: просмотр разных диапазонов дат одним выбором - PullRequest
0 голосов
/ 19 октября 2018

Я хочу иметь возможность рассчитывать разные возрастные диапазоны для разных дат на протяжении года без необходимости объединения всех.

Теперь запрос будет выглядеть примерно так:

   SELECT
      to_char(last_day(add_months(sysdate,-1)),'YYYYMM') yrmnth,
      FLOOR(months_between(last_day(add_months(sysdate,-1)),birth_date)/12),
    count(distinct id) members
    from agefile
    WHERE to_char(from_date, 'YYYYMM')<=to_char(last_day(add_months(sysdate,-1)),'YYYYMM') 
    and to_char(thru_date, 'YYYYMM')>=to_char(last_day(add_months(sysdate,-1)),'YYYYMM')
    GROUP BY to_char(last_day(add_months(sysdate,-1)),'YYYYMM'),
    FLOOR(months_between(last_day(add_months(sysdate,-1)),birth_date)/12)

    UNION ALL

    SELECT
      to_char(last_day(add_months(sysdate,-2)),'YYYYMM') yrmnth,
      FLOOR(months_between(last_day(add_months(sysdate,-2)),birth_date)/12),
    count(distinct id) members
    from agefile
    WHERE to_char(from_date, 'YYYYMM')<=to_char(last_day(add_months(sysdate,-2)),'YYYYMM') 
    and to_char(thru_date, 'YYYYMM')>=to_char(last_day(add_months(sysdate,-2)),'YYYYMM')
    GROUP BY to_char(last_day(add_months(sysdate,-2)),'YYYYMM'),
    FLOOR(months_between(last_day(add_months(sysdate,-2)),birth_date)/12)

    UNION ALL

and so on...

Итак, вместо того, чтобы передать возрастной файл 12 раз, я хочу передать его один раз, но вывести 12-кратное число возрастов.

Пример:

yrmnth    age     members
201809     1        100
201809     2        120
201809     3        145
201808     1        56

«Сколько членов было возрастом x на последний день каждого месяца за последние 12 месяцев» - это бизнес-вопрос

Любойспособ обойти передачу 12 раз и сделать это с помощью одного выбора?

спасибо

Ответы [ 3 ]

0 голосов
/ 19 октября 2018

Создайте месячные дни в предложении with и перекрестное соединение с таблицей:

with months as
(
  select last_day(add_months(sysdate, -1)) as day from dual
  union all
  select last_day(add_months(sysdate, -2)) as day from dual
  union all
  ...
)
select
  to_char(months.day,'yyyymm') yrmnth,
  floor(months_between(months.day, birth_date) / 12),
  count(distinct id) members
from months cross join agefile
where to_char(from_date, 'yyyymm') <= to_char(months.day, 'yyyymm') 
  and to_char(thru_date, 'yyyymm') >= to_char(months.day, 'yyyymm')
group by
  to_char(months.day, 'yyyymm'),
  floor(months_between(months.day, birth_date) / 12);
0 голосов
/ 19 октября 2018

Ваш запрос выполняет много избыточных операций и может быть много очищен:

WITH m AS(
  SELECT last_day(add_months(sysdate,level-12)) month_end FROM dual CONNECT BY level <=12
)
SELECT
  m.month_end,
  trunc(months_between(af.birth_date, .month_end)) as age_at,
  count(*) as num_mem
FROM
  age_file af
  CROSS JOIN
  m
GROUP BY
  m.month_end,
  trunc(months_between(af.birth_date, .month_end))

Я не мог понять, каково было значение даты от и до даты, если только это нефильтр для активного членства, в этом случае он, вероятно, может быть выражен как where m.month_end between af.from_date and af.thru_date

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

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

В нынешнем виде этот запрос также рассчитывает текущий месяц.,Если вы хотите, чтобы предыдущие 12 месяцев не включали текущий месяц, укажите -13 в запросе уровня.(Запрос производит 1 к 12, вычитание 12 означает, что это от -12 до 0. Вычитание 13 делает его от -13 до -1)

0 голосов
/ 19 октября 2018

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

Вы можете сделать что-то вроде:

SELECT ROWNUM as rn FROM agefile
WHERE ROWNUM <= 12

Затем CROSS JOIN и использовать rn*-1вместо ваших жестко запрограммированных целых чисел:

   with cte as (     SELECT ROWNUM as rn
                      FROM agefile
                      WHERE ROWNUM <= 12
                )
    SELECT
      to_char(last_day(add_months(sysdate,rn*-1)),'YYYYMM') yrmnth,
      FLOOR(months_between(last_day(add_months(sysdate,rn*-1)),birth_date)/12),
      count(distinct id) members
    FROM agefile
    CROSS JOIN cte
    WHERE to_char(from_date, 'YYYYMM')<=to_char(last_day(add_months(sysdate,rn*-1)),'YYYYMM') 
       and to_char(thru_date, 'YYYYMM')>=to_char(last_day(add_months(sysdate,rn*-1)),'YYYYMM')
    GROUP BY to_char(last_day(add_months(sysdate,rn*-1)),'YYYYMM'),
       FLOOR(months_between(last_day(add_months(sysdate,rn*-1)),birth_date)/12)

В этом случае он очищается еще лучше, если вы перекрестно применяете к списку месяцев, а не к целым числам, и имеете предварительно построенную таблицу чисел / счетчиков дляприсоединиться к сделает его еще чище.

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