我正在按照评论者的建议重新提出我之前提出的问题。
以下数据表示产品连续几周的销售情况。
22,19,20,23,16,14,15,15,18,21,24,10,17
我需要连续几周找到最长的销售数字,即由14,15,15,18,21,24
代表的第6周到第11周。
我有一个返回结果的查询,但想知道改进它的方法。有人可以建议一些方法吗?提前谢谢。
with
raw_data (sales) as
(
select '22,19,20,23,16,14,15,15,18,21,24,10,17' from dual
)
,
derived_tbl(week, sales) as
(
select level, regexp_substr(sales, '([[:digit:]]+)(,|$)', 1, level, null, 1)
from raw_data connect by level <= regexp_count(sales,',')+1
)
,
coll(week, sales, salesdlag, salesdlead) as
(
select week, sales,
nvl(sales - (lag(sales) over (order by week)), 0),
nvl((lead(sales) over (order by week) - sales), 0)
from derived_tbl
)
,
filt_coll(week, sales, salesdlag, salesdlead) as
(
select week, sales, salesdlag, salesdlead
from coll
where not (salesdlag < 0 and salesdlead < 0)
)
,
cte(startweek, sales, salesdlag, salesdlead, actualweek) as
(
select week, sales, salesdlag, salesdlead, week from filt_coll
union all
select cte.startweek, cl.sales, cl.salesdlag, cl.salesdlead, cl.week
from filt_coll cl, cte
where cl.week = cte.actualweek + 1 and cl.sales >= cte.sales
)
,
pen_coll as
(
select * from cte order by startweek,actualweek
)
,
final_coll as
(
select startweek, actualweek, sales, count(startweek) over(PARTITION BY startweek) as cnt from pen_coll
)
select LISTAGG(sales, ',') within group (order by null) as rslt
from final_coll
where cnt = (select max(cnt) from final_coll)
;
答案 0 :(得分:0)
使用集合(而不是分隔的字符串)来存储值,您还可以使用分层查询来查找结果:
SELECT *
FROM (
SELECT TRIM( LEADING ',' FROM SYS_CONNECT_BY_PATH( value, ',' ) ) AS week_values,
CONNECT_BY_ROOT id AS first_week,
id AS last_week,
LEVEL AS num_weeks,
MAX( LEVEL ) OVER () AS max_weeks
FROM (
SELECT COLUMN_VALUE AS value,
ROWNUM As id
FROM TABLE( SYS.ODCINUMBERLIST( 22,19,20,23,16,14,15,15,18,21,24,10,17 ) )
)
WHERE CONNECT_BY_ISLEAF = 1
CONNECT BY PRIOR id + 1 = id AND PRIOR value <= value
)
WHERE num_weeks = max_weeks
<强>输出强>:
WEEK_VALUES FIRST_WEEK LAST_WEEK NUM_WEEKS MAX_WEEKS
----------------- ---------- --------- --------- ---------
14,15,15,18,21,24 6 11 6 6
您可以进一步将分层查询限制为仅在前一个值更大时启动:
SELECT *
FROM (
SELECT TRIM( LEADING ',' FROM SYS_CONNECT_BY_PATH( value, ',' ) ) AS week_values,
CONNECT_BY_ROOT id AS first_week,
id AS last_week,
LEVEL AS num_weeks,
MAX( LEVEL ) OVER () AS max_weeks
FROM (
SELECT COLUMN_VALUE AS value,
LAG( COLUMN_VALUE ) OVER ( ORDER BY ROWNUM ) AS prev_value,
ROWNUM As id
FROM TABLE( SYS.ODCINUMBERLIST( 22,19,20,23,16,14,15,15,18,21,24,10,17 ) )
)
WHERE CONNECT_BY_ISLEAF = 1
START WITH prev_value IS NULL OR prev_value > value
CONNECT BY PRIOR id + 1 = id AND PRIOR value <= value
)
WHERE num_weeks = max_weeks
<强>更新强>
Oracle安装程序:
create table tst(id, value) as
select rownum, round(dbms_random.value*9)
from dual
connect by level <= 10000;
查询:
SELECT *
FROM (
SELECT TRIM( LEADING ',' FROM SYS_CONNECT_BY_PATH( value, ',' ) ) AS week_values,
CONNECT_BY_ROOT id AS first_week,
id AS last_week,
LEVEL AS num_weeks,
MAX( LEVEL ) OVER () AS max_weeks
FROM (
SELECT value,
LAG( value ) OVER ( ORDER BY id ) AS prev_value,
id
FROM tst
)
WHERE CONNECT_BY_ISLEAF = 1
START WITH prev_value IS NULL OR prev_value > value
CONNECT BY PRIOR id + 1 = id AND PRIOR value <= value
)
WHERE num_weeks = max_weeks