Oracle行转列函数PRINT_TABLE的用法

简介: Oracle行转列函数PRINT_TABLE的用法

简介

在sqlplus,如果列比较多,往往会显示不够清晰,这时如果能把查询语句行转列就明了多了,可以用print_table存储过程实现。

存储过程PRINT_TABLE源码

CREATE OR REPLACE PROCEDURE PRINT_TABLE(P_QUERY    IN VARCHAR2,
                                        P_DATE_FMT IN VARCHAR2 DEFAULT 'YYYY-MM-DD HH24:MI:SS')
-- THIS UTILITY IS DESIGNED TO BE INSTALLED ONCE IN A DATABASE AND USED
  -- BY ALL.  ALSO, IT IS NICE TO HAVE ROLES ENABLED SO THAT QUERIES BY
  -- DBA'S THAT USE A ROLE TO GAIN ACCESS TO THE DBA_* VIEWS STILL WORK
  -- THAT IS THE PURPOSE OF AUTHID CURRENT_USER
AUTHID CURRENT_USER IS
  L_THECURSOR   INTEGER DEFAULT DBMS_SQL.OPEN_CURSOR;
  L_COLUMNVALUE VARCHAR2(4000);
  L_STATUS      INTEGER;
  L_DESCTBL     DBMS_SQL.DESC_TAB;
  L_COLCNT      NUMBER;
  L_CS          VARCHAR2(255);
  L_DATE_FMT    VARCHAR2(255);
  l_rowCnt      NUMBER := 1;
 
  -- SMALL INLINE PROCEDURE TO RESTORE THE SESSIONS STATE
  -- WE MAY HAVE MODIFIED THE CURSOR SHARING AND NLS DATE FORMAT
  -- SESSION VARIABLES, THIS JUST RESTORES THEM
  PROCEDURE RESTORE IS
  BEGIN
    IF (UPPER(L_CS) NOT IN ('FORCE', 'SIMILAR')) THEN
      EXECUTE IMMEDIATE 'ALTER SESSION SET CURSOR_SHARING=EXACT';
    END IF;
  
    IF (P_DATE_FMT IS NOT NULL) THEN
      EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT=''' ||
                        L_DATE_FMT || '''';
    END IF;
  
    DBMS_SQL.CLOSE_CURSOR(L_THECURSOR);
  END RESTORE;
BEGIN
  -- I LIKE TO SEE THE DATES PRINT OUT WITH TIMES, BY DEFAULT, THE
  -- FORMAT MASK I USE INCLUDES THAT.  IN ORDER TO BE "FRIENDLY"
  -- WE SAVE THE DATE CURRENT SESSIONS DATE FORMAT AND THEN USE
  -- THE ONE WITH THE DATE AND TIME.  PASSING IN NULL WILL CAUSE
  -- THIS ROUTINE JUST TO USE THE CURRENT DATE FORMAT
  IF (P_DATE_FMT IS NOT NULL) THEN
    SELECT SYS_CONTEXT('USERENV', 'NLS_DATE_FORMAT')
      INTO L_DATE_FMT
      FROM DUAL;
  
    EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_DATE_FORMAT=''' || P_DATE_FMT || '''';
  END IF;
 
  -- TO BE BIND VARIABLE FRIENDLY ON THIS AD-HOC QUERIES, WE
  -- LOOK TO SEE IF CURSOR SHARING IS ALREADY SET TO FORCE OR
  -- SIMILAR, IF NOT, SET IT SO WHEN WE PARSE -- LITERALS
  -- ARE REPLACED WITH BINDS
  IF (DBMS_UTILITY.GET_PARAMETER_VALUE('CURSOR_SHARING', L_STATUS, L_CS) = 1) THEN
    IF (UPPER(L_CS) NOT IN ('FORCE', 'SIMILAR')) THEN
      EXECUTE IMMEDIATE 'ALTER SESSION SET CURSOR_SHARING=FORCE';
    END IF;
  END IF;
 
  -- PARSE AND DESCRIBE THE QUERY SENT TO US.  WE NEED
  -- TO KNOW THE NUMBER OF COLUMNS AND THEIR NAMES.
  DBMS_SQL.PARSE(L_THECURSOR, P_QUERY, DBMS_SQL.NATIVE);
  DBMS_SQL.DESCRIBE_COLUMNS(L_THECURSOR, L_COLCNT, L_DESCTBL);
 
  -- DEFINE ALL COLUMNS TO BE CAST TO VARCHAR2'S, WE
  -- ARE JUST PRINTING THEM OUT
  FOR I IN 1 .. L_COLCNT LOOP
    IF (L_DESCTBL(I).COL_TYPE NOT IN (113)) THEN
      DBMS_SQL.DEFINE_COLUMN(L_THECURSOR, I, L_COLUMNVALUE, 4000);
    END IF;
  END LOOP;
 
  -- EXECUTE THE QUERY, SO WE CAN FETCH
  L_STATUS := DBMS_SQL.EXECUTE(L_THECURSOR);
 
  -- LOOP AND PRINT OUT EACH COLUMN ON A SEPARATE LINE
  -- BEAR IN MIND THAT DBMS_OUTPUT ONLY PRINTS 255 CHARACTERS/LINE
  -- SO WE'LL ONLY SEE THE FIRST 200 CHARACTERS BY MY DESIGN...
  WHILE (DBMS_SQL.FETCH_ROWS(L_THECURSOR) > 0) LOOP
    FOR I IN 1 .. L_COLCNT LOOP
      IF (L_DESCTBL(I).COL_TYPE NOT IN (113)) THEN
        DBMS_SQL.COLUMN_VALUE(L_THECURSOR, I, L_COLUMNVALUE);
        DBMS_OUTPUT.PUT_LINE(RPAD(L_DESCTBL(I).COL_NAME, 30) || ': ' ||
                             SUBSTR(L_COLUMNVALUE, 1, 200));
      END IF;
    END LOOP;
  
      dbms_output.put_line('[Row:' || l_rowCnt ||']--------------------------------------------------------------------------------------------');
      l_rowCnt := l_rowCnt + 1;

  END LOOP;
 
  -- NOW, RESTORE THE SESSION STATE, NO MATTER WHAT
  RESTORE;
