Oracle 11g - 列到行

时间:2016-02-07 22:15:47

标签: sql oracle11g

我的数据进入我的系统(格式无法更改),如下所示:

Row, C001,         C002, C003, to C029  (Columns for FY values)
1,   Name,         0910, 1011 
2,   Eqt1 (Speed), 60,   100
3,   Eqt1 (Cost),  20,   30 
4,   Eqt2 (Speed), 50,   60
5,   Eqt2 (Cost),  30,   45

我需要将其更改为:

Name, Start_Date,  End_Date,    Speed, Cost
Eqt1, 01-APR-2009, 30-MAR-2010, 60,    20
Eqt1, 01-APR-2010, 30-MAR-2011, 100,   30
Eqt2, 01-APR-2009, 30-MAR-2010, 50,    30
Eqt2, 01-APR-2010, 30-MAR-2011, 60,    45

我可以使用子选择分割日期,其中row = 1。 我可以替换名称中的(速度)(成本)。 但我无法做到。

  WITH survey_query AS  (
      SELECT    *
      FROM  tbl_data
  )
  SELECT    (CASE WHEN upper(sq.c001) LIKE '%FLEET SIZE%' THEN TRIM(REPLACE(upper(sq.c001), 'FLEET SIZE', ''))
                WHEN upper(sq.c001) LIKE '%FLYING HOURS%' THEN TRIM(REPLACE(upper(sq.c001), 'FLYING HOURS', ''))
           END) equipment_name
         ,(select TO_DATE(2000+dbms_lob.substr(c002,2,1)||'0101', 'yymmdd') FROM survey_query where line = 1) start_date
         ,(select TO_DATE(2000+dbms_lob.substr(c002,2,4)||'0330', 'yymmdd') FROM survey_query where line = 1) end_date
          ,(case when UPPER(sq.c001) like '%FLEET SIZE%' THEN sq.c002 END) fleet_size
          ,(case when UPPER(sq.c001) like '%FLYING HOURS%' THEN sq.c002 END) flying_hours
  FROM  survey_query sq
  WHERE line > 1
 UNION
   SELECT   (CASE WHEN upper(sq.c001) LIKE '%FLEET SIZE%' THEN TRIM(REPLACE(upper(sq.c001), 'FLEET SIZE', ''))
                WHEN upper(sq.c001) LIKE '%FLYING HOURS%' THEN TRIM(REPLACE(upper(sq.c001), 'FLYING HOURS', ''))
           END) equipment_name
         ,(select TO_DATE(2000+dbms_lob.substr(c003,2,1)||'0101', 'yymmdd') FROM survey_query where line = 1) start_date
         ,(select TO_DATE(2000+dbms_lob.substr(c003,2,4)||'0330', 'yymmdd') FROM survey_query where line = 1) end_date
          ,(case when UPPER(sq.c001) like '%FLEET SIZE%' THEN sq.c003 END) fleet_size
          ,(case when UPPER(sq.c001) like '%FLYING HOURS%' THEN sq.c003 END) flying_hours
  FROM  survey_query sq
  WHERE line > 1;

有什么想法吗?我必须有一个更好的方法,因为我有28列的数据,所以27"工会"

由于

2 个答案:

答案 0 :(得分:0)

它不是很优雅,因为它使用了旧式的旋转,但我无法通过11g PIVOT功能来解决这个问题:

with sample_data as (select 1 row#, 'Name' c001, 0910 c002, 1011 c003, 1112 c004 from dual union all
                     select 2 row#, 'Eqt1 (Speed)' c001, 60 c002, 100 c003, 140 c004 from dual union all
                     select 3 row#, 'Eqt1 (Cost)' c001, 20 c002, 30 c003, 80 c004 from dual union all
                     select 4 row#, 'Eqt2 (Speed)' c001, 50 c002, 60 c003, 70 c004 from dual union all
                     select 5 row#, 'Eqt2 (Cost)' c001, 30 c002, 45 c003, 56 c004 from dual),
-- end of mimicking your table as a subquery called "sample_data"
-- you wouldn't need this subquery, since you would have your own table/query to use in place
-- change the table name referred to in the res subquery below as appropriate
             res as (select row#,
                            case when c001 like '%(Speed)' then substr(c001, 1, length(c001) - 8)
                                 when c001 like '%(Cost)' then substr(c001, 1, length(c001) - 7)
                                 else c001
                            end name,
                            case when c001 like '%(Speed)' then 'Speed'
                                 when c001 like '%(Cost)' then 'Cost'
                                 else c001
                            end type,
                            to_date('01/04'||substr(first_value(lpad(c002, 4, 0)) over (order by row#), 1, 2), 'dd/mm/rr') fy1_start_date,
                            to_date('31/03'||substr(first_value(lpad(c002, 4, 0)) over (order by row#), 3, 2), 'dd/mm/rr') fy1_end_date,
                            to_date('01/04'||substr(first_value(lpad(c003, 4, 0)) over (order by row#), 1, 2), 'dd/mm/rr') fy2_start_date,
                            to_date('31/03'||substr(first_value(lpad(c003, 4, 0)) over (order by row#), 3, 2), 'dd/mm/rr') fy2_end_date,
                            to_date('01/04'||substr(first_value(lpad(c004, 4, 0)) over (order by row#), 1, 2), 'dd/mm/rr') fy3_start_date,
                            to_date('31/03'||substr(first_value(lpad(c004, 4, 0)) over (order by row#), 3, 2), 'dd/mm/rr') fy3_end_date,
                            c002,
                            c003,
                            c004
                     from   sample_data),
           dummy as (select level id
                     from   dual
                     connect by level <= 3 -- num fyears to consider
                     )
select   name,
         case when d.id = 1 then res.fy1_start_date
              when d.id = 2 then res.fy2_start_date
              when d.id = 3 then res.fy3_start_date
         end start_date,
         case when d.id = 1 then res.fy1_end_date
              when d.id = 2 then res.fy2_end_date
              when d.id = 3 then res.fy3_end_date
         end end_date,
         max(case when d.id = 1 and res.type = 'Speed' then c002
                  when d.id = 2 and res.type = 'Speed' then c003
                  when d.id = 3 and res.type = 'Speed' then c004
             end) speed,
         max(case when d.id = 1 and res.type = 'Cost' then c002
                  when d.id = 2 and res.type = 'Cost' then c003
                  when d.id = 3 and res.type = 'Cost' then c004
             end) cost
from     res
         cross join dummy d
where    res.row# != 1
group by name,
         case when d.id = 1 then res.fy1_start_date
              when d.id = 2 then res.fy2_start_date
              when d.id = 3 then res.fy3_start_date
         end,
         case when d.id = 1 then res.fy1_end_date
              when d.id = 2 then res.fy2_end_date
              when d.id = 3 then res.fy3_end_date
         end
order by name, start_date;

NAME  START_DATE  END_DATE         SPEED       COST
----- ----------- ----------- ---------- ----------
Eqt1  01-APR-2009 31-MAR-2010         60         20
Eqt1  01-APR-2010 31-MAR-2011        100         30
Eqt1  01-APR-2011 31-MAR-2012        140         80
Eqt2  01-APR-2009 31-MAR-2010         50         30
Eqt2  01-APR-2010 31-MAR-2011         60         45
Eqt2  01-APR-2011 31-MAR-2012         70         56

答案 1 :(得分:0)

感谢您的回答,他们让我思考。也很抱歉在回复中等了很长时间,我已经工作了2周。

我已经离开了以下

str.replaceAll("\\p{Blank}+", "").replaceAll("[\\.\\*\\?]+", ".*?");