2015-10-14 162 views
4

Oracle 11g R2正在使用中。這是我的源表:Oracle - 爲每個唯一列值生成唯一行並將行轉換爲列

ASSETNUM WONUM WODATE  TYPE1 TYPE2 LOCATION 
-------------------------------------------------------- 
W1   1001 2015-10-10 N  N  loc1 
W1   1002 2015-10-02 Y  N  loc2 
W1   1003 2015-10-04 Y  N  loc2 
W1   1004 2015-10-05 N  Y  loc2 
W1   1005 2015-10-07 N  Y  loc2 
W2   2001 2015-10-11 N  N  loc1 
W2   2002 2015-10-03 Y  N  loc2 
W2   2003 2015-10-02 Y  N  loc2 
W2   2004 2015-10-08 N  Y  loc3 
W2   2005 2015-10-06 N  Y  loc3 

http://sqlfiddle.com/#!4/8ee297/1

我想編寫一個查詢得到以下數據:

ASSETNUM LATEST  LOCATION for LATEST_WODATE_FOR LATEST_WODATE_FOR  
      WODATE  LATEST WODATE TYPE1=Y    TYPE2=Y 
---------------------------------------------------------------------------- 
W1   2015-10-10 loc1   2015-10-04   2015-10-07 
W2   2015-10-11 loc1   2015-10-03   2015-10-08 

我需要只有一行類似的結果集爲每個獨特的價值ASSETNUM。

任何幫助,將不勝感激!

回答

3

分析功能救援。

http://sqlfiddle.com/#!4/8ee297/4

select assetnum, 
     wodate, 
     wonum, 
     location, 
     last_type1_wodate, 
     last_type2_wodate 
from(select assetnum, 
      wodate, 
      wonum, 
      location, 
      rank() over (partition by assetnum order by wodate desc) rnk_wodate, 
      max(case when type1 = 'Y' then wodate else null end) 
       over (partition by assetnum) last_type1_wodate, 
      max(case when type2 = 'Y' then wodate else null end) 
       over (partition by assetnum) last_type2_wodate 
     from t) 
    where rnk_wodate = 1 

走過那是什麼做

  • rank() over (partition by assetnum order by wodate desc)通吃行特定assetnumwodate排序。外部where rnk_wodate = 1上的謂詞僅返回最近一行。如果可能存在關係,則可能需要使用dense_rankrow_number來取代rank,具體取決於您希望如何處理關係。
  • max(case when type1 = 'Y' then wodate else null end) over (partition by assetnum)獲取特定assetnum的所有行,並找到最大化case表達式的值。那將是最後一排type1 = 'Y'assetnum
+0

這太棒了!謝謝你的回答。它完全符合我的要求!我只需要在select查詢中添加'location'並且它工作正常。這絕對是我的首選答案,即使它有點難以理解。非常感謝演練! – squashbuff

2

我認爲這個概念最簡單的方法是簡單地查看您的問題,爲3個獨立的查詢,其中每個做一個GROUP BY獲得一些具體的東西(最新WODATE,最新WODATE的類型1,以及最新的WODATE對於Type2)。這些查詢可以輕鬆地連接在一起,爲您提供所需的輸出。

SELECT T.ASSETNUM, t1.LATEST_WODATE, T.LOCATION, t2.LATEST_WODATE_TYPE1, 
    t3.LATEST_WODATE_TYPE2 
FROM T INNER JOIN 
(
    SELECT ASSETNUM, MAX(WODATE) AS LATEST_WODATE 
    FROM T 
    GROUP BY ASSETNUM 
) t1 
ON T.ASSETNUM = t1.ASSETNUM AND T.WODATE = t1.LATEST_WODATE 
INNER JOIN 
(
    SELECT ASSETNUM, MAX(WODATE) AS LATEST_WODATE_TYPE1 
    FROM T 
    WHERE TYPE1 = 'Y' 
    GROUP BY ASSETNUM 
) t2 
ON T.ASSETNUM = t2.ASSETNUM 
INNER JOIN 
(
    SELECT ASSETNUM, MAX(WODATE) AS LATEST_WODATE_TYPE2 
    FROM T 
    WHERE TYPE2 = 'Y' 
    GROUP BY ASSETNUM 
) t3 
ON T.ASSETNUM = t3.ASSETNUM 

點擊下面的鏈接,運行演示:

SQLFiddle

+0

感謝您的回答,您是對的,從概念上講,這個答案是最容易遵循的。 – squashbuff

+0

另一個答案,即使有點難以遵循,更適合我的要求。我已將其他答案標記爲已接受的答案。對於那個很抱歉。 – squashbuff

2

使用聚合函數first

SQL Fiddle

查詢

select assetnum, 
     max(wodate), 
     max(wonum) keep (dense_rank first order by wodate desc) wonum, 
     max(case when type1 = 'Y' then wodate end) last_type1_wodate, 
     max(case when type2 = 'Y' then wodate end) last_type2_wodate 
from t 
group by 
     assetnum 

Results

| ASSETNUM |    MAX(WODATE) | WONUM |   LAST_TYPE1_WODATE |   LAST_TYPE2_WODATE | 
|----------|---------------------------|-------|---------------------------|---------------------------| 
|  W1 | October, 10 2015 00:00:00 | 1001 | October, 04 2015 00:00:00 | October, 07 2015 00:00:00 | 
|  W2 | October, 11 2015 00:00:00 | 2001 | October, 03 2015 00:00:00 | October, 08 2015 00:00:00 | 

(dense_rank) (first) (order by wodate desc)
( 2 ) ( 3 ) ( 1 )

  1. 順序在每個assetnum降序(如在指定GROUP BY子句)的日期。
  2. 將dense_rank賦值給它們。
  3. 只選擇第一條記錄。

在您的示例數據中,這將只選擇單個記錄。對應最近的日期。 但是你不能直接選擇wonum,因爲你使用的是GROUP BY子句。所以你必須使用一個聚合函數,它可以是MIN,MAX,SUM等。它只存在於語義上。

+0

謝謝。你能詳細解釋一下這個查詢嗎?我不確定爲什麼在這裏使用'max(wonum)'。 – squashbuff

+0

謝謝,我該如何在這個查詢中添加'location'? – squashbuff

+1

max(location)keep(dense_rank first order by wodate desc) – Noel