Oracle - 为每个唯一列值生成唯一行,并将行转换为列

时间:2015-10-14 05:19:54

标签: sql oracle

Oracle 11g R2正在使用中。这是我的源表:

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 个答案:

答案 0 :(得分: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)获取特定assetnum的所有行,并按wodate对其进行排序。外部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

答案 1 :(得分:2)

我认为概念上最简单的方法是简单地将您的问题视为3个单独的查询,每个查询都执行GROUP BY以获取某些特定内容(最新WODATE,最新{ Type1为{1}},Type2为WODATE。这些查询可以很容易地连接在一起,为您提供所需的输出。

WODATE

点击以下链接查看正在运行的演示:

SQLFiddle

答案 2 :(得分: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. 仅选择第一条记录。
  4. 在您的示例数据中,这将仅选择单个记录。对应最新日期。 但是你不能直接选择wonum,因为你正在使用GROUP BY子句。所以你必须使用一个聚合函数,它可以是MIN,MAX,SUM等。它仅用于语义目的。