如何在Oracle数据库内格式化SQL或PL/SQL ?

点击上方"蓝字"

关注我们,享更多干货!

在一些情况下,梳理复杂的SQL或PL/SQL代码逻辑时最好是格式化一下文本。

当然我们有Toad或PL/SQL Developer等其它第三方客户端程序作为辅助,但如果在数据库内容方面可以将SQL格式化则更佳。

当前数据库12c以后的软件安装介质中已经包含了Oracle/ SQLcl或Oracle SQL Developer,使用这两者任一自带工具中的JavaLib的dbtools-common.jar中的oracle.dbtools.app.Format函数就可以实现。

下面是实际安装步骤,环境为19.3

1、加载java

19.3中自带的发现无法使用:

[oracle@oel7db1 lib]$ loadjava -u anbob/anbob@cdb1pdb1 /u01/app/oracle/product/19.2.0/db_1/sqldeveloper/sqldeveloper/lib/dbtools-common.jar
[oracle@oel7db1 lib]$ sqlplus anbob/anbob@cdb1pdb1

创建3#的Java函数时会提示下面的错误:

Warning: Java created with compilation errors.

SSQL> show error
Errors for JAVA SOURCE "SQLFORMATTER":

LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0      Note: SQLFORMATTER uses or overrides a deprecated API.
0/0      ORA-29534: referenced object ANBOB.oracle/dbtools/app/Format
         could not be resolved

0/0      Note: Recompile with -Xlint:deprecation for details.

下载新版的SQLcl: 

https://www.oracle.com/tools/downloads/sqlcl-downloads.html 

使用目录里的 dbtools-common.jar 可以解决。

我这里把SQLcl放到了$ORACLE_HOME下:

loadjava -u anbob/anbob@cdb1pdb1 /u01/app/oracle/product/19.2.0/db_1/sqlcl/lib/dbtools-common.jar

2、JAVA授权

SQL> exec dbms_java.grant_permission( 'ANBOB', 'SYS:java.lang.RuntimePermission', 'oracle.DbmsJavaScriptUser', '' );

SQL> exec dbms_java.grant_permission( 'ANBOB', 'SYS:java.lang.RuntimePermission', 'accessClassInPackage.jdk.nashorn.internal.runtime', '' );

SQL> exec dbms_java.grant_permission( 'ANBOB', 'SYS:java.lang.reflect.ReflectPermission', 'suppressAccessChecks', '' );

SQL> exec dbms_java.grant_permission( 'ANBOB', 'SYS:java.util.PropertyPermission', 'polyglot.js.nashorn-compat', 'write' )

注意:如果不授权SYS:java.util.PropertyPermission 在后面执行时会提示无权限。

3、创建JAVA函数

CREATE or replace AND COMPILE JAVA SOURCE NAMED SQLFormatter AS
/* Imports */
import oracle.dbtools.app.Format;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import oracle.sql.BLOB;
import oracle.sql.CLOB;
import java.io.StringWriter;
import java.io.PrintWriter;


public class SQLFormatter {

    private static String getStackTrace(Exception e) {
       StringWriter writer = new StringWriter();
       PrintWriter printWriter = new PrintWriter( writer );
       e.printStackTrace( printWriter );
       printWriter.flush();

       return writer.toString();
    }

