如何将此混合行/列表转换为所需的输出。(Oracle SQL/Release:Ora12c)

如何将此混合行/列表转换为所需的输出。(Oracle SQL/Release:Ora12c),sql,oracle,pivot,Sql,Oracle,Pivot,我有这个Excel输入文件被远程传递,并试图导入到这个最终结果,没有任何运气。如有任何帮助/建议,将不胜感激。到目前为止,我已经尝试了Oracle LEAD函数来获取要透视的前6行(如果在本例中这是正确的术语的话),其余的都有问题 因此,我输入的数据是这种格式的(我在第4列末尾添加了行号,以使我的LEAD函数工作) 我想让它成为这种输出格式 +------+------+------+--------+--------+------+------+--------------+-------+

我有这个Excel输入文件被远程传递,并试图导入到这个最终结果,没有任何运气。如有任何帮助/建议,将不胜感激。到目前为止,我已经尝试了Oracle LEAD函数来获取要透视的前6行(如果在本例中这是正确的术语的话),其余的都有问题

因此,我输入的数据是这种格式的(我在第4列末尾添加了行号,以使我的LEAD函数工作)

我想让它成为这种输出格式


+------+------+------+--------+--------+------+------+--------------+-------+
| Col1 | Col2 | Col3 |  Col4  |  Col5  | Col6 | Col7 |     Col8     | Col9  |
+------+------+------+--------+--------+------+------+--------------+-------+
| 2019 | ABC  | xyz  | 112233 | 555666 | C    | 1000 | blahblahblah | $1000 |
| 2019 | ABC  | xyz  | 112233 | 555666 | C    | 1001 | blahblahxxyy | $999  |
| 2019 | ABC  | xyz  | 112233 | 555666 | C    | 1029 | blahblahxxyy | $7676 |
| ...  | ...  | ...  | ...    | ...    | .    | ...  | ...          | ...   |
| 2019 | EFG  | xyz  | 112233 | 555888 | C    | 1000 | blahblahblah | $4440 |
| 2019 | EFG  | xyz  | 112233 | 555888 | C    | 1001 | blahblahxxyy | $3875 |
| 2019 | EFG  | xyz  | 112233 | 555888 | C    | 1029 | blahblahxxyy | $5029 |
| ...  | ...  | ...  | ...    | ...    | .    | ...  | ...          | ...   |
+------+------+------+--------+--------+------+------+--------------+-------+
基本上,我需要将前6行(如果愿意的话,标题行)转换为它们下面的行号的水平/重复值。然后在n上重复逻辑,因为这些标题部分一直在重复,下面是行号表

感谢您的指点/帮助

注:这是我迄今为止一直在尝试/想出的方法

select (CASE WHEN Col1 = 'FYear' THEN Col2 END) New_Col1, 
LEAD((CASE WHEN Col1 = 'Office' THEN Col2 END)) OVER (ORDER BY Col4) New_Col2,
LEAD((CASE WHEN Col1 = 'Org' THEN Col2 END),2,0) OVER (ORDER BY Col4) New_Col3,
LEAD((CASE WHEN Col1 = 'Acct' THEN Col2 END),3,0) OVER (ORDER BY Col4) New_Col4,
LEAD((CASE WHEN Col1 = 'SubAcct' THEN Col2 END),4,0) OVER (ORDER BY Col4) New_Col5,
LEAD((CASE WHEN Col1 = 'Status' THEN Col2 END),5,0) OVER (ORDER BY Col4) New_Col6
from demo_table
where col4 <7;

select(Col1='FYear'然后Col2 END时的情况)New_Col1,
在(Col4订购)新的Col2上引入(Col1=办公室然后Col2结束时的情况),
领先(Col1='Org'然后Col2 END时的情况),2,0)超过(Col4订单)新的Col3,
领先((Col1='Acct'然后Col2 END时的情况),3,0)超过(Col4订单)新的Col4,
领先(Col1=子CCT后Col2结束时的情况),4,0)超过(按Col4排序)新的Col5,
领先(Col1=状态后Col2结束时的情况),5,0)超过(Col4订单)新的Col6
从demo_表
其中,col4根据col4除以9,将“传统”旋转的第1-6行与每个行号的第“1000”、“1001”、“1029”行连接起来:

with 
  d as (select t.*, floor((col4 - 1) / 9) + 1 rn from t),
  a as (select rn, 
               max(case col1 when 'FYear' then col2 end) col1,
               max(case col1 when 'Office' then col2 end) col2,
               max(case col1 when 'Org' then col2 end) col3,
               max(case col1 when 'Acct' then col2 end) col4,
               max(case col1 when 'SubAcct' then col2 end) col5,
               max(case col1 when 'Status' then col2 end) col6
          from d group by rn),
  b as (select rn, col1 as col7, col2 as col8, col3 as col9 
          from d where col1 in ('1000', '1001', '1029'))
