Sql Oracle 11g-从列到行
我的系统格式中的数据无法更改,如下所示:Sql Oracle 11g-从列到行,sql,oracle11g,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, Sta
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个工会会一团糟
谢谢它不是很优雅,因为它使用了旧式的旋转,但我无法通过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
谢谢你的回答,他们让我思考。也很抱歉在回复中等待了很长时间,我已经下班两周了 我同意以下观点
WITH ss_query AS (
SELECT *
FROM tbl_data
)
, rowgen as (select /*+materialize()*/level yr from dual connect by level <= 3)
, dates as (select /*+materialize()*/to_date(substr(c001,1,2)||'0401','yymmdd') fy_start from ss_query where line = 2)
select equipment_name
, date_start
, date_end
, max(cost) cost
, max(speed) speed
from (
select
case when upper(c001) like '%COST%' then substr(c001,1,instr(upper(c001),'COST')-2)
when upper(c001) like '%SPEED%' then substr(c001,1,instr(upper(c001),'SPEED') -2)
end equipment_name,
add_months(fy_start,12 * (yr - 1)) date_start,
add_months(fy_start,12 * (yr))-1 date_end,
case when upper(c001) like '%SPEED%' then
case when yr = 1 then c002
when yr = 2 then c003
when yr = 3 then c004
end
end speed,
case when upper(c001) like '%COST%' then
case when yr = 1 then c002
when yr = 2 then c003
when yr = 3 then c004
end
end cost
from ss_query ,
rowgen,
dates
where line > 2
)
where speed is not null or cost is not null
group by equipment_name, date_start, date_end
order by equipment_name, date_start;
看起来像是和的复杂组合