1. 程式人生 > >oracle 11g及之前版本行轉列方法總結

oracle 11g及之前版本行轉列方法總結

oracle 資料處理過程中經常遇到資料行列轉換的需求,故現整理自己用的一些方法供大家參考

方法一:
使用自帶的轉換函式wmsys.wm_concat()
源資料如下

select t.rank, t.Name from t_menu_item t;

10 CLARK
10 KING
10 MILLER
20 ADAMS
20 FORD
20 JONES
20 SCOTT
20 SMITH
30 ALLEN
30 BLAKE
30 JAMES
30 MARTIN
30 TURNER
30 WARD

我們通過 10g 所提供的 WMSYS.WM_CONCAT 函式即可以完成 行轉列的效果

    select t.rank, WMSYS.WM_CONCAT(t.Name) TIME From t_menu_item t GROUP BY t.rank;  

DEPTNO ENAME
10 CLARK, KING, MILLER
20 ADAMS, FORD, JONES, SCOTT, SMITH
30 ALLEN, BLAKE, JAMES, MARTIN, TURNER, WARD

這種方法轉換得到的資料是以“,”分割的字串資料。

方法二:
自己構建轉換函式,實現行轉列。
函式程式碼如下:

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 sys_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; / -- 在外面包裝一層PLSQL函式: 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; / /************** eg. select * from table( pivot('select deptno , job , avg(sal) sal_avg from scott.emp group by deptno , job ') ); ***************/

轉換前資料
這裡寫圖片描述
呼叫pivot()函式後的資料展示結果
這裡寫圖片描述
這種方法的好處是轉換列自由,不用特殊指定。

方法三:
這種方法適用於資料量小並且列欄位固定的情況,就是使用decode和sum實現轉換,這種方法網上很多,也很簡單,就不詳細介紹。

相關推薦

oracle 11g之前版本方法總結

oracle 資料處理過程中經常遇到資料行列轉換的需求,故現整理自己用的一些方法供大家參考 方法一: 使用自帶的轉換函式wmsys.wm_concat() 源資料如下 select t.rank, t.Name from t_menu_item t;

Oracle 11g Pivot函式實現

先上語法規範: SELECT .... FROM PIVOT ( aggregate-function() FOR IN (, ,..., )

oracle 存儲過程-動態,解決。

pla gin sel rom con left join from blog creat 包頭 create or replace package pro_test as TYPE out_cursor IS REF CURSOR; procedure A

Oracle 技巧總結(一):

1.行轉列 oracle中行轉列 語法結構select listagg(column1, ',') within group(order by column2) from X;  如下圖所示: listagg(attr1, attr2):第一個引數是要行轉列的那個欄位

oracle 11g下的pivot填坑--xmlTypeclob或String

臨近年關,我們給全公司用的API平臺也到了要裝逼的時刻,然而裝逼利器還沒搞完,那就是報表呈現,於是leader說你來搞一下吧。 echarts肯定是要的,報表呈現還是很完美的。然後就是資料庫層面的了。我們裝的是oracle 11g,這貨提供了pivot來進行轉列,然而它是有坑的,本次記錄的就是這個。 pi

oracle轉行、連續日期數字實現方式mybatis下實現方式

九月份複習,十月份考試,十月底一直沒法收心,趕在十一初 由於不可抗拒的原因又不得不重新找工作就;欸~, 又是一番折騰,從入職到現在,可又沒法閒下來了... 這次就簡單介紹下oracle資料庫下如何實現行轉列、列轉行及此在mybatis中的實現方式,就具體用法我就不詳細說了,主要介紹下實戰中所碰到的坑

Oracle 11g使用Pivot函式實現資料聚合

經常使用資料庫,我們有很大的精力應付在處理各種各樣的資料型別,處理各種型別的報表。需要對資料進行行列轉換,Oracle 11G 提供了pivot函式,方便我們對資料進行行列轉換。 表設計如下: create table tongji( id number primary

oracle 11g 的問題 decode實現與pivot實現

oracle 11g 行轉列的問題舉一個簡單的例子,假設有表名為demo其中只有兩列一列為型別names,一列為數量nums。表中資料如下:目標統計出表中apple及orange各自的總數,在一列中顯示出來。常規寫法:select names,sum(nums) from d

Oracle

cat pre case nbsp 運用 分隔 nvl ase partition 一、簡易運用 ——>沒轉之前一個主號綁定多個副號的多行輸出(像移動的歡樂在線) SELECT f.town_name 鎮區, f.school_name 學校,

Oracle根據【日期】組,其他條件根據PIVOT。使每個日期條件關聯的其他數據只有一行。

col acl time pivot per clas 一行 crop group select OPER_TIME, MICROPAY, REFUND from ( select trunc(oper_time) oper_time,

除錯經驗——使用自定義函式在Oracle中實現類似LISTAGG函式的(字串連線)功能

問題描述: LISTAGG函式是一個很實用的函式,但僅在Oracle 11.2以後的版本中才有。 生產環境中有個資料庫是Oracle 11.1,需要行轉列,但並不能使用LISTAGG函式。 解決方法: 參考以下文章: https://oracle-base.com/artic

oracle資料錶

今天看到一個題目,要求是行轉列,回來查了一下資料 題目要求是把 這樣的一張錶轉換為 這樣的表格 首先建立表 CREATE TABLE A ( year VARCHAR2(255), month VARCHAR2(255), amount NUMBER ); 然後插入資料 INSE

oracle ,多

問題描述:    應公司要求,設計功能,一個ID,對應不同的值,展示的時候不同的值拼接展示,如何實現;   解決思路:     1) 拼接字串,想到了 oracle  Function(),這樣肯定能實現,但是比較麻煩;

表的: DECODE(Oracle) 和 CASE WHEN 的異同點

異同點 都可以對錶行轉列; DECODE功能上和簡單Case函式比較類似,不能像Case搜尋函式一樣,進行更復雜的判斷 在Case函式中,可以使用BETWEEN, LIKE, IS NULL, IN, EXISTS等等(也可以使用NOT IN和NOT EXISTS,但是這個時候要注意NULL的

oracle 11g以下的版本定義自增主鍵

11g及以下的版本定義自增主鍵(更高版本可以直接定義autoincreatement 的主鍵) CREATE TABLE collect ( ID NUMBER(10) PRIMARY KEY NOT NULL, mobile VARCHAR2(50),

Oracle pivot

行轉列語法為pivot(聚合函式 for 列名 in(型別)): pivot ( sum ( planqty ) for plantype in ( 'in', 'out' ) ) 1.建立測試表格 CREATE TABLE XXXMGR.FAB_BSFACTORYDAI

[面試][oracle] 資料庫 轉行詳解

[一]、行轉列 1.1、初始測試資料 表結構:TEST_TB_GRADE create table TEST_TB_GRADE    (      ID        NUMBER(10) notnull,      USER_NAME VARCHAR2

Oracle+排序

--1.刪除臨時表 drop table biz_bus_station_direct_0711; --2.將站點資料等放入臨時表 create table biz_bus_station_direct

Oracle pivot 、轉行unpivot 的Sql語句總結

多行轉字串 這個比較簡單,用||或concat函式可以實現 print? 1.  select concat(id,username) str from app_user   2.     3.  select id||username str from app_use

oracle 例子程式碼

select * from (select deptno,job,sal from emp) pivot(        sum(sal)        for job in (          'ANALYST' as analyst_sal,          'MA