2015-04-23 157 views
0

我在這個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 
+0

你如何定義列的順序;從EDITS值的varchar2排序順序?通過快速測試,我可以按照該順序獲得列。你能否添加表格和數據設置來重新創建問題? –

+0

訂單是使用一列來定義的,其中每個編輯都有其預定義的順序(我沒有使用編輯的值)。只是用select查詢更新了我的問題。 – RidRoid

+0

我的意思是你爲什麼認爲你得到的訂單是錯誤的。「EDIT」的實際值是什麼 - 你在問題中表現出的更多變化的不同情況?我不認爲你會得到那些確切的樞軸標題,除非你通過'p_fmt'參數,這讓我認爲你已經編輯了值 - 可能隱藏了問題... –

回答

0

我用這同一個支點和遇到同樣的問題。您提到的動態數據透視表按字母順序排列了旋轉的列。在哈克解決方法,我發現是使用一個case語句添加字符,如

SELECT 
        ID_DEMAND 
        , NAME 
        , CASE 
        WHEN EDIT < 'EDIT2' THEN ' EDIT2' 
        WHEN EDIT > 'EDIT4' THEN '_EDIT4' 
        ELSE EDIT 
        END AS EDIT, 
        , ORDER_EDIT 
        , MIN (DATE_ACTION) as EDIT_START 

這種缺乏成熟和風格,但能夠完成任務 東西。

+0

問題是我的編輯沒有預定義的值(名稱可能有所不同,可以從專用表中更改),因此我無法進行比較:/ – RidRoid

+0

@RidRoid - 那麼您如何知道您的訂單想讓他們進來?是在專用表中定義的,例如序列/優先級列,您可以加入並在案例中使用? –

+0

@AlexPoole在我最初的'select'query中有'ORDER BY ID_DEMAND,ORDER_EDIT',但是一旦我將查詢作爲參數傳遞給訂單就會丟失。 – RidRoid

0

您正在使用的函數將忽略您使用order by子句設置的值的順序,並根據默認的第二個參數將旋轉列名稱及其順序作爲結果集中排序後的值的基礎pivot保留爲upper(@p),稍後將其翻譯爲upper(EDIT)。似乎沒有一種簡單的方法可以得到您想要的結果,因爲該排序必須基於倒數第二個EDIT字段 - 可以將其保留爲小寫字母或以某種其他方式進行操作,但不是以某種方式執行你要。

您可以修改的實施要求和消費的增加排序列,有效地將pivot函數定義爲:

create or replace 
function pivot(p_stmt in varchar2, 
    p_fmt in varchar2 := 'upper(@[email protected])', 
    p_ord in varchar2 := '@[email protected]', -- added 
    dummy in number := 0) 
return anydataset pipelined using PivotImpl; 
/

這有一個額外的排序佔位符,我已經在精神上默認爲'@[email protected]'現有的,並可能會允許一些操縱。這必須反映在所有PivotImpl函數聲明中,然後必須用於提取列值並決定其排序的遊標。我已經做了如下:

open rc for replace(replace('select ' || t_fmt || ' 
         from(' || p_stmt || ') 
         group by ' || t_fmt || ' 
         order by min(' || t_ord || ')' 
        , '@[email protected]' 
        , desc_tab(numcols - 1).col_name 
        ) 
        , '@[email protected]' 
        , desc_tab(numcols - 2).col_name 
        ); 

這意味着你的ORDER_EDIT值必須包括在選擇列表中,並且必須在列位置EDIT與我已經修改了列號的處理方式之前, ;但也意味着您現有的order by條款是多餘的。

有一些很簡單的虛擬數據設置:

create table job (id_job number, name varchar2(10)); 
create table demand (id_demand number, id_job number); 
create table log (id_demand number, edit varchar2(4), 
    order_edit number, date_action date); 

insert into job values (42, 'Name'); 
insert into demand values (1601, 42); 
insert into log values (1601, 'EdtC', 1, sysdate); 
insert into log values (1601, 'EdtA', 2, sysdate); 
insert into log values (1601, 'EdtB', 3, sysdate); 

你內心的查詢獲取:

ID_DEMAND NAME  EDIT  TOTAL 
---------- ---------- ---- ---------- 
     1601 Name  EdtC   0 
     1601 Name  EdtA   0 
     1601 Name  EdtB   

原來執行得:

ID_DEMAND NAME    EDTA  EDTB  EDTC 
---------- ---------- ---------- ---------- ---------- 
     1601 Name    0      0 

並調用這個修改實施:

