2012-01-28 67 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