我正在尝试将多行合并为一行。列值需要成为列名,并且需要是动态的,因为可能会添加更多列值
当前
key attribute value reason message
1001 Att1 Val1 Reason 1 Message 1
1001 Att2 Val2 Reason 1 Message 1
1001 Att3 Val3 Reason 1 Message 1
1002 Att1 Val4 Reason 2 Message 2
1002 Att2 Val5 Reason 2 Message 2
1002 Att4 Val7 Reason 2 Message 2
1002 Att5 Val8 Reason 2 Message 2
1002 Att6 Val9 Reason 2 Message 2
想要这个结构
key Att1 Att2 Att3 Att4 Att5 Att6 reason message
1001 Val1 Val2 Val3 Reason 1 Message 1
1002 Val4 Val5 Val7 Val8 Val9 Reason 2 Message 2
请帮忙!
答案 0 :(得分:0)
要获得结果,您需要进行PIVOT操作;主要问题是你需要它是动态的,所以我们事先并不知道你会得到的数字或列数。
您可以尝试使用一些动态SQL,构建一个与您的数据匹配的语句:
declare
vSQL varchar2(32767) :=
' from (select * from test)
pivot (max(value) for attribute in (';
vAttributes varchar2(32767);
vOutputFields varchar2(32767) := 'key || '' | '' || reason || '' | '' || message || '' | '' || ';
vAllFields varchar2(3) := '*';
vClob clob;
type tabVarchar2 is table of varchar2(32767);
vTabVarchar2 tabVarchar2;
vSQLOneField varchar2(32767);
vSQLMoreFields varchar2(32767);
begin
-- get the columns
select listagg( '''' || attribute || '''', ',') within group (order by attribute),
vOutputFields || listagg( '"''' || attribute || '''"', '|| '' | '' || ') within group (order by attribute)
into vAttributes, vOutputFields
from (select distinct attribute from test) ;
-- build the statement for many fields
vSQLMoreFields := 'select ' || vAllFields || vSQL || vAttributes || '))';
-- print the query
dbms_output.put_line(vSQLMoreFields);
-- fetch it as a unique XML
select DBMS_XMLGEN.getXML(vSQLMoreFields)
into vClob
from dual;
dbms_output.put_line(vClob);
-- build the statement for a unique field
vSQLOneField := 'select ' || vOutputFields || ' from (' || vSQLMoreFields || ')';
-- print the query
dbms_output.put_line(vSQLOneField);
-- fetch as a unique field into a structure
execute immediate vSQLOneField bulk collect into vTabVarchar2;
for i in 1 .. vTabVarchar2.last loop
dbms_output.put_line( vTabVarchar2(i));
end loop;
end;
我主要看到两个问题:
varchar2
的数组,每个值包含整行; 答案 1 :(得分:0)
另一种方法是这个:
CREATE OR REPLACE FUNCTION TransposeTab RETURN SYS_REFCURSOR AS
cur SYS_REFCURSOR;
sqlstr VARCHAR2(10000);
BEGIN
sqlstr := 'SELECT * FROM TABLE1 PIVOT (MAX(val) FOR ATTRIBUTE IN (';
FOR aCol IN (SELECT DISTINCT ATTRIBUTE FROM TABLE1) LOOP
sqlstr := sqlstr || ''''||aCol.ATTRIBUTE||''' AS "'||aCol.ATTRIBUTE||'",';
END LOOP;
sqlstr := REGEXP_REPLACE(sqlstr, ',$','))');
--DBMS_OUTPUT.PUT_LINE ( sqlstr );
OPEN cur FOR sqlstr;
RETURN cur;
END;
为了得到结果,你可以做到这一点。
SELECT TransposeTab FROM dual;
或(仅限SQL * Plus)
var rc refcursor
EXEC :rc := TransposeTab;
PRINT rc