我认为Oracle函数FIRST_VALUE是基于这两个问题我需要使用的:
SQL - How to select a row having a column with max value
Oracle: Taking the record with the max date
我有3个表格,代表与组织相关联的人员。每个组织可能都有一个父组织,其中ORG.PARENT是ORG.ID的外键(因此表引用自身)。一个人可能与多个团体有关。
PERSON
ID NAME
----------
1 Bob
ORG
ID NAME PARENT
------------------------
1 A (null)
2 A-1 1
3 A-2 1
4 A-3 1
5 A-1-a 2
6 A-1-b 2
7 A-2-a 3
8 A-2-b 3
PERSON_TO_ORG
PERSON_ID ORG_ID
-----------------
1 1
1 3
我想列出与之关联的群组,因此我使用了此查询:
SELECT NAME, ID, sys_connect_by_path(NAME, '/') AS path
FROM org
START WITH ID IN
(SELECT org_id FROM person_to_org WHERE person_id=1)
connect by prior org.ID = org.parent;
......这给了我:
NAME ID PATH
------------------
A-2 3 /A-2
A-2-a 8 /A-2/A-2-a
A-2-b 9 /A-2/A-2-b
A 1 /A
A-1 2 /A/A-1
A-1-a 5 /A/A-1/A-1-a
A-1-b 6 /A/A-1/A-1-b
A-2 3 /A/A-2
A-2-a 8 /A/A-2/A-2-a
A-2-b 9 /A/A-2/A-2-b
A-3 4 /A/A-3
注意A-2应该如何出现两次。但是,我不希望组出现两次。我希望一个组只出现在树中的最低级别,即最高级别的值。以下是我尝试使用FIRST_VALUE而没有运气的方法 - 我仍然让A-2(和其他人)出现两次:
SELECT id, name, path, first_value(lev) OVER
(
PARTITION BY ID,NAME, path ORDER BY lev DESC
) AS max_lev FROM
(SELECT NAME, ID, sys_connect_by_path(NAME, '/') AS path, LEVEL as lev
FROM org START WITH ID IN
(SELECT org_id FROM person_to_org WHERE person_id=1)
connect by prior org.ID = org.parent);
这看起来类似于Pro Oracle SQL中的FIRST_VALUE示例,但无论我如何调整参数,我似乎无法使其工作。
如何只返回给定组具有最高级别值的行(即树中最远的行)?
答案 0 :(得分:3)
正如您所提到的其中一个主题所述,分析并不是最有效的方法:您需要聚合以过滤掉重复项。
SQL> SELECT id
2 , max(name) keep (dense_rank last order by lev) name
3 , max(path) keep (dense_rank last order by lev) path
4 FROM ( SELECT NAME
5 , ID
6 , sys_connect_by_path(NAME, '/') AS path
7 , LEVEL as lev
8 FROM org
9 START WITH ID IN (SELECT org_id FROM person_to_org WHERE person_id=1)
10 connect by prior org.ID = org.parent
11 )
12 group by id
13 /
ID NAME PATH
---------- ----- --------------------
1 A /A
2 A-1 /A/A-1
3 A-2 /A/A-2
4 A-3 /A/A-3
5 A-1-a /A/A-1/A-1-a
6 A-1-b /A/A-1/A-1-b
7 A-2-a /A/A-2/A-2-a
8 A-2-b /A/A-2/A-2-b
8 rows selected.
的问候,
罗布。
PS:以下是有关最后聚合函数的更多信息:http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions071.htm#sthref1495
答案 1 :(得分:2)
这个(未经测试的)
SELECT
SELECT id,
name,
path
FROM (
SELECT id,
name,
path,
row_number() over (partition by id,name order by lev desc) as rn
FROM (
SELECT NAME,
ID,
sys_connect_by_path(NAME, '/') AS path,
LEVEL as lev
FROM org
START WITH ID IN (SELECT org_id FROM person_to_org WHERE person_id=1)
connect by prior org.ID = org.parent
)
)
where rn = 1
答案 2 :(得分:1)
您应该只对OVER (PARTITION BY ID,NAME ORDER BY lev DESC)
进行分区
不是ID,NAME, path
编辑:
您可能需要first_value(path)
,而不是first_value(lev)