我使用的是Oracle 10g,我有一个表,可以在给定的一天存储一个人的数据快照。对于核心数据发生任何变化(存储在其他地方)的任何人,每晚都会向表格添加新行。这允许使用日期来编写查询,以找出过去一天中某人“看起来”的样子。即使只有人的一个方面发生了变化,也会向表中添加一个新行 - 这意味着许多列在切片之间具有重复值,因为并非每个快照中的每个细节都发生了更改。
以下是数据样本:
SliceID PersonID StartDt Detail1 Detail2 Detail3 Detail4 ...
1 101 08/20/09 Red Vanilla N 23
2 101 08/31/09 Orange Chocolate N 23
3 101 09/15/09 Yellow Chocolate Y 24
4 101 09/16/09 Green Chocolate N 24
5 102 01/10/09 Blue Lemon N 36
6 102 01/11/09 Indigo Lemon N 36
7 102 02/02/09 Violet Lemon Y 36
8 103 07/07/09 Red Orange N 12
9 104 01/31/09 Orange Orange N 12
10 104 10/20/09 Yellow Orange N 13
我需要编写一个查询来提取时间片记录,其中一些相关位而不是整个记录已经改变。因此,参考上面的内容,如果我只想知道Detail3从其先前值改变的切片,那么我希望只能获得PersonID 101的SliceID 1,3和4以及PersonID的SliceID 5和7的行102和SliceID 8用于PersonID 103,SliceID 9用于PersonID 104。
我在想我应该能够使用某种Oracle Hierarchical Query(使用CONNECT BY [PRIOR])来获得我想要的东西,但我还没弄清楚如何编写它。也许你可以帮忙。
感谢您的时间和考虑。
答案 0 :(得分:2)
这是我对LAG()解决方案的看法,它基本上与egorius相同,但我展示了我的工作;)
SQL> select * from
2 (
3 select sliceid
4 , personid
5 , startdt
6 , detail3 as new_detail3
7 , lag(detail3) over (partition by personid
8 order by startdt) prev_detail3
9 from some_table
10 )
11 where prev_detail3 is null
12 or ( prev_detail3 != new_detail3 )
13 /
SLICEID PERSONID STARTDT N P
---------- ---------- --------- - -
1 101 20-AUG-09 N
3 101 15-SEP-09 Y N
4 101 16-SEP-09 N Y
5 102 10-JAN-09 N
7 102 02-FEB-09 Y N
8 103 07-JUL-09 N
9 104 31-JAN-09 N
7 rows selected.
SQL>
关于这个解决方案的一点是它在103和104的结果中运行,他们没有切片记录,其中detail3已经改变。如果这是一个问题,我们可以应用额外的过滤,只返回有变化的行:
SQL> with subq as (
2 select t.*
3 , row_number () over (partition by personid
4 order by sliceid ) rn
5 from
6 (
7 select sliceid
8 , personid
9 , startdt
10 , detail3 as new_detail3
11 , lag(detail3) over (partition by personid
12 order by startdt) prev_detail3
13 from some_table
14 ) t
15 where t.prev_detail3 is null
16 or ( t.prev_detail3 != t.new_detail3 )
17 )
18 select sliceid
19 , personid
20 , startdt
21 , new_detail3
22 , prev_detail3
23 from subq sq
24 where exists ( select null from subq x
25 where x.personid = sq.personid
26 and x.rn > 1 )
27 order by sliceid
28 /
SLICEID PERSONID STARTDT N P
---------- ---------- --------- - -
1 101 20-AUG-09 N
3 101 15-SEP-09 Y N
4 101 16-SEP-09 N Y
5 102 10-JAN-09 N
7 102 02-FEB-09 Y N
SQL>
修改强>
正如egorius在评论中指出的那样,OP 希望所有用户都能点击,即使他们没有更改,所以查询的第一个版本是正确的解决方案。
答案 1 :(得分:1)
我认为你对LAG函数有更好的运气:
SELECT s.sliceid
FROM (SELECT t.sliceid,
t.personid,
t.detail3,
LAG(t.detail3) OVER (PARTITION BY t.personid ORDER BY t.startdt) 'prev_val'
FROM TABLE t) s
WHERE s.personid = 101
AND (s.prev_val IS NULL OR s.prev_val != s.detail3)
子查询保理选择:
WITH slices AS (
SELECT t.sliceid,
t.personid,
t.detail3,
LAG(t.detail3) OVER (PARTITION BY t.personid ORDER BY t.startdt) 'prev_val'
FROM TABLE t)
SELECT s.sliceid
FROM slices s
WHERE s.personid = 101
AND (s.prev_val IS NULL OR s.prev_val != s.detail3)
答案 2 :(得分:1)
除了OMG小马的回答:如果你需要查询所有人的切片,你需要partition by
:
SELECT s.sliceid
, s.personid
FROM (SELECT t.sliceid,
t.personid,
t.detail3,
LAG(t.detail3) OVER (
PARTITION BY t.personid ORDER BY t.startdt
) prev_val
FROM t) s
WHERE (s.prev_val IS NULL OR s.prev_val != s.detail3)