我有以下Oracle数据库,可以通过Web应用程序中的用户干预随时间增长任意数量的列。
ID | Name | Football | WhoCreated | When | Baseball | Cheerleading | Swimming
1 | Billy | (null) | sam, smith | (Timestamp)| 1 | (null) | 1
2 | Susie | 1 | sam, smith | (Timestamp)| (null) | 1 | 1
3 | Johnny | 1 | Homer | (Timestamp)| 1 | (null) | (null)
我正在尝试生成一个看起来像
的输出2, Susie, Football
3, Johnny, Football
1, Billy, Baseball
3, Johnny, Baseball
2, Susie, Cheerleading
1, Billy, Swimming
2, Susie, Swimming
我可以使用UNION执行此操作,但我必须针对特定名称字段调整每个。我已经达到了大约50列(50个工会),并且系统中的用户可以随时增长。为了进一步复杂化,我在列表中间有一些用于审计目的的列。我真的需要某种循环遍历列的动态方式,我已经搜索过了,但似乎都没有解决我的问题。
答案 0 :(得分:0)
这应该会给你一个想法。我无法测试它,但很容易理解。
create or replace package test_pkg AS
TYPE REP_CURS IS REF CURSOR;
TYPE output_REC IS RECORD(
id_ number,
name_ varchar2(50),
field_ varchar2(50));
TYPE output_TAB IS TABLE OF output_REC;
FUNCTION Get_Data RETURN output_TAB
PIPELINED;
END test_pkg;
CREATE OR REPLACE PACKAGE BODY test_pkg IS
FUNCTION Get_Data RETURN output_TAB
PIPELINED IS
output_REC_ output_REC;
rep_lines_ REP_CURS;
stmt_ VARCHAR2(5000);
table_rec_ yourtable%ROWTYPE;
begin
stmt_ := ' YOUR QUERY HERE ';
OPEN rep_lines_ FOR stmt_;
LOOP
FETCH rep_lines_
INTO table_rec_;
EXIT WHEN rep_lines_%NOTFOUND;
output_REC_.id_ := table_rec_.id;
output_REC_.name_ := table_rec_.name;
if table_rec_.football IS not null then
output_REC_.field_ := table_rec_.football;
PIPE ROW(output_REC_);
end if;
if table_rec_.Baseball IS not null then
output_REC_.field_ := table_rec_.Baseball;
PIPE ROW(output_REC_);
end if;
if table_rec_.Cheerleading IS not null then
output_REC_.field_ := table_rec_.Cheerleading;
PIPE ROW(output_REC_);
end if;
if table_rec_.Swimming IS not null then
output_REC_.field_ := table_rec_.Swimming;
PIPE ROW(output_REC_);
end if;
END LOOP;
CLOSE rep_lines_;
RETURN;
exception
when others then
DBMS_OUTPUT.put_line('Error:' || DBMS_UTILITY.FORMAT_ERROR_BACKTRACE ||
DBMS_UTILITY.FORMAT_ERROR_STACK ||
DBMS_UTILITY.FORMAT_CALL_STACK);
END Get_Data;
END test_pkg;
答案 1 :(得分:0)
您应该创建一个函数然后使用它,请考虑以下代码:
CREATE OR REPLACE FUNCTION commalist (par_id NUMBER) RETURN VARCHAR2 IS
TYPE curs IS REF CURSOR;
v_emp_cursor curs;
fieldvalue VARCHAR2(4000);
var_out VARCHAR2(4000);
CURSOR col IS
SELECT column_name
FROM user_tab_columns
WHERE table_name = 'TABLE';
BEGIN
FOR reccol IN col LOOP
OPEN v_emp_cursor FOR ('SELECT '||reccol.column_name||' val
FROM TABLE
WHERE id = '||par_id);
LOOP
FETCH v_emp_cursor INTO fieldvalue;
IF fieldvalue IS NOT NULL THEN
var_out := var_out||fieldvalue||', ';
END IF;
EXIT WHEN v_emp_cursor%NOTFOUND;
END LOOP;
CLOSE v_emp_cursor;
END LOOP;
RETURN SubStr(var_out, 0, Length(var_out) - 2);
END;
答案 2 :(得分:0)
试试这个
with src as (select 1 ID, 'Billy' name, 0 Football, 'sam smith' WhoCreated, sysTimestamp when,
1 Baseball, cast(null as number) Cheerleading, 1 Swimming
from dual
union all
select 2, 'Susie', 1, 'sam smith', sysTimestamp, null, 1, 1
from dual
union all
select 3, 'Johnny', 1, 'Homer', sysTimestamp, 1, null, null
from dual),
unpivottbl as (select *
from src
UNPIVOT
(
VAL
FOR descript
IN (Football, Baseball, Cheerleading, Swimming)
))
select ID, name, descript
from unpivottbl
where VAL = 1
虽然它不是动态解决方案,但您需要添加要为其取消数据的列。这是unpivot的参考。