EXCEPTION
  WHEN OTHERS THEN
    RESTORE;
    RAISE;
END;
/

PRINT_TABLE用法

set serveroutput on size 1000000
set line 1000
exec print_table('select * from v$database');
exec print_table('select * from dba_users where rownum<=2');

-- 含单引号时:select * from dba_users where USERNAME='SYSTEM';
exec print_table(Q'[ select * from dba_users where USERNAME='SYSTEM'  ]');
exec print_table( 'select * from dba_users where USERNAME=''SYSTEM'' ');
含单引号时,可以使用Q语法,或者多一层引号也可以。

有关Oracle的Q语法请参考:https://www.xmmup.com/zaioraclezhongshenmeshiquoteq-qyufa.html

PRINT_TABLE示例

SQL> set serveroutput on size 1000000
SQL> set line 1000
SQL> exec print_table('select * from v$database');
DBID                          : 1865761973
NAME                          : EAS
CREATED                       : 2018-01-08 07:34:13
RESETLOGS_CHANGE#             : 11901181731
RESETLOGS_TIME                : 2021-09-22 20:27:42
PRIOR_RESETLOGS_CHANGE#       : 925702
PRIOR_RESETLOGS_TIME          : 2018-01-08 07:34:15
LOG_MODE                      : ARCHIVELOG
CHECKPOINT_CHANGE#            : 16240830676
ARCHIVE_CHANGE#               : 16237756205
CONTROLFILE_TYPE              : CURRENT
CONTROLFILE_CREATED           : 2018-01-08 07:34:13
CONTROLFILE_SEQUENCE#         : 4618967
CONTROLFILE_CHANGE#           : 16242584575
CONTROLFILE_TIME              : 2022-12-05 21:45:57
OPEN_RESETLOGS                : NOT ALLOWED
VERSION_TIME                  : 2021-09-21 16:33:02
OPEN_MODE                     : READ WRITE
PROTECTION_MODE               : MAXIMUM PERFORMANCE
PROTECTION_LEVEL              : MAXIMUM PERFORMANCE
REMOTE_ARCHIVE                : ENABLED
ACTIVATION#                   : 1984818535
SWITCHOVER#                   : 1984818535
DATABASE_ROLE                 : PRIMARY
ARCHIVELOG_CHANGE#            : 16240830676
ARCHIVELOG_COMPRESSION        : DISABLED
SWITCHOVER_STATUS             : NOT ALLOWED
DATAGUARD_BROKER              : DISABLED
GUARD_STATUS                  : NONE
SUPPLEMENTAL_LOG_DATA_MIN     : NO
SUPPLEMENTAL_LOG_DATA_PK      : NO
SUPPLEMENTAL_LOG_DATA_UI      : NO
FORCE_LOGGING                 : YES
PLATFORM_ID                   : 13
PLATFORM_NAME                 : Linux x86 64-bit
RECOVERY_TARGET_INCARNATION#  : 4
LAST_OPEN_INCARNATION#        : 4
CURRENT_SCN                   : 16242584726
FLASHBACK_ON                  : NO
SUPPLEMENTAL_LOG_DATA_FK      : NO
SUPPLEMENTAL_LOG_DATA_ALL     : NO
DB_UNIQUE_NAME                : eas
STANDBY_BECAME_PRIMARY_SCN    : 0
FS_FAILOVER_STATUS            : DISABLED
FS_FAILOVER_CURRENT_TARGET    :
FS_FAILOVER_THRESHOLD         : 0
FS_FAILOVER_OBSERVER_PRESENT  :
FS_FAILOVER_OBSERVER_HOST     :
CONTROLFILE_CONVERTED         : NO
PRIMARY_DB_UNIQUE_NAME        :
SUPPLEMENTAL_LOG_DATA_PL      : NO
MIN_REQUIRED_CAPTURE_CHANGE#  :
[Row:1]--------------------------------------------------------------------------------------------

PL/SQL procedure successfully completed.

