Oracle PL/SQL 中的漂亮打印

Posted

技术标签:

【中文标题】Oracle PL/SQL 中的漂亮打印【英文标题】:Pretty print in Oracle PL/SQL 【发布时间】:2016-05-23 17:12:39 【问题描述】:

有没有更好的方法在 Oracle PL/SQL 中打印到 STDOUT?

DBMS_OUTPUT.PUT_LINE 看起来非常基本和粗略。 应该有Python的pprint(Pretty Print)之类的东西吗?

【问题讨论】:

“应该有”还是“有”?欢迎您编写自己的程序。 您在哪里使用 DBMS_OUTPUT,在 sql*plus 报告中?否则,获取文本,并在您的应用代码中对其进行格式化 【参考方案1】:

PL/SQL 旨在处理数据,而不是显示数据,或与调用它的客户端交互(例如,没有用户输入机制)。

The DBMS_OUTPUT package“使您能够从存储过程和包发送消息。该包对于显示 PL/SQL 调试信息特别有用”。它不是为“漂亮”的输出而设计的,因为 PL/SQL 不是为这种工作而设计的。重要的是要意识到调用您的过程的客户端可能不会查看或显示 DBMS_OUTPUT 缓冲区,因此您写入的内容可能会丢失。

PL/SQL 不会将 anything 打印到标准输出; DBMS_OUTPUT 调用写入缓冲区 - 如果它完全启用 - 然后在 PL/SQL 完成执行后,客户端 可以读取该缓冲区并在某处显示内容(如果启用,则再次显示)。这也意味着您不能使用它来跟踪进度,因为在执行过程中您看不到任何东西,只有在它完成时才能看到;所以即使是调试它也不是最好的工具。

根据您要执行的操作,您可以通过执行set serveroutput on format wrapped 使 SQL*Plus 中的内容看起来稍微好一些,这将阻止它在缓冲区行的开头丢失空格。但这通常是一个很小的好处。

更一般地,您的过程应该通过 OUT 参数将其处理结果传递给调用者,或者通过使其成为返回有用信息的函数。

如果您当前正尝试使用dbms_output.put_line 显示查询结果,那么这不是一个好主意。您可以改为将集合或引用光标返回给客户端,并让客户端担心如何显示它。您可以轻松地在 SQL*Plus 或 SQL Developer using bind variables 中显示引用游标。

【讨论】:

很好的讲座。我只需要漂亮的印刷品。 Python 旨在处理数据,而不是显示数据。他们仍然有 pprint。 但是 Python 也被设计成交互式的; PL/SQL 不是。也许另一个区别是 PL/SQL 在服务器中运行,在数据库内部,而不是在客户端中。客户端 - 或计划的作业,或其他一点 PL/SQL - 要求服务器执行代码。【参考方案2】:

够了吗?

 --Pretty print
CREATE OR REPLACE PROCEDURE PP(input varchar2, p_pn varchar2:='PP')
AS
   pos   INTEGER;
   len   INTEGER      := 4000;
   nl    VARCHAR2 (2) := CHR (10);
   r_    VARCHAR2 (2) := CHR (13);
   v_padded varchar2(64):=p_pn;--rpad(p_pn, 5, ' ');
BEGIN
   IF LENGTH (input) > len
   THEN
      pos := INSTR (input, nl, 1, 1);
      IF pos > 0 AND pos < len
      THEN
         DBMS_OUTPUT.put_line (v_padded||': '||REPLACE (SUBSTR (input, 1, pos - 1), r_, ''));
         pp (SUBSTR (input, pos + 1),p_pn);
      ELSE
         IF pos = 0 AND LENGTH (input) <= len
         THEN
  DBMS_OUTPUT.put_line (v_padded||': '||REPLACE (SUBSTR (input, 1, len), r_, ''));
         ELSE
  DBMS_OUTPUT.put_line (v_padded||': '||REPLACE (SUBSTR (input, 1, len), r_, ''));
  pp (SUBSTR (input, len + 1),p_pn);
         END IF;
      END IF;
   ELSE
      DBMS_OUTPUT.put_line (v_padded||': '||REPLACE (SUBSTR (input, 1, len), r_, ''));
   END IF;
EXCEPTION
   WHEN OTHERS
   THEN
      RAISE;
END PP;

示例输出:

