2012-01-28 39 views
4

我相信甲骨文功能FIRST_VALUE是什么,我需要基于这两个问题可以用: SQL - How to select a row having a column with max value
Oracle: Taking the record with the max dateOracle分析功能 - 使用FIRST_VALUE删除不需要的行

我有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 

我想列出的一组PE rson与这样相关联的我用这个查询:

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); 

这似乎类似于专业的Oracle SQL的FIRST_VALUE例子,但我似乎无法无论我如何调整参数,都可以使其工作。

如何仅返回给定组具有最高级别值(即树中最下面)的行?

回答

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

+0

max(name)和max(path)是什么意思?他们只是如此'保持'可以使用? – Paul 2012-01-28 17:35:43

+0

这个构造中的最大值(或最小值)仅在最后排列了多于一条记录的情况下才有意义。这里不可能在同一棵树上,并且具有相同的级别,所以你可以在这里使用min。 – 2012-01-28 17:55:19

+0

非常好...感谢您的出色解决方案。通过弄清楚它是如何工作的,我也学到了很多东西。 – Paul 2012-01-28 17:56:45

1

你应该划分仅OVER (PARTITION BY ID,NAME ORDER BY lev DESC)ID,NAME, path

编辑: ,也许你想first_value(path),不first_value(lev)

+0

这是更接近 - 在'FIRST_VALUE(路径)'列现在包含针对给定ID的所有行的正确值,但我仍然有重复标识。 – Paul 2012-01-28 16:26:48

+0

这就是你问的。最初,我发布了一个删除重复项的查询,但在一分钟后我删除了它,因为我明白你不想要那个。该查询与a_horse_with_no_name相同。 :) – 2012-01-28 19:19:11

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 
+0

有一个小小的变化('按顺序排列,而不是按顺序排列')它的工作原理 - 谢谢! – Paul 2012-01-28 16:37:50