Oracle 中的漂亮打印 PL/SQL
Pretty print in Oracle PL/SQL
在 Oracle PL/SQL 中是否有更好的打印到 STDOUT 的方法?
DBMS_OUTPUT.PUT_LINE 看起来非常基础和粗糙。
应该有类似Python的pprint(漂亮的打印)吗?
PL/SQL 旨在处理数据,而不是显示数据或与调用它的客户端进行交互(例如,没有用户输入机制)。
The DBMS_OUTPUT
package"enables you to send messages from stored procedures and packages. The package is especially useful for displaying PL/SQL debugging information"。它不是为 'pretty' 输出而设计的,因为 PL/SQL 不是为那种工作而设计的。并且重要的是要意识到调用您的过程的客户端可能不会查看或显示 DBMS_OUTPUT 缓冲区,因此您写入它的内容无论如何都可能丢失。
PL/SQL 不会将 任何内容 打印到标准输出; DBMS_OUTPUT 调用写入缓冲区 - 如果它完全启用 - 然后一旦 PL/SQL 完成执行,client 可以读取该缓冲区并显示某处的内容(再次启用)。这也意味着您不能使用它来跟踪进度,因为在执行过程中您看不到任何东西,只有在它完成时才会看到;所以即使是调试它也不总是最好的工具。
根据您尝试执行的操作,您可以通过执行 set serveroutput on format wrapped
使 SQL*Plus 中的内容看起来稍微好一些,这会阻止它在缓冲区行的开头丢失空格。但这通常是一个小好处。
更一般地说,您的过程应该通过 OUT 参数将其处理结果传递给调用者,或者使它成为一个 return 有用的函数。
如果您目前正在尝试使用 dbms_output.put_line
显示查询结果,那么这不是一个好主意。您可以改为 return 向客户端发送一个集合或一个引用游标,并让客户端担心如何显示它。您可以在 SQL*Plus 或 SQL Developer using bind variables.
中轻松显示参考光标
没有我所知道的内置函数。但是我写了一个过程来从存储过程中漂亮地打印结果集。
该过程称为 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
很多年前,我只是用它来进行故障排除;当然在生产部署之前进行测试
够漂亮吗?
--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
实际上有一个标准方法,但它只适用于 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;
如果您尝试打印 json 对象,可以使用 JSON_UTIL_PKG 和 JSON_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"
}
也许您正在寻找 fnd_file 函数
fnd_file.put_line(fnd_file.output,:message);
其中 :message 是您要打印的值。
在 Oracle PL/SQL 中是否有更好的打印到 STDOUT 的方法?
DBMS_OUTPUT.PUT_LINE 看起来非常基础和粗糙。 应该有类似Python的pprint(漂亮的打印)吗?
PL/SQL 旨在处理数据,而不是显示数据或与调用它的客户端进行交互(例如,没有用户输入机制)。
The DBMS_OUTPUT
package"enables you to send messages from stored procedures and packages. The package is especially useful for displaying PL/SQL debugging information"。它不是为 'pretty' 输出而设计的,因为 PL/SQL 不是为那种工作而设计的。并且重要的是要意识到调用您的过程的客户端可能不会查看或显示 DBMS_OUTPUT 缓冲区,因此您写入它的内容无论如何都可能丢失。
PL/SQL 不会将 任何内容 打印到标准输出; DBMS_OUTPUT 调用写入缓冲区 - 如果它完全启用 - 然后一旦 PL/SQL 完成执行,client 可以读取该缓冲区并显示某处的内容(再次启用)。这也意味着您不能使用它来跟踪进度,因为在执行过程中您看不到任何东西,只有在它完成时才会看到;所以即使是调试它也不总是最好的工具。
根据您尝试执行的操作,您可以通过执行 set serveroutput on format wrapped
使 SQL*Plus 中的内容看起来稍微好一些,这会阻止它在缓冲区行的开头丢失空格。但这通常是一个小好处。
更一般地说,您的过程应该通过 OUT 参数将其处理结果传递给调用者,或者使它成为一个 return 有用的函数。
如果您目前正在尝试使用 dbms_output.put_line
显示查询结果,那么这不是一个好主意。您可以改为 return 向客户端发送一个集合或一个引用游标,并让客户端担心如何显示它。您可以在 SQL*Plus 或 SQL Developer using bind variables.
没有我所知道的内置函数。但是我写了一个过程来从存储过程中漂亮地打印结果集。
该过程称为 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
很多年前,我只是用它来进行故障排除;当然在生产部署之前进行测试
够漂亮吗?
--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
实际上有一个标准方法,但它只适用于 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;
如果您尝试打印 json 对象,可以使用 JSON_UTIL_PKG 和 JSON_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"
}
也许您正在寻找 fnd_file 函数
fnd_file.put_line(fnd_file.output,:message);
其中 :message 是您要打印的值。