考虑一个包含date
和status
列的表格(可能的值为A
和B
)。在对该表进行排序后,我想获得值status
的{{1}}的大多数连续值。
例如,按日期排序的日期结果集
A
将返回3(标有星号)。
由于我对SQL的知识非常有限,我完全不知道如何实现这一目标。我怀疑它与分区和分组有关,但就我而言。当然,我想避免使用A
B
B
A*
A*
A*
B
B
的解决方案,然后对结果集进行后处理,除非由于某些原因尚未发现它被证明是最好的。
测试表:
select *
插入陈述:
CREATE TABLE TEST
(
DATE DATE,
STATUS VARCHAR2(1)
)
RESULT_CACHE (MODE DEFAULT)
STORAGE (
BUFFER_POOL DEFAULT
FLASH_CACHE DEFAULT
CELL_FLASH_CACHE DEFAULT
)
LOGGING
NOCOMPRESS
NOCACHE
NOPARALLEL
NOMONITORING;
感谢您的帮助! :)
答案 0 :(得分:3)
注意:从原始答案中编辑 - 我错过了OP需要最长字符串A
' a的事实,而不是具有相同状态的最长字符串。 结束注释
这是Tabibitosan方法的完美应用(使用相同排序的ROW_NUMBER()
值的固定差异,使用和不使用STATUS
进行分区以创建我们需要的其他分组。注意:我将列名从DATE
更改为DT
; DATE
是一个Oracle关键字,不应该用作列名。
select max(count(*)) as max_count
from (
select status,
row_number() over (order by dt)
- row_number() over (partition by status order by dt) as grp
from test
)
where status = 'A'
group by status, grp
;
在Oracle 12.1及更高版本中,您可以对新的match_recoginze
子句执行相同的操作:
select max(cnt) as max_count
from test
match_recognize(
order by dt
measures count(*) as cnt
pattern ( x+ )
define x as status = 'A'
)
;
答案 1 :(得分:2)
您需要一个指定排序的列,因为SQL表代表无序集。
您可以通过不同方式识别群组。在你的情况下,也许最简单的方法是在每个“A”之前计算“B”的数量 - 这对于“A”序列是恒定的。然后使用另一个窗口函数来确定组中的数字:
select t.*
from (select t.*, max(cnt) over () as max_cnt
from (select t.*, count(*) over (partition by status, grp) as cnt
from (select t.*,
sum(case when status <> 'A' then 1 else 0 end) over (order by ?) as grp
from t
) t
where status = 'A'
) t
) t
where cnt = max_cnt;
如果您只想要值“3”,那么您可以使用:
select max(cnt)
from (select t.*, count(*) over (partition by status, grp) as cnt
from (select t.*,
sum(case when status <> 'A' then 1 else 0 end) over (order by ?) as grp
from t
) t
where status = 'A'
) t