我在這個article中發現了這個驚人的功能。該功能將在一列一組值入列標題:用於動態sql的Oracle功能
CREATE OR REPLACE
type PivotImpl as object
(
ret_type anytype, -- The return type of the table function
stmt varchar2(32767),
fmt varchar2(32767),
cur integer,
static function ODCITableDescribe(rtype out anytype, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@[email protected])', dummy in number := 0)
return number,
static function ODCITablePrepare(sctx out PivotImpl, ti in sys.ODCITabFuncInfo, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@[email protected])', dummy in number := 0)
return number,
static function ODCITableStart(sctx in out PivotImpl, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@[email protected])', dummy in number := 0)
return number,
member function ODCITableFetch(self in out PivotImpl, nrows in number, outset out anydataset)
return number,
member function ODCITableClose(self in PivotImpl)
return number
)
/
create or replace type body PivotImpl as
static function ODCITableDescribe(rtype out anytype, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@[email protected])', dummy in number)
return number
is
atyp anytype;
cur integer;
numcols number;
desc_tab dbms_sql.desc_tab2;
rc s
ys_refcursor;
t_c2 varchar2(32767);
t_fmt varchar2(1000);
begin
cur := dbms_sql.open_cursor;
dbms_sql.parse(cur, p_stmt, dbms_sql.native);
dbms_sql.describe_columns2(cur, numcols, desc_tab);
dbms_sql.close_cursor(cur);
--
anytype.begincreate(dbms_types.typecode_object, atyp);
for i in 1 .. numcols - 2
loop
atyp.addattr(desc_tab(i).col_name
, case desc_tab(i).col_type
when 1 then dbms_types.typecode_varchar2
when 2 then dbms_types.typecode_number
when 9 then dbms_types.typecode_varchar2
when 11 then dbms_types.typecode_varchar2 -- show rowid as varchar2
when 12 then dbms_types.typecode_date
when 208 then dbms_types.typecode_varchar2 -- show urowid as varchar2
when 96 then dbms_types.typecode_char
when 180 then dbms_types.typecode_timestamp
when 181 then dbms_types.typecode_timestamp_tz
when 231 then dbms_types.typecode_timestamp_ltz
when 182 then dbms_types.typecode_interval_ym
when 183 then dbms_types.typecode_interval_ds
end
, desc_tab(i).col_precision
, desc_tab(i).col_scale
, case desc_tab(i).col_type
when 11 then 18 -- for rowid col_max_len = 16, and 18 characters are shown
else desc_tab(i).col_max_len
end
, desc_tab(i).col_charsetid
, desc_tab(i).col_charsetform
);
end loop;
if instr(p_fmt, '@[email protected]') > 0
then
t_fmt := p_fmt;
else
t_fmt := '@[email protected]';
end if;
open rc for replace('select distinct ' || t_fmt || '
from(' || p_stmt || ')
order by ' || t_fmt
, '@[email protected]'
, desc_tab(numcols - 1).col_name
);
loop
fetch rc into t_c2;
exit when rc%notfound;
atyp.addattr(t_c2
, case desc_tab(numcols).col_type
when 1 then dbms_types.typecode_varchar2
when 2 then dbms_types.typecode_number
when 9 then dbms_types.typecode_varchar2
when 11 then dbms_types.typecode_varchar2 -- show rowid as varchar2
when 12 then dbms_types.typecode_date
when 208 then dbms_types.typecode_urowid
when 96 then dbms_types.typecode_char
when 180 then dbms_types.typecode_timestamp
when 181 then dbms_types.typecode_timestamp_tz
when 231 then dbms_types.typecode_timestamp_ltz
when 182 then dbms_types.typecode_interval_ym
when 183 then dbms_types.typecode_interval_ds
end
, desc_tab(numcols).col_precision
, desc_tab(numcols).col_scale
, case desc_tab(numcols).col_type
when 11 then 18 -- for rowid col_max_len = 16, and 18 characters are shown
else desc_tab(numcols).col_max_len
end
, desc_tab(numcols).col_charsetid
, desc_tab(numcols).col_charsetform
);
end loop;
close rc;
atyp.endcreate;
anytype.begincreate(dbms_types.typecode_table, rtype);
rtype.SetInfo(null, null, null, null, null, atyp, dbms_types.typecode_object, 0);
rtype.endcreate();
return odciconst.success;
exception
when others then
return odciconst.error;
end;
--
static function ODCITablePrepare(sctx out PivotImpl, ti in sys.ODCITabFuncInfo, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@[email protected])', dummy in number)
return number
is
prec pls_integer;
scale pls_integer;
len pls_integer;
csid pls_integer;
csfrm pls_integer;
elem_typ anytype;
aname varchar2(30);
tc pls_integer;
begin
tc := ti.RetType.GetAttrElemInfo(1, prec, scale, len, csid, csfrm, elem_typ, aname);
--
if instr(p_fmt, '@[email protected]') > 0
then
sctx := PivotImpl(elem_typ, p_stmt, p_fmt, null);
else
sctx := PivotImpl(elem_typ, p_stmt, '@[email protected]', null);
end if;
return odciconst.success;
end;
--
static function ODCITableStart(sctx in out PivotImpl, p_stmt in varchar2, p_fmt in varchar2 := 'upper(@[email protected])', dummy in number)
return number
is
cur integer;
numcols number;
desc_tab dbms_sql.desc_tab2;
t_stmt varchar2(32767);
type_code pls_integer;
prec pls_integer;
scale pls_integer;
len pls_integer;
csid pls_integer;
csfrm pls_integer;
schema_name varchar2(30);
type_name varchar2(30);
version varchar2(30);
attr_count pls_integer;
attr_type anytype;
attr_name varchar2(100);
dummy2 integer;
begin
cur := dbms_sql.open_cursor;
dbms_sql.parse(cur, p_stmt, dbms_sql.native);
dbms_sql.describe_columns2(cur, numcols, desc_tab);
dbms_sql.close_cursor(cur);
--
for i in 1 .. numcols - 2
loop
t_stmt := t_stmt || ', "' || desc_tab(i).col_name || '"';
end loop;
--
type_code := sctx.ret_type.getinfo(prec
, scale
, len
, csid
, csfrm
, schema_name
, type_name
, version
, attr_count
);
for i in numcols - 1 .. attr_count
loop
type_code := sctx.ret_type.getattreleminfo(i
, prec
, scale
, len
, csid
, csfrm
, attr_type
, attr_name
);
t_stmt := t_stmt || replace(', max(decode(' || sctx.fmt || ', ''' || attr_name || ''', ' || desc_tab(numcols).col_name || '))'
, '@[email protected]'
, desc_tab(numcols - 1).col_name
);
end loop;
t_stmt := 'select ' || substr(t_stmt, 2) || ' from (' || sctx.stmt || ')';
for i in 1 .. numcols - 2
loop
if i = 1
then
t_stmt := t_stmt || ' group by "' || desc_tab(i).col_name || '"';
else
t_stmt := t_stmt || ', "' || desc_tab(i).col_name || '"';
end if;
end loop;
--
dbms_output.put_line(t_stmt);
sctx.cur := dbms_sql.open_cursor;
dbms_sql.parse(sctx.cur, t_stmt, dbms_sql.native);
for i in 1 .. attr_count
loop
type_code := sctx.ret_type.getattreleminfo(i
, prec
, scale
, len
, csid
, csfrm
, attr_type
, attr_name
);
case type_code
when dbms_types.typecode_char then dbms_sql.define_column(sctx.cur, i, 'x', 32767);
when dbms_types.typecode_varchar2 then dbms_sql.define_column(sctx.cur, i, 'x', 32767);
when dbms_types.typecode_number then dbms_sql.define_column(sctx.cur, i, cast(null as number));
when dbms_types.typecode_date then dbms_sql.define_column(sctx.cur, i, cast(null as date));
when dbms_types.typecode_urowid then dbms_sql.define_column(sctx.cur, i, cast(null as urowid));
when dbms_types.typecode_timestamp then dbms_sql.define_column(sctx.cur, i, cast(null as timestamp));
when dbms_types.typecode_timestamp_tz then dbms_sql.define_column(sctx.cur, i, cast(null as timestamp with time zone));
when dbms_types.typecode_timestamp_ltz then dbms_sql.define_column(sctx.cur, i, cast(null as timestamp with local time zone));
when dbms_types.typecode_interval_ym then dbms_sql.define_column(sctx.cur, i, cast(null as interval year to month));
when dbms_types.typecode_interval_ds then dbms_sql.define_column(sctx.cur, i, cast(null as interval day to second));
end case;
end loop;
dummy2 := dbms_sql.execute(sctx.cur);
return odciconst.success;
end;
--
member function ODCITableFetch(self in out PivotImpl, nrows in number, outset out anydataset)
return number
is
c1_col_type pls_integer;
type_code pls_integer;
prec pls_integer;
scale pls_integer;
len pls_integer;
csid pls_integer;
csfrm pls_integer;
schema_name varchar2(30);
type_name varchar2(30);
version varchar2(30);
attr_count pls_integer;
attr_type anytype;
attr_name varchar2(100);
v1 varchar2(32767);
n1 number;
d1 date;
ur1 urowid;
ids1 interval day to second;
iym1 interval year to month;
ts1 timestamp;
tstz1 timestamp with time zone;
tsltz1 timestamp with local time zone;
begin
outset := null;
if nrows < 1
then
-- is this possible???
return odciconst.success;
end if;
--
dbms_output.put_line('fetch');
if dbms_sql.fetch_rows(self.cur) = 0
then
return odciconst.success;
end if;
--
dbms_output.put_line('done');
type_code := self.ret_type.getinfo(prec
, scale
, len
, csid
, csfrm
, schema_name
, type_name
, version
, attr_count
);
anydataset.begincreate(dbms_types.typecode_object, self.ret_type, outset);
outset.addinstance;
outset.piecewise();
for i in 1 .. attr_count
loop
type_code := self.ret_type.getattreleminfo(i
, prec
, scale
, len
, csid
, csfrm
, attr_type
, attr_name
);
dbms_output.put_line(attr_name);
case type_code
when dbms_types.typecode_char then
dbms_sql.column_value(self.cur, i, v1);
outset.setchar(v1);
when dbms_types.typecode_varchar2 then
dbms_sql.column_value(self.cur, i, v1);
outset.setvarchar2(v1);
when dbms_types.typecode_number then
dbms_sql.column_value(self.cur, i, n1);
outset.setnumber(n1);
when dbms_types.typecode_date then
dbms_sql.column_value(self.cur, i, d1);
outset.setdate(d1);
when dbms_types.typecode_urowid then
dbms_sql.column_value(self.cur, i, ur1);
outset.seturowid(ur1);
when dbms_types.typecode_interval_ds then
dbms_sql.column_value(self.cur, i, ids1);
outset.setintervalds(ids1);
when dbms_types.typecode_interval_ym then
dbms_sql.column_value(self.cur, i, iym1);
outset.setintervalym(iym1);
when dbms_types.typecode_timestamp then
dbms_sql.column_value(self.cur, i, ts1);
outset.settimestamp(ts1);
when dbms_types.typecode_timestamp_tz then
dbms_sql.column_value(self.cur, i, tstz1);
outset.settimestamptz(tstz1);
when dbms_types.typecode_timestamp_ltz then
dbms_sql.column_value(self.cur, i, tsltz1);
outset.settimestampltz(tsltz1);
end case;
end loop;
outset.endcreate;
return odciconst.success;
end;
--
member function ODCITableClose(self in PivotImpl)
return number
is
c integer;
begin
c := self.cur;
dbms_sql.close_cursor(c);
return odciconst.success;
end;
end;
/
create or replace
function pivot(p_stmt in varchar2, p_fmt in varchar2 := 'upper(@[email protected])', dummy in number := 0)
return anydataset pipelined using PivotImpl;
/
不幸的是,該函數不排序的列:我的選擇查詢的結果是:
ID NAME EDITS DAYS
1 Example Edt1 10
1 Example Edt2 5
1 Example Edt3 3
當我用的是pivot
功能我失去了秩序:
Select * from table (PIVOT('My select query'));
ID NAME Edt2 Edt1 Edt3
1 Example 5 10 3
能否請你幫我編輯此功能,以保持列的順序,因爲它是用的值最初的專欄?謝謝。
UPDATE:我的選擇查詢:
SELECT ID_DEMAND
, NAME
, EDIT
, LEAD (EDIT_START) OVER (PARTITION BY ID_DEMAND ORDER BY ORDER_EDIT) - EDIT_START AS TOTAL
FROM (
SELECT
ID_DEMAND
, NAME
, EDIT
, ORDER_EDIT
, MIN (DATE_ACTION) as EDIT_START
FROM
(SELECT
D.ID_DEMAND
, J.NAME
, L.DATE_ACTION
, L.EDIT
, L.ORDER_EDIT
FROM (DEMAND D LEFT JOIN LOG L ON D.ID_DEMAND = L.ID_DEMAND)
LEFT JOIN JOB J ON D.ID_JOB = J.ID_JOB)T
GROUP BY
ID_DEMAND
, NAME
, EDIT
, ORDER_EDIT)
JHERE ID_DEMAND = 1601
ORDER BY ID_DEMAND, ORDER_EDIT
你如何定義列的順序;從EDITS值的varchar2排序順序?通過快速測試,我可以按照該順序獲得列。你能否添加表格和數據設置來重新創建問題? –
訂單是使用一列來定義的,其中每個編輯都有其預定義的順序(我沒有使用編輯的值)。只是用select查詢更新了我的問題。 – RidRoid
我的意思是你爲什麼認爲你得到的訂單是錯誤的。「EDIT」的實際值是什麼 - 你在問題中表現出的更多變化的不同情況?我不認爲你會得到那些確切的樞軸標題,除非你通過'p_fmt'參數,這讓我認爲你已經編輯了值 - 可能隱藏了問題... –