ORACLE:一次选择即可查看不同的日期范围

时间:2018-10-18 21:38:32

标签: sql oracle

我希望能够计算一年中不同日期的不同年龄范围,而不必进行所有合并。

现在查询将是这样的:

   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...

因此,我不想传递一次agefile,而是传递12次,而不是传递12次age。

示例:

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

“在最近12个月的每个月的最后一天,有多少个成员的年龄为x”将是业务问题

有什么方法可以绕过文件传递12次并一次选择吗?

谢谢

3 个答案:

答案 0 :(得分:1)

您想要交叉连接到整数集,而不是对整数进行硬编码。

您可以执行以下操作:

SELECT ROWNUM as rn FROM agefile
WHERE ROWNUM <= 12

然后交叉加入并使用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)

在这种情况下,如果您交叉申请一个月列表而不是整数,它的清理效果会更好,并且加入一个预先构建的数字/理货价格表将使其更加整洁。

答案 1 :(得分:0)

在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);

答案 2 :(得分:0)

您的查询执行了很多多余的操作,可以进行很多清理:

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)