我希望能够计算一年中不同日期的不同年龄范围,而不必进行所有合并。
现在查询将是这样的:
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次并一次选择吗?
谢谢
答案 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)