【问题标题】:Oracle analytic function - using FIRST_VALUE to remove unwanted rowsOracle 分析函数 - 使用 FIRST_VALUE 删除不需要的行
【发布时间】:2012-02-21 05:30:36
【问题描述】:

基于以下两个问题,我认为我需要使用 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 的外键(因此该表引用自身)。一个人可能与多个组相关联。

ID    NAME
----------
1     Bob

组织

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 示例,但无论我如何调整参数,我似乎都无法使其工作。

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

【问题讨论】:

    标签: sql oracle oracle10g oracle-analytics


    【解决方案1】:

    你应该只分区OVER (PARTITION BY ID,NAME ORDER BY lev DESC) 不是ID,NAME, path

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

    【讨论】:

    • 更接近了 - first_value(path) 列现在包含给定 ID 的所有行的正确值,但我仍然有重复的 ID。
    • 这是你问的。最初,我发布了一个删除重复项的查询,但在一分钟内我删除了它,因为我知道你不想要那个。该查询与 a_horse_with_no_name 相同。 :)
    【解决方案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
    

    【讨论】:

    • 稍作改动(order by lev,而不是order by level)就可以了——谢谢!
    【解决方案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:这里是关于 LAST 聚合函数的更多信息:http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions071.htm#sthref1495

    【讨论】:

    • max(name)max(path) 的用途是什么?它们只是这样keep 可以使用吗?
    • 此构造中的 max(或 min)仅在最后订购多个记录的情况下才相关。在这里不可能在同一棵树中并且具有相同的级别,因此您可以在此处使用 min 代替。
    • 太好了...感谢您提供的出色解决方案。通过弄清楚它是如何工作的,我也学到了很多东西。
    猜你喜欢
    • 2015-08-11
    • 2013-03-06
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-21
    相关资源
    最近更新 更多