Select * from table (PIVOT('SELECT ID_DEMAND 
     , NAME 
     , ORDER_EDIT 
     , 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) 
      WHERE ID_DEMAND = 1601')); 

...與包括在選擇列表ORDER_EDIT,所以結果現在設置的樣子:

ID_DEMAND NAME  ORDER_EDIT EDIT  TOTAL 
---------- ---------- ---------- ---- ---------- 
     1601 Name    1 EdtC   0 
     1601 Name    2 EdtA   0 
     1601 Name    3 EdtB   

修改後的函數調用獲得:

ID_DEMAND NAME    EDTC  EDTA  EDTB 
---------- ---------- ---------- ---------- ---------- 
     1601 Name    0   0   

其中在具有樞轉列由您的國旗指定的順序,這是我認爲您想實現的目標。


這是整個修改後的實現,對於SQL Fiddle來說這太大了。我已經打上我已經-- added-- changed意見改變了位:

CREATE OR REPLACE 
type PivotImpl as object 
(
    ret_type anytype,  -- The return type of the table function 
    stmt varchar2(32767), 

    fmt varchar2(32767), 
    ord varchar2(32767), -- added 
    cur integer, 
    static function ODCITableDescribe(rtype out anytype, 
    p_stmt in varchar2, 
    p_fmt in varchar2 := 'upper(@[email protected])', 
    p_ord in varchar2 := '@[email protected]', -- added 
    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])', 
    p_ord in varchar2 := '@[email protected]', -- added 
    dummy in number := 0) 
    return number, 
    static function ODCITableStart(sctx in out PivotImpl, 
    p_stmt in varchar2, 
    p_fmt in varchar2 := 'upper(@[email protected])', 
    p_ord in varchar2 := '@[email protected]', -- added 
    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])', 
    p_ord in varchar2 := '@[email protected]', -- added 
    dummy in number) 
    return number 
    is 
    atyp anytype; 
    cur integer; 
    numcols number; 
    desc_tab dbms_sql.desc_tab2; 
    rc sys_refcursor; 
    t_c2 varchar2(32767); 
    t_fmt varchar2(1000); 
    t_ord varchar2(1000); -- added 
    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 - 3 -- changed 
    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; 
    -- added, but not really implemented 
    if instr(p_ord, '@[email protected]') > 0 
    then 
     t_ord := p_ord; 
    else 
     t_ord := '@[email protected]'; 
    end if; 
    -- changed cursor/replace to handle ordering 
    open rc for replace(replace('select ' || t_fmt || ' 
          from(' || p_stmt || ') 
          group by ' || t_fmt || ' 
          order by min(' || t_ord || ')' 
         , '@[email protected]' 
         , desc_tab(numcols - 1).col_name 
         ) 
         , '@[email protected]' 
         , desc_tab(numcols - 2).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])', 
    p_ord in varchar2 := '@[email protected]', -- added 
    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, p_ord, null); -- changed 
    else 
     sctx := PivotImpl(elem_typ, p_stmt, '@[email protected]', '@[email protected]', null); -- changed 
    end if; 
    return odciconst.success; 
    end; 
-- 
    static function ODCITableStart(sctx in out PivotImpl, 
    p_stmt in varchar2, 
    p_fmt in varchar2 := 'upper(@[email protected])', 
    p_ord in varchar2 := '@[email protected]', -- added 
    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 - 3 -- changed 
    loop 
     t_stmt := t_stmt || ', "' || desc_tab(i).col_name || '"'; 
    end loop; 
-- 
dbms_output.put_line(t_stmt); 
    type_code := sctx.ret_type.getinfo(prec 
             , scale 
             , len 
             , csid 
             , csfrm 
             , schema_name 
             , type_name 
             , version 
             , attr_count 
            ); 
    for i in numcols - 2 .. attr_count -- changed 
    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 - 3 -- changed 
    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; 
-- 
    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])', 
    p_ord in varchar2 := '@[email protected]', -- added 
    dummy in number := 0) 
return anydataset pipelined using PivotImpl; 
/
0

作爲替代代碼修改,如果你不關心列名...

ROWNUM會給數我相信和原來的訂單一樣。

由於文本排序,ROWNUM不能自行排序。

IE: 1,10,11,12,2,20,21,22

如果你不關心的列名,然後

0允許前綴或填充數字「正常」排序行爲。

IE 001,002,003,004,005,006,007

001 COL名稱1002山口名稱2,003山口名稱3

如果級聯來保持一定程度的原始列名

注: to_number看起來不起作用,因爲我相信在內部,這會得到按摩迴文本。