我有一个带有时间戳列和多个标识符列的数据集。当按时间戳排序时,我希望将具有相同标识符的相邻行的每个“块”压缩为单行。需要每个块的最小和最大时间戳。
来源数据:
TSTAMP ID1 ID2
t1 A B <= start of new block
t2 A B
t3 C D <= start of new block
t4 E F <= start of new block
t5 E F
t6 E F
t7 A B <= start of new block
t8 G H <= start of new block
期望的结果:
MIN_TSTAMP MAX_TSTAMP ID1 ID2
t1 t2 A B
t3 t3 C D
t4 t6 E F
t7 t7 A B
t8 t8 G H
我认为这对于窗口分析函数已经成熟,但是如果没有对IDn
的所有相等组合进行分组,而不是仅按相邻行中的那些进行分组,则按时间戳排序时,我无法进行分区。
解决方法是首先在内联视图中创建一个键列,然后我可以将其分组,即块中每行的值相同,每个块的值不同。我可以使用LAG分析函数来比较行值,然后调用PL / SQL函数来返回序列的nextval / currval值(在此上下文中直接调用SQL中的nextval / currval)。
select min(ilv.tstamp), max(ilv.tstamp), id1, id2
from (
select case when (id1 != lag(id1,1,'*') over (partition by (1) order by tstamp)
or id2 != lag(id2,1,'*') over (partition by (1) order by tstamp))
then
pk_seq_utils.gav_get_nextval
else
pk_seq_utils.gav_get_currval
end ident, t.*
from tab1 t
order by tstamp) ilv
group by ident, id1, id2
order by 1;
其中gav_get_xxx
函数只是从序列返回currval / nextval。
但我想只使用SQL并避免使用PL / SQL(因为我也可以在PL / SQL中轻松编写它并从管道函数中输出结果行。)
有什么想法吗?
感谢。
答案 0 :(得分:4)
Tabibitosan救援!
with sample_data as (select 't1' tstamp, 'A' id1, 'B' id2 from dual union all
select 't2' tstamp, 'A' id1, 'B' id2 from dual union all
select 't3' tstamp, 'C' id1, 'D' id2 from dual union all
select 't4' tstamp, 'E' id1, 'F' id2 from dual union all
select 't5' tstamp, 'E' id1, 'F' id2 from dual union all
select 't6' tstamp, 'E' id1, 'F' id2 from dual union all
select 't7' tstamp, 'A' id1, 'B' id2 from dual union all
select 't8' tstamp, 'G' id1, 'H' id2 from dual)
select min(tstamp) min_tstamp, max(tstamp) max_tstamp, id1, id2
from (select tstamp,
id1,
id2,
row_number() over (order by tstamp) - row_number() over (partition by id1, id2 order by tstamp) grp
from sample_data)
group by id1,
id2,
grp
order by min(tstamp);
MIN_TSTAMP MAX_TSTAMP ID1 ID2
---------- ---------- --- ---
t1 t2 A B
t3 t3 C D
t4 t6 E F
t7 t7 A B
t8 t8 G H
答案 1 :(得分:2)
您应该能够使用row_number
窗口功能执行此操作,如下所示:
select
min(tstamp) mints, max(tstamp) maxts, id1, id2
from (
select
*,
row_number() over (order by tstamp)
- row_number() over (partition by id1, id2 order by tstamp) as rn
from t
) as subq
group by id1, id2, rn
order by rn
我还没有能够使用任何Oracle数据库进行测试,但它可以与MSSQL一起使用,也可以在Oracle中工作,因为窗口函数的工作方式相同。
答案 2 :(得分:2)
您可以使用an analytic 'trick'来识别间隙和岛屿,将所有行中每行的位置与tstamp
的位置进行比较,其中tstamp
的位置仅针对id2, id2
select tstamp, id1, id2,
row_number() over (partition by id1, id2 order by tstamp)
- row_number() over (order by tstamp) as block_id
from tab1;
TS I I BLOCK_ID
-- - - ----------
t1 A B 0
t2 A B 0
t3 C D -2
t4 E F -3
t5 E F -3
t6 E F -3
t7 A B -4
t8 G H -7
组合:
block_id
select min(tstamp) as min_tstamp, max(tstamp) as max_tstamp, id1, id2
from (
select tstamp, id1, id2,
row_number() over (partition by id1, id2 order by tstamp)
- row_number() over (order by tstamp) as block_id
from tab1
)
group by id1, id2, block_id
order by min(tstamp);
MI MA I I
-- -- - -
t1 t2 A B
t3 t3 C D
t4 t6 E F
t7 t7 A B
t8 t8 G H
的实际值并不重要,只是它对于组合的每个块都是唯一的。然后,您可以使用它进行分组:
body {
background:url('bg.jpg') no-repeat center center;
background-size:cover;
/* Workaround for some mobile browsers */
min-height:100%;
padding-top: 20px;
padding-bottom: 20px;
}
答案 3 :(得分:1)
您需要一步一步地执行此操作:
查询:
SELECT DISTINCT aya.aya_id,
aya_name,
(SELECT aya_name
FROM AYANTDROIT aya2
WHERE aya2.aya_id =
(SELECT ben_ben_id
FROM benefice LEFT OUTER JOIN ayantdroit ayad
ON ben_aya_id = ayad.aya_id
WHERE ayad.aya_id = **aya.AYA_ID**
)
)
FROM AYANTDROIT aya
ORDER BY aya_name