select * 
  from a join b using (rn)
  order by rn, col7

根据col4除以9,将每个行号的“传统”枢轴行1-6与行“1000”、“1001”、“1029”连接起来:

with 
  d as (select t.*, floor((col4 - 1) / 9) + 1 rn from t),
  a as (select rn, 
               max(case col1 when 'FYear' then col2 end) col1,
               max(case col1 when 'Office' then col2 end) col2,
               max(case col1 when 'Org' then col2 end) col3,
               max(case col1 when 'Acct' then col2 end) col4,
               max(case col1 when 'SubAcct' then col2 end) col5,
               max(case col1 when 'Status' then col2 end) col6
          from d group by rn),
  b as (select rn, col1 as col7, col2 as col8, col3 as col9 
          from d where col1 in ('1000', '1001', '1029'))
select * 
  from a join b using (rn)
  order by rn, col7

我支持行在DB中没有排序的评论。 此外,您不需要指定段的行数是否可以超过9行

我有一个解决方案,它适用于任何数量的行pr段,如果以某种方式保留顺序,它需要每个段在col1中以“FYear”开头,并且为了保留顺序,但不关心头行之后是否正好有三行

设置:

create table testtbl
(
  col1 varchar2(100)
  ,col2 varchar2(100)
  ,col3 varchar2(100)
  ,col4 int
  )
insert into testtbl values ('FYear'  ,2019,'',1);
insert into testtbl values ('Office' ,'ABC','',2);
insert into testtbl values ('Org'    ,'xyz','',3);
insert into testtbl values ('Acct'   ,11122233,'',4);
insert into testtbl values ('SubAcct',555666,'',5);
insert into testtbl values ('Status' ,'C','',6);
insert into testtbl values (1000     ,'blahblahblah',1000,7);
insert into testtbl values (1001     ,'blahblahxxyy',999,8);
insert into testtbl values (1029     ,'blahblahxxyy',7676,9);
insert into testtbl values ('FYear'  ,2019,'',10);
insert into testtbl values ('Office' ,'EFG','',11);
insert into testtbl values ('Org'    ,'xyz','',12);
insert into testtbl values ('Acct'   ,11122233,'',13);
insert into testtbl values ('SubAcct',555888,'',14);
insert into testtbl values ('Status' ,'C','',15);
insert into testtbl values (1000     ,'blahblahblah',4440,16);
insert into testtbl values (1001     ,'blahblahxxyy',3875,17);
insert into testtbl values (1029     ,'blahblahxxyy',5029,18);
解决方案:

我首先创建一个grp,它跨越序列中的所有行,然后在该组中找到标题值并将它们放在前6列中。然后,我将原来的3列添加为col7-9,最后过滤掉包含标题的行

select 
col1,col2,col3,col4,col5,col6,col7,col8,col9
from
(
select 
   max(case when col1='FYear' then Col2 else '' end)    over (partition by grp) Col1
  ,max(case when col1='Office' then Col2 else '' end)   over (partition by grp) Col2
  ,max(case when col1='Org' then Col2 else '' end)      over (partition by grp) Col3
  ,max(case when col1='Acct' then Col2 else '' end)     over (partition by grp) Col4
  ,max(case when col1='SubAcct' then Col2 else '' end)  over (partition by grp) Col5
  ,max(case when col1='Status' then Col2 else '' end)   over (partition by grp) Col6  
  , col1  col7
  , col2  col8
  , col3  col9
from 
(
select
  col1,col2,col3,col4
  ,sum(case when col1='FYear' then 1 else 0 end ) over (order by col4) grp
from testtbl t 
) a
) b
where  col7 not in('FYear','Office','Org','Acct','SubAcct','Status' )

我支持在DB中没有对行排序的注释。 此外,您不需要指定段的行数是否可以超过9行

我有一个解决方案,它适用于任何数量的行pr段,如果以某种方式保留顺序,它需要每个段在col1中以“FYear”开头,并且为了保留顺序,但不关心头行之后是否正好有三行

设置:

create table testtbl
(
  col1 varchar2(100)
  ,col2 varchar2(100)
  ,col3 varchar2(100)
  ,col4 int
  )