    public static Format getFormat() {
        oracle.dbtools.app.Format format = new oracle.dbtools.app.Format();
        
        format.options.put("singleLineComments", Format.InlineComments.CommentsUnchanged);
        format.options.put("kwCase", Format.Case.UPPER);
        format.options.put("idCase", Format.Case.NoCaseChange);                             // default: Format.Case.lower
        format.options.put("adjustCaseOnly", false);                                        // default: false (set true to skip formatting)
        format.options.put("formatThreshold", 1);                                           // default: 1 (disables deprecated post-processing logic)
        // Alignment
        format.options.put("alignTabColAliases", false);                                    // default: true
        format.options.put("alignTypeDecl", true);
        format.options.put("alignNamedArgs", true);
        format.options.put("alignEquality", false);
        format.options.put("alignAssignments", true);                                       // default: false
        format.options.put("alignRight", false);                                            // default: false
        // Indentation
        format.options.put("identSpaces", 3);                                               // default: 4
        format.options.put("useTab", false);
        // Line Breaks
        format.options.put("breaksComma", Format.Breaks.Before);                            // default: Format.Breaks.After
        format.options.put("breaksProcArgs", false);
        format.options.put("breaksConcat", Format.Breaks.Before);
        format.options.put("breaksAroundLogicalConjunctions", Format.Breaks.Before);
        format.options.put("breaksAfterSelect", true);                                      // default: true
        format.options.put("commasPerLine", 1);                                             // default: 5
        format.options.put("breakOnSubqueries", true);
        format.options.put("breakAnsiiJoin", true);                                         // default: false
        format.options.put("breakParenCondition", true);                                    // default: false
        format.options.put("maxCharLineSize", 120);                                         // default: 128
        format.options.put("forceLinebreaksBeforeComment", false);                          // default: false
        format.options.put("extraLinesAfterSignificantStatements", Format.BreaksX2.Keep);   // default: Format.BreaksX2.X2
        format.options.put("flowControl", Format.FlowControl.IndentedActions);
        // White Space
        format.options.put("spaceAroundOperators", true);
        format.options.put("spaceAfterCommas", true);
        format.options.put("spaceAroundBrackets", Format.Space.Default);
        //format.options.put("formatProgramURL", "default");
        
        return format;
    }
    
  public static String format(String str) 
  {
    String res;
    try {
       //res = new Format().format(str);
       Format f = SQLFormatter.getFormat();
       res = f.format(str);
       }
    catch (Exception e){
       res = "Error: " + e.getMessage() + " [ " + SQLFormatter.getStackTrace(e) + " ]";
    }
    return res;
  }

  public static CLOB formatClob(oracle.sql.CLOB clob) 
  throws SQLException
  {
    String str = clob.getSubString(1, (int) clob.length());
    String res = SQLFormatter.format(str);
    Connection conn = DriverManager.getConnection("jdbc:default:connection:");
    CLOB resClob = CLOB.createTemporary(conn, false, BLOB.DURATION_SESSION);
    resClob.setString(1L, res);
    
    return resClob;
  }
}
/

注:也可以从https://github.com/xtender/xt_scripts/blob/master/extra/SQLFormatte 下载最新版

4、创建PL/SQL PACKAGE

create or replace package SQLFormatter as

  FUNCTION Format(str in varchar2) RETURN VARCHAR2
  AS LANGUAGE JAVA NAME 'SQLFormatter.format(java.lang.String) return java.lang.String';

  FUNCTION FormatClob(str in clob) RETURN CLOB
  AS LANGUAGE JAVA NAME 'SQLFormatter.formatClob(oracle.sql.CLOB) return oracle.sql.CLOB';
  
end;
/

5、测试

SQL> select anbob.SQLFormatter.formatclob(to_clob('select 1 a from dual')) qtext from dual;

QTEXT
---------------------------------------------------------------------------------------
SELECT
   1 a
FROM
   dual


SQL> select anbob.SQLFormatter.format('select 1 a,2 /*123 */ b,3 c, d from dual, dual d2') qtext from dual;

QTEXT
----------------------------------------------------------------------------------------
SELECT
   1 a
 , 2 /*123 */ b
 , 3 c
 , d
FROM
   dual
 , dual d2

墨天轮原文链接:https://www.modb.pro/db/100274复制链接至浏览器或点击文末阅读原文查看)

关于作者

张维照,云和恩墨技术总监,Oracle ACE-A。2006年起从事数据库管理工作,2009年起从事O DBA维护工作,十余年来专注于Database技术和架构的研究,热衷于oracle数据库故障诊断、性能优化、内部原理、新特性的学习与分享,在BLOG分享大量的学习和案例经验。从事过多套TB级省级工商、医疗、交通、人社、政府、电信运营商等行业数据库项目从业经验。

END

推荐阅读:267页!2020年度数据库技术年刊

推荐下载:2020数据技术嘉年华PPT下载


2020数据技术嘉年华近50个PPT下载、视频回放已上传墨天轮平台,可在“数据和云”公众号回复关键词“2020DTC”获得!

你知道吗?我们的视频号里已经发布了很多精彩的内容,快去看看吧!↓↓↓

点击下图查看更多 ↓

云和恩墨大讲堂 | 一个分享交流的地方

长按,识别二维码,加入万人交流社群

请备注:云和恩墨大讲堂

  点个“在看” 

你的喜欢会被看到❤

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值