SQL> 
SQL> exec print_table('select * from dba_users where rownum<=2');
USERNAME                      : SYS
USER_ID                       : 0
PASSWORD                      :
ACCOUNT_STATUS                : OPEN
LOCK_DATE                     :
EXPIRY_DATE                   :
DEFAULT_TABLESPACE            : SYSTEM
TEMPORARY_TABLESPACE          : TEMP
CREATED                       : 2013-08-24 11:37:40
PROFILE                       : DEFAULT
INITIAL_RSRC_CONSUMER_GROUP   : SYS_GROUP
EXTERNAL_NAME                 :
PASSWORD_VERSIONS             : 10G 11G
EDITIONS_ENABLED              : N
AUTHENTICATION_TYPE           : PASSWORD
[Row:1]--------------------------------------------------------------------------------------------
USERNAME                      : SYSTEM
USER_ID                       : 5
PASSWORD                      :
ACCOUNT_STATUS                : EXPIRED
LOCK_DATE                     :
EXPIRY_DATE                   : 2020-12-07 02:00:02
DEFAULT_TABLESPACE            : SYSTEM
TEMPORARY_TABLESPACE          : TEMP
CREATED                       : 2013-08-24 11:37:40
PROFILE                       : DEFAULT
INITIAL_RSRC_CONSUMER_GROUP   : SYS_GROUP
EXTERNAL_NAME                 :
PASSWORD_VERSIONS             : 10G 11G
EDITIONS_ENABLED              : N
AUTHENTICATION_TYPE           : PASSWORD
[Row:2]--------------------------------------------------------------------------------------------

PL/SQL procedure successfully completed.

SQL> 
SQL> exec print_table(Q'[ select * from dba_users where USERNAME='SYSTEM'  ]');
USERNAME                      : SYSTEM
USER_ID                       : 5
PASSWORD                      :
ACCOUNT_STATUS                : EXPIRED
LOCK_DATE                     :
EXPIRY_DATE                   : 2020-12-07 02:00:02
DEFAULT_TABLESPACE            : SYSTEM
TEMPORARY_TABLESPACE          : TEMP
CREATED                       : 2013-08-24 11:37:40
PROFILE                       : DEFAULT
INITIAL_RSRC_CONSUMER_GROUP   : SYS_GROUP
EXTERNAL_NAME                 :
PASSWORD_VERSIONS             : 10G 11G
EDITIONS_ENABLED              : N
AUTHENTICATION_TYPE           : PASSWORD
[Row:1]--------------------------------------------------------------------------------------------

PL/SQL procedure successfully completed.

SQL> 
SQL> exec print_table( 'select * from dba_users where USERNAME=''SYSTEM'' ');
USERNAME                      : SYSTEM
USER_ID                       : 5
PASSWORD                      :
ACCOUNT_STATUS                : EXPIRED
LOCK_DATE                     :
EXPIRY_DATE                   : 2020-12-07 02:00:02
DEFAULT_TABLESPACE            : SYSTEM
TEMPORARY_TABLESPACE          : TEMP
CREATED                       : 2013-08-24 11:37:40
PROFILE                       : DEFAULT
INITIAL_RSRC_CONSUMER_GROUP   : SYS_GROUP
EXTERNAL_NAME                 :
PASSWORD_VERSIONS             : 10G 11G
EDITIONS_ENABLED              : N
AUTHENTICATION_TYPE           : PASSWORD
[Row:1]--------------------------------------------------------------------------------------------

PL/SQL procedure successfully completed.

SQL> 
目录
相关文章
|
7月前
|
Oracle 关系型数据库 数据库
Oracle中merge Into的用法
Oracle中merge Into的用法
|
1月前
|
SQL Oracle 关系型数据库
[Oracle]面试官:你举例几个内置函数,并且说说如何使用内置函数作正则匹配
本文介绍了多种SQL内置函数,包括单行函数、非空判断函数、日期函数和正则表达式相关函数。每种函数都有详细的参数说明和使用示例,帮助读者更好地理解和应用这些函数。文章强调了字符串操作、数值处理、日期计算和正则表达式的使用方法,并提供了丰富的示例代码。作者建议读者通过自测来巩固学习成果。
26 1
[Oracle]面试官:你举例几个内置函数,并且说说如何使用内置函数作正则匹配
|
5月前
|
SQL Oracle 算法
|
2月前
|
SQL 存储 Oracle
Oracle用法
【10月更文挑战第15天】Oracle用法
44 5
|
7月前
|
SQL 存储 Oracle
一篇文章带你学会 Oracle 存储过程的基本介绍和高阶用法(上)
一篇文章带你学会 Oracle 存储过程的基本介绍和高阶用法
|
5月前
|
SQL Oracle 关系型数据库
|
5月前
|
SQL Oracle 关系型数据库
Oracle|内置函数之INSTR
【7月更文挑战第5天】
|
5月前
|
Oracle 关系型数据库 数据挖掘
|
5月前
|
Oracle 关系型数据库 Java
Oracle数据库导入工具IMP详解与用法
Oracle数据库导入工具IMP详解与用法
|
5月前
|
Oracle 关系型数据库 数据挖掘

相关课程

更多

推荐镜像

更多