insert into testtbl values ('FYear'  ,2019,'',1);
insert into testtbl values ('Office' ,'ABC','',2);
insert into testtbl values ('Org'    ,'xyz','',3);
insert into testtbl values ('Acct'   ,11122233,'',4);
insert into testtbl values ('SubAcct',555666,'',5);
insert into testtbl values ('Status' ,'C','',6);
insert into testtbl values (1000     ,'blahblahblah',1000,7);
insert into testtbl values (1001     ,'blahblahxxyy',999,8);
insert into testtbl values (1029     ,'blahblahxxyy',7676,9);
insert into testtbl values ('FYear'  ,2019,'',10);
insert into testtbl values ('Office' ,'EFG','',11);
insert into testtbl values ('Org'    ,'xyz','',12);
insert into testtbl values ('Acct'   ,11122233,'',13);
insert into testtbl values ('SubAcct',555888,'',14);
insert into testtbl values ('Status' ,'C','',15);
insert into testtbl values (1000     ,'blahblahblah',4440,16);
insert into testtbl values (1001     ,'blahblahxxyy',3875,17);
insert into testtbl values (1029     ,'blahblahxxyy',5029,18);
解决方案:

我首先创建一个grp,它跨越序列中的所有行,然后在该组中找到标题值并将它们放在前6列中。然后,我将原来的3列添加为col7-9,最后过滤掉包含标题的行

select 
col1,col2,col3,col4,col5,col6,col7,col8,col9
from
(
select 
   max(case when col1='FYear' then Col2 else '' end)    over (partition by grp) Col1
  ,max(case when col1='Office' then Col2 else '' end)   over (partition by grp) Col2
  ,max(case when col1='Org' then Col2 else '' end)      over (partition by grp) Col3
  ,max(case when col1='Acct' then Col2 else '' end)     over (partition by grp) Col4
  ,max(case when col1='SubAcct' then Col2 else '' end)  over (partition by grp) Col5
  ,max(case when col1='Status' then Col2 else '' end)   over (partition by grp) Col6  
  , col1  col7
  , col2  col8
  , col3  col9
from 
(
select
  col1,col2,col3,col4
  ,sum(case when col1='FYear' then 1 else 0 end ) over (order by col4) grp
from testtbl t 
) a
) b
where  col7 not in('FYear','Office','Org','Acct','SubAcct','Status' )

由于您使用的是Oracle 12,因此可以利用
match\u recognize
,这将快速解决此问题。(在Oracle 11中,您可以使用联接和旋转,如Plnder Stibbons所示,但这会更慢。)

请注意,我为输出中的前六列提供了更有意义的名称;对于最后三列,您应该找到比
col7、col8、col9更好的名称。我还将
fyear
acct
subacct
转换为number数据类型,这是您可能需要的。我允许
col1
中的“已旋转”值(如
'1000'
等)为除六个特殊值
'FYear',Office'
等以外的任何值(包括该值有时可能为
null
)-这可以从
match\u recognize
define
子句中分类为“x”的行的定义中看出

通过您的输入数据,我得到以下输出:

FYEAR OFFICE ORG     ACCT SUBACCT STATUS COL7 COL8         COL9
----- ------ --- -------- ------- ------ ---- ------------ -----
 2019 ABC    xyz 11122233 555666  C      1000 blahblahblah $1000
 2019 ABC    xyz 11122233 555666  C      1001 blahblahxxyy $999
 2019 ABC    xyz 11122233 555666  C      1029 blahblahxxyy $7676
 2019 EFG    xyz 11122233 555888  C      1000 blahblahblah $4440
 2019 EFG    xyz 11122233 555888  C      1001 blahblahxxyy $3875
 2019 EFG    xyz 11122233 555888  C      1029 blahblahxxyy $5029
您可能还应该将
col9
转换为数字;我没有表现出来,因为这取决于你真正拥有什么。它总是
null
还是美元值(前面有美元符号的数字)?不管怎样,这是一个与你的问题无关的问题,但是请考虑一下。
另一个重要的注意事项:我假设您的“段”总是将前六行作为“特殊”行,精确的值在
col1
中,正如您在示例中显示的那样。剩余的行可以有
col1
中的任何内容(特殊值除外),并且这些行的数量可以是任何内容,包括无,在这种情况下,相应的“段”将在输出中产生绝对无任何内容。如果在这种特殊情况下需要不同的处理方式,可以很容易地适应,您只需解释该处理方式是什么。

由于您使用的是Oracle 12,您可以利用
匹配识别
,这将快速解决此问题。(在Oracle 11中,您可以使用联接和旋转,如Plnder Stibbons所示,但这会更慢。)

请注意,我为输出中的前六列提供了更有意义的名称;对于最后三列,您应该找到比
col7、col8、col9更好的名称。我还将
fyear
acct
subacct
转换为number数据类型,这是您可能需要的。我允许
col1
中的“已旋转”值(如
'1000'
等)是除六个特殊值
'FYear'、'Office'
等以外的任何值(包括该值有时可能为
null
)-这在分类为'