在我的表中,我有YMonth列,YYONY格式的YMONTH值(如201510)。目前我正在这样做,
SELECT COUNT(*) FROM MyTable WHERE XXX AND YMONTH
in(TO_CHAR(add_months(SYSDATE,0),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-1),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-2),'YYYYMM'))
如果count = 3则OK。否则,我会执行,
SELECT COUNT(*) FROM MyTable WHERE XXX AND YMONTH
in(TO_CHAR(add_months(SYSDATE,-1),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-2),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-3),'YYYYMM'))
如果count = 3则OK。否则,我会执行,
SELECT COUNT(*) FROM MyTable WHERE XXX AND YMONTH
in(TO_CHAR(add_months(SYSDATE,-2),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-3),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-4),'YYYYMM'))
这很有效。但我想让它变得简单,只想执行一个sql。
答案 0 :(得分:2)
您可以使用分层查询来查找连续的月份:
Oracle 11g R2架构设置:
CREATE TABLE MyTable ( YMONTH ) AS
SELECT '201511' FROM DUAL
UNION ALL SELECT '201510' FROM DUAL
UNION ALL SELECT '201509' FROM DUAL
UNION ALL SELECT '201508' FROM DUAL
UNION ALL SELECT '201507' FROM DUAL
查询1 :
此查询将在3个月内为每个不同的连续条目集返回一行。在上表中有三个3个月的期间(7月至9月,8月至10月和9月至11月),因此结果集返回这三行。
SELECT YMONTH AS FROM_YMONTH,
CONNECT_BY_ROOT( YMONTH ) AS TO_YMONTH
FROM MyTable
WHERE LEVEL = 3
START WITH TO_DATE( YMONTH, 'YYYYMM' ) BETWEEN TRUNC( SYSDATE, 'MM' ) - INTERVAL '2' MONTH AND TRUNC( SYSDATE, 'MM' )
CONNECT BY PRIOR TO_DATE( YMONTH, 'YYYYMM' ) - INTERVAL '1' MONTH = TO_DATE( YMONTH, 'YYYYMM' )
<强> Results 强>:
| FROM_YMONTH | TO_YMONTH |
|-------------|-----------|
| 201509 | 201511 |
| 201508 | 201510 |
| 201507 | 201509 |
查询2 :
如果您只想在此期间内连续最多(最多3个)月份的数字值,那么您可以使用此值(虽然它不会告诉您该期间的哪个月份):
SELECT MAX( LEVEL ) AS Max_Consecutive_Months
FROM MyTable
START WITH TO_DATE( YMONTH, 'YYYYMM' ) BETWEEN TRUNC( SYSDATE, 'MM' ) - INTERVAL '2' MONTH AND TRUNC( SYSDATE, 'MM' )
CONNECT BY PRIOR TO_DATE( YMONTH, 'YYYYMM' ) - INTERVAL '1' MONTH = TO_DATE( YMONTH, 'YYYYMM' )
AND LEVEL <= 3
<强> Results 强>:
| MAX_CONSECUTIVE_MONTHS |
|------------------------|
| 3 |
答案 1 :(得分:0)
是的,您可以在单个查询中执行此操作。在一个查询中组合这些条件,然后对YMonth DESC 进行排序,并按 ROWNUM 进行限制
SELECT COUNT(*) FROM (
SELECT XXX,YMONTH
FROM MyTable
WHERE XXX
AND YMONTH IN(
TO_CHAR(add_months(SYSDATE,0),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-1),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-2),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-3),'YYYYMM'),
TO_CHAR(add_months(SYSDATE,-4),'YYYYMM')
)
ORDER BY YMONTH DESC
) WHERE ROWNUM <= 3
请尝试上面的查询,看看它是否有效。
答案 2 :(得分:0)
通过YMONTH订购您的桌子并添加一个rownum列:
-- test data
with mytable as
(select '201501' as ymonth
from dual
union
select '201503' as ymonth
from dual
union
select '201504' as ymonth
from dual
union
select '201505' as ymonth
from dual
union
select '201507' as ymonth
from dual
union
select '201508' as ymonth
from dual
union
select '201510' as ymonth
from dual
union
select '201511' as ymonth from dual),
ordered_data as
(select ymonth, row_number() over(order by ymonth desc) as r
from mytable)
select * from ordered_data;
结果:
ymonth r
201511 1
201510 2
201508 3
201507 4
201505 5
201504 6
201503 7
201501 8
通过此结果,您可以按add_months(ymonth,r)
进行分组。具有相同值的行属于一起,即
ymonth r add_months(ymonth,r)
201511 1 201512
201510 2 201512
201508 3 201511
201507 4 201511
201505 5 201510 -
201504 6 201510 - first group of tree
201503 7 201510 -
201501 8 201509
以下sql提供了您三个月范围的最后一个月,根据您的需要进行调整:
-- test data
with mytable as
(select '201501' as ymonth
from dual
union
select '201503' as ymonth
from dual
union
select '201504' as ymonth
from dual
union
select '201505' as ymonth
from dual
union
select '201507' as ymonth
from dual
union
select '201508' as ymonth
from dual
union
select '201510' as ymonth
from dual
union
select '201511' as ymonth from dual),
ordered_data as
(select ymonth, row_number() over(order by ymonth desc) as r
from mytable)
select max(d.ymonth)
from ordered_data d
where add_months(to_date(d.ymonth || '01', 'YYYYMMDD'), r) =
(select max(add_months(to_date(dd.ymonth || '01', 'YYYYMMDD'), r))
from ordered_data dd
group by add_months(to_date(dd.ymonth || '01', 'YYYYMMDD'), r)
having count(*) >= 3);
答案 3 :(得分:0)
我不太确定你期望单个查询的输出是什么,但也许你会追求像:
with mytable as (select 1 xxx, 201511 ymonth from dual union all
select 1 xxx, 201510 ymonth from dual union all
select 1 xxx, 201509 ymonth from dual union all
select 1 xxx, 201508 ymonth from dual union all
select 2 xxx, 201510 ymonth from dual union all
select 2 xxx, 201509 ymonth from dual union all
select 2 xxx, 201508 ymonth from dual union all
select 3 xxx, 201511 ymonth from dual union all
select 3 xxx, 201509 ymonth from dual union all
select 3 xxx, 201508 ymonth from dual union all
select 3 xxx, 201507 ymonth from dual)
-- end of mimicking the mytable table with data in it
select xxx,
ymonth,
case when count(case when to_date(ymonth||'01', 'yyyymmdd') between add_months(trunc(sysdate, 'mm'), -2) and add_months(trunc(sysdate, 'mm'), 0) then 1 end) over (partition by xxx) = 3 then 'last_3_months'
when count(case when to_date(ymonth||'01', 'yyyymmdd') between add_months(trunc(sysdate, 'mm'), -3) and add_months(trunc(sysdate, 'mm'), -1) then 1 end) over (partition by xxx) = 3 then 'last_3_months_but_1'
when count(case when to_date(ymonth||'01', 'yyyymmdd') between add_months(trunc(sysdate, 'mm'), -4) and add_months(trunc(sysdate, 'mm'), -2) then 1 end) over (partition by xxx) = 3 then 'last_3_months_but_2'
end month_range
from mytable
where to_date(ymonth||'01', 'yyyymmdd') between add_months(trunc(sysdate, 'mm'), -4) and add_months(trunc(sysdate, 'mm'), 0);
XXX YMONTH MONTH_RANGE
---------- ---------- --------------------------------
1 201511 last_3_months
1 201510 last_3_months
1 201509 last_3_months
1 201508 last_3_months
2 201510 last_3_months_but_1
2 201509 last_3_months_but_1
2 201508 last_3_months_but_1
3 201511 last_3_months_but_2
3 201509 last_3_months_but_2
3 201508 last_3_months_but_2
3 201507 last_3_months_but_2