SQL>
FUN_ENCRYPT_PERSON_ID: Input  = 123456789123
FUN_ENCRYPT_PERSON_ID: Suffix = 123
FUN_ENCRYPT_PERSON_ID: Base   = 876543210
FUN_ENCRYPT_PERSON_ID: 2->5 1 10000     10000
FUN_ENCRYPT_PERSON_ID: 3->9 2 200000000 200010000
FUN_ENCRYPT_PERSON_ID: 4->2 3 30        200010030
FUN_ENCRYPT_PERSON_ID: 5->1 4 4         200010034
FUN_ENCRYPT_PERSON_ID: 6->3 5 500       200010534
FUN_ENCRYPT_PERSON_ID: 7->6 6 600000    200610534
FUN_ENCRYPT_PERSON_ID: 8->4 7 7000      200617534
FUN_ENCRYPT_PERSON_ID: 9->8 8 80000000  280617534
FUN_ENCRYPT_PERSON_ID: Output = 280617534123

【讨论】:

【参考方案3】:

我知道没有内置函数。但是我写了一个过程来从存储过程中漂亮地打印一个结果集。

该过程称为 print_out_resultset。示例用法:

....
cursor mycur (mynum in number) is
select * from mytable where mycol >= mynum; 

myrow mytable%rowtype;
myvar number;
...
begin
....

print_out_resultset(query_string =>
  'select * from mytable where mycol >= :b1',
  col1 => 'SAM', col2 => 'FRED', col3 => 'ERIC',
  b1 => myvar,
  maxrows => 4);

open mycur(myvar);
fetch mycur into myrow;
while mycur%found loop
....

示例结果

SQL> set serverout on;
SQL> execute myproc;
SAM         FRED        ERIC       
-----------------------------------
32A         49B         15C
34A         11B         99C
11F         99A         887
77E         88J         976

代码在这里:http://toolkit.rdbms-insight.com/print_out_resultset.php

多年前,我仅将其用于故障排除;当然,在生产部署之前进行测试

【讨论】:

【参考方案4】:

其实有一个标准的方法,但它只适用于 varchar 变量:

declare
  v_str varchar2(100):= 'formatted';
  v_int int := 10 ;
begin
  dbms_output.put_line(
     UTL_LMS.FORMAT_MESSAGE('Somebody told that "%s" output works well with ' 
                            ||'varchar variables, but not with int variables: "%d". '
                            ||'Only with constant integers (%d) it works.'
                            , v_str, v_int, 100)                            
  );
end;

【讨论】:

【参考方案5】:

如果您尝试打印 json 对象,有更好的方法来使用 JSON_UTIL_PKGJSON_PRINTER 进行打印。

  L_JSON_LIST         JSON_LIST;
  L_JSON              JSON;
  L_CLOB              CLOB;
BEGIN
  --JSON_UTIL_PKG.SQL_TO_JSON returns a list, so storing it in a JSON_LIST.
  L_JSON_LIST := JSON_UTIL_PKG.SQL_TO_JSON('SELECT
                                      ''abc'' "Address1",
                                      ''def'' "Address2",
                                      ''gh'' "City"
                                     FROM
                                       DUAL');
  DBMS_LOB.CREATETEMPORARY(L_CLOB, TRUE);                            
  --get the first item in the list
  L_JSON :=       JSON(L_JSON_LIST.GET(1));
  --It takes a json object and will return it in a clob.
  JSON_PRINTER.PRETTY_PRINT(OBJ => L_JSON, BUF => L_CLOB); 

  --output  
  DBMS_OUTPUT.PUT_LINE(L_CLOB);                                    
END;

而且,输出如下所示,


  "Address1" : "abc"
,
  "Address2" : "def"
,
  "City" : "gh"


【讨论】:

【参考方案6】:

也许你正在寻找 fnd_file 函数

fnd_file.put_line(fnd_file.output,:message);

其中 :message 是您要打印的值。

【讨论】:

看起来 fnd_file 是一个 PL/SQL 包,仅在 Oracle E-Business Suite 中可用。

以上是关于Oracle PL/SQL 中的漂亮打印的主要内容,如果未能解决你的问题,请参考以下文章

新的 jupyter 笔记本中的 sympy 漂亮打印是不是损坏?

Python:Jupyter Notebook 中的漂亮打印

Java 中的漂亮打印 JSON

如何在 SQLAlchemy 中漂亮地格式化 SQL 查询的打印?

python python中的漂亮(或漂亮打印)JSON对象具有这一功能。在尝试了解什么时,我总是使用这个片段

clojure中的漂亮打印机XML