APEX_JSON 使用 clob 打印输出
APEX_JSON print output using clob
让我试着解释一下发生了什么。我为 运行 一个 apex_json 程序创建了一个简单的 sql 脚本,并创建了一个 json 文件。到这里为止,一切都很好。但是,当我查看创建的 JSON 文件的内容时,这些行被断开并且文件包含一些不应该存在的回车 returns 。我尝试了不同的组合,但我碰壁了。
这是我的代码:
这里是我的 json_file.sql 的内容(包含 sql 的脚本)
spool &1
DECLARE
c_limit CONSTANT PLS_INTEGER DEFAULT 10000; -- EXAMPLE of LIMIT
CURSOR nkey_cur (v_filename in varchar2) IS SELECT * FROM RDM_OUT.JSON_NKEY_REP_DTL DTL where DTL.FILENAME = v_filename ;
TYPE tbl_Nativekey IS TABLE OF RDM_OUT.JSON_NKEY_REP_DTL%ROWTYPE INDEX BY PLS_INTEGER;
var_Nativekey tbl_Nativekey;
v_clob := clob;
procedure print_clob_to_output (p_clob in clob)
is
l_offset int := 1;
begin
--dbms_output.put_line('Print CLOB');
loop
exit when l_offset > dbms_lob.getlength(p_clob);
dbms_output.put_line( dbms_lob.substr( p_clob, 32767, l_offset ) );
l_offset := l_offset + 32767;
end loop;
end print_clob_to_output;
BEGIN
for l_hdr_row in (select FILENAME, REPORT_DATE, DOMAINCODE, LEGALENTITYCODE from RDM_OUT.JSON_NKEY_REP_HDR where DOMAINCODE = '00001' )
loop
APEX_JSON.INITIALIZE_CLOB_OUTPUT;
APEX_JSON.OPEN_OBJECT;
APEX_JSON.WRITE('Date',l_hdr_row.REPORT_DATE);
APEX_JSON.WRITE('DomainCode',l_hdr_row.DOMAINCODE);
APEX_JSON.WRITE('LegalEntityCode',l_hdr_row.LEGALENTITYCODE);
APEX_JSON.OPEN_ARRAY('Keys');
OPEN nkey_cur(l_hdr_row.FILENAME);
LOOP
FETCH nkey_cur BULK COLLECT INTO var_Nativekey LIMIT c_limit;
EXIT WHEN var_Nativekey.COUNT = 0;
FOR i IN var_Nativekey.FIRST..var_Nativekey.LAST LOOP
APEX_JSON.OPEN_OBJECT;
APEX_JSON.WRITE('NativeKey',var_Nativekey(i).NATIVEKEY);
APEX_JSON.WRITE('MasterKey',var_Nativekey(i).MASTERKEY);
APEX_JSON.WRITE('EndDate',var_Nativekey(i).ENDDATE);
APEX_JSON.CLOSE_OBJECT;
END LOOP;
END LOOP;
CLOSE nkey_cur;
APEX_JSON.CLOSE_ARRAY;
APEX_JSON.CLOSE_OBJECT;
APEX_JSON.CLOSE_ALL;
v_clob := APEX_JSON.GET_CLOB_OUTPUT ;
APEX_JSON.FREE_OUTPUT;
PRINT_CLOB_TO_OUTPUT(p_clob => v_clob);
end loop;
END;
/
spool off
exit
我 运行 这个程序使用 shell 脚本,基本上以这种方式调用 sqlplus
SQL> whenever sqlerror exit failure;
whenever oserror exit failure;
set serveroutput on size unlimited pages 0 lines 180 long 99999999 head off verify off feed off
@json_query.sql file.json
json 已创建,这是我找到虚线的时间(请参阅下面的键 EndDate 值):
$ cat -vte file.json
{$
"Date":"2020-03-31"$
,"DomainCode":"00001"$
,"LegalEntityCode":"00055"$
,"Keys":[$
{$
"NativeKey":"129582692"$
,"MasterKey":"329323111430011996"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey$
":"14735034"$
,"MasterKey":"329390935000331576"$
,"EndDate":"9999-12-31"$
}$
,{ $
$
"NativeKey":"98102571"$
,"MasterKey":"329361261430632555"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey":"175080315"$
,"MasterKey":"329361251430284082"$
,"EndDate":"9999-12-31"$
}$
,{$
"Nativ$
eKey":"34262142"$
,"MasterKey":"329323245070279903"$
,"EndDate":"9999-12-31"$
$
}$
,{$
"NativeKey":"84094570"$
,"MasterKey":"329395105070385872"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey":"43337038"$
,"MasterKey":"329323085070265746"$
,"EndDate":"9999-12-31"$
}$
,{$
"Na$
tiveKey":"86265510"$
,"MasterKey":"329300305070004470"$
,"EndDate":"9999-12-3 $
1"$
}$
,{$
"NativeKey":"96926906"$
,"MasterKey":"329323031430673339"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey":"96760800"$
,"MasterKey":"329323031430666865"$
,"EndDate":"9999-12-31"$
}$
,{$
$
"NativeKey":"94063822"$
,"MasterKey":"329323031430571553"$
,"EndDate":"9999-1 $
2-31"$
}$
,{$
"NativeKey":"14529231"$
,"MasterKey":"329390935000077722"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey":"173183320"$
,"MasterKey":"329344461430004834"$
,"EndDate":"9999-12-31"$
}$
$
,{$
"NativeKey":"34044987"$
,"MasterKey":"329323245070056084"$
,"EndDate":"99 $
99-12-31"$
}$
]$
}$
有人知道这里发生了什么吗?我什至尝试将 clob 存储在 table 中,然后使用函数从那里打印它,但是在插入数据时它已经损坏了。我在某处读到 APEX_JSON 使用 HTP 缓冲区写入数据,但我不明白我做错了什么或为什么 json 已损坏。
非常感谢任何帮助
谢谢
问题不在于 APEX_JSON,您每 180 个字符(这是您的行长度)会得到一个额外的换行符,第一个出现在第二个 NativeKey 键名称中。
问题是您的 CLOB 中的换行符被 SQL*Plus 行长度处理绊倒了。即使您手动构造一个包含干净 JSON 内容的 CLOB,并执行 dbms_output.put_line(v_clob, 200, 1);
,它仍会在同一位置添加一个换行符。据我所知,您似乎对此无能为力;最接近的是将 linesize
设置得非常高,但大型 CLOB 最终会破坏它。顺便说一下,切换到 SQLcl 似乎可以避免这个问题。
您可以在 print_clob_to_output
过程中修复它,方法是将 CLOB 拆分为单独的行并逐行打印,而不是像现在这样仅根据字符数拆分。 (顺便说一句,无论如何,您的程序都略有损坏;除了这个问题之外,您每 32767 个字符都会有一个额外的换行符,因为 put_line
添加了一个。如果您确实决定,则需要查看它切换到 SQLcl.)
declare
v_clob clob;
procedure print_clob_to_output (p_clob in clob)
is
l_offset pls_integer := 1;
l_chars pls_integer;
begin
--dbms_output.put_line('Print CLOB');
loop
exit when l_offset > dbms_lob.getlength(p_clob);
l_chars := dbms_lob.instr(p_clob, chr(10), l_offset, 1);
if l_chars is null or l_chars = 0 then
l_chars := dbms_lob.getlength(p_clob) + 1;
end if;
dbms_output.put_line('> ' || dbms_lob.substr(p_clob, l_chars - l_offset, l_offset));
l_offset := l_chars + 1;
end loop;
end print_clob_to_output;
begin
...
此版本在 CLOB 中从当前偏移量开始查找下一个换行符 - chr(10)
- 然后从偏移量到之前的字符处获取子字符串。子字符串,表示没有换行符的完整行,当该行输出为 put_line
时,它会添加自己的行。 chr(10)
被 l_offset := l_chars + 1
行丢弃。如果没有换行符,或者最后一行没有以换行符结尾,还有一些处理。
缓冲区处理 - 我认为 - 意味着 SQL*Plus 然后不会混淆并且不会将输出包装到额外的行上。
让我试着解释一下发生了什么。我为 运行 一个 apex_json 程序创建了一个简单的 sql 脚本,并创建了一个 json 文件。到这里为止,一切都很好。但是,当我查看创建的 JSON 文件的内容时,这些行被断开并且文件包含一些不应该存在的回车 returns 。我尝试了不同的组合,但我碰壁了。
这是我的代码:
这里是我的 json_file.sql 的内容(包含 sql 的脚本)
spool &1
DECLARE
c_limit CONSTANT PLS_INTEGER DEFAULT 10000; -- EXAMPLE of LIMIT
CURSOR nkey_cur (v_filename in varchar2) IS SELECT * FROM RDM_OUT.JSON_NKEY_REP_DTL DTL where DTL.FILENAME = v_filename ;
TYPE tbl_Nativekey IS TABLE OF RDM_OUT.JSON_NKEY_REP_DTL%ROWTYPE INDEX BY PLS_INTEGER;
var_Nativekey tbl_Nativekey;
v_clob := clob;
procedure print_clob_to_output (p_clob in clob)
is
l_offset int := 1;
begin
--dbms_output.put_line('Print CLOB');
loop
exit when l_offset > dbms_lob.getlength(p_clob);
dbms_output.put_line( dbms_lob.substr( p_clob, 32767, l_offset ) );
l_offset := l_offset + 32767;
end loop;
end print_clob_to_output;
BEGIN
for l_hdr_row in (select FILENAME, REPORT_DATE, DOMAINCODE, LEGALENTITYCODE from RDM_OUT.JSON_NKEY_REP_HDR where DOMAINCODE = '00001' )
loop
APEX_JSON.INITIALIZE_CLOB_OUTPUT;
APEX_JSON.OPEN_OBJECT;
APEX_JSON.WRITE('Date',l_hdr_row.REPORT_DATE);
APEX_JSON.WRITE('DomainCode',l_hdr_row.DOMAINCODE);
APEX_JSON.WRITE('LegalEntityCode',l_hdr_row.LEGALENTITYCODE);
APEX_JSON.OPEN_ARRAY('Keys');
OPEN nkey_cur(l_hdr_row.FILENAME);
LOOP
FETCH nkey_cur BULK COLLECT INTO var_Nativekey LIMIT c_limit;
EXIT WHEN var_Nativekey.COUNT = 0;
FOR i IN var_Nativekey.FIRST..var_Nativekey.LAST LOOP
APEX_JSON.OPEN_OBJECT;
APEX_JSON.WRITE('NativeKey',var_Nativekey(i).NATIVEKEY);
APEX_JSON.WRITE('MasterKey',var_Nativekey(i).MASTERKEY);
APEX_JSON.WRITE('EndDate',var_Nativekey(i).ENDDATE);
APEX_JSON.CLOSE_OBJECT;
END LOOP;
END LOOP;
CLOSE nkey_cur;
APEX_JSON.CLOSE_ARRAY;
APEX_JSON.CLOSE_OBJECT;
APEX_JSON.CLOSE_ALL;
v_clob := APEX_JSON.GET_CLOB_OUTPUT ;
APEX_JSON.FREE_OUTPUT;
PRINT_CLOB_TO_OUTPUT(p_clob => v_clob);
end loop;
END;
/
spool off
exit
我 运行 这个程序使用 shell 脚本,基本上以这种方式调用 sqlplus
SQL> whenever sqlerror exit failure;
whenever oserror exit failure;
set serveroutput on size unlimited pages 0 lines 180 long 99999999 head off verify off feed off
@json_query.sql file.json
json 已创建,这是我找到虚线的时间(请参阅下面的键 EndDate 值):
$ cat -vte file.json
{$
"Date":"2020-03-31"$
,"DomainCode":"00001"$
,"LegalEntityCode":"00055"$
,"Keys":[$
{$
"NativeKey":"129582692"$
,"MasterKey":"329323111430011996"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey$
":"14735034"$
,"MasterKey":"329390935000331576"$
,"EndDate":"9999-12-31"$
}$
,{ $
$
"NativeKey":"98102571"$
,"MasterKey":"329361261430632555"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey":"175080315"$
,"MasterKey":"329361251430284082"$
,"EndDate":"9999-12-31"$
}$
,{$
"Nativ$
eKey":"34262142"$
,"MasterKey":"329323245070279903"$
,"EndDate":"9999-12-31"$
$
}$
,{$
"NativeKey":"84094570"$
,"MasterKey":"329395105070385872"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey":"43337038"$
,"MasterKey":"329323085070265746"$
,"EndDate":"9999-12-31"$
}$
,{$
"Na$
tiveKey":"86265510"$
,"MasterKey":"329300305070004470"$
,"EndDate":"9999-12-3 $
1"$
}$
,{$
"NativeKey":"96926906"$
,"MasterKey":"329323031430673339"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey":"96760800"$
,"MasterKey":"329323031430666865"$
,"EndDate":"9999-12-31"$
}$
,{$
$
"NativeKey":"94063822"$
,"MasterKey":"329323031430571553"$
,"EndDate":"9999-1 $
2-31"$
}$
,{$
"NativeKey":"14529231"$
,"MasterKey":"329390935000077722"$
,"EndDate":"9999-12-31"$
}$
,{$
"NativeKey":"173183320"$
,"MasterKey":"329344461430004834"$
,"EndDate":"9999-12-31"$
}$
$
,{$
"NativeKey":"34044987"$
,"MasterKey":"329323245070056084"$
,"EndDate":"99 $
99-12-31"$
}$
]$
}$
有人知道这里发生了什么吗?我什至尝试将 clob 存储在 table 中,然后使用函数从那里打印它,但是在插入数据时它已经损坏了。我在某处读到 APEX_JSON 使用 HTP 缓冲区写入数据,但我不明白我做错了什么或为什么 json 已损坏。
非常感谢任何帮助 谢谢
问题不在于 APEX_JSON,您每 180 个字符(这是您的行长度)会得到一个额外的换行符,第一个出现在第二个 NativeKey 键名称中。
问题是您的 CLOB 中的换行符被 SQL*Plus 行长度处理绊倒了。即使您手动构造一个包含干净 JSON 内容的 CLOB,并执行 dbms_output.put_line(v_clob, 200, 1);
,它仍会在同一位置添加一个换行符。据我所知,您似乎对此无能为力;最接近的是将 linesize
设置得非常高,但大型 CLOB 最终会破坏它。顺便说一下,切换到 SQLcl 似乎可以避免这个问题。
您可以在 print_clob_to_output
过程中修复它,方法是将 CLOB 拆分为单独的行并逐行打印,而不是像现在这样仅根据字符数拆分。 (顺便说一句,无论如何,您的程序都略有损坏;除了这个问题之外,您每 32767 个字符都会有一个额外的换行符,因为 put_line
添加了一个。如果您确实决定,则需要查看它切换到 SQLcl.)
declare
v_clob clob;
procedure print_clob_to_output (p_clob in clob)
is
l_offset pls_integer := 1;
l_chars pls_integer;
begin
--dbms_output.put_line('Print CLOB');
loop
exit when l_offset > dbms_lob.getlength(p_clob);
l_chars := dbms_lob.instr(p_clob, chr(10), l_offset, 1);
if l_chars is null or l_chars = 0 then
l_chars := dbms_lob.getlength(p_clob) + 1;
end if;
dbms_output.put_line('> ' || dbms_lob.substr(p_clob, l_chars - l_offset, l_offset));
l_offset := l_chars + 1;
end loop;
end print_clob_to_output;
begin
...
此版本在 CLOB 中从当前偏移量开始查找下一个换行符 - chr(10)
- 然后从偏移量到之前的字符处获取子字符串。子字符串,表示没有换行符的完整行,当该行输出为 put_line
时,它会添加自己的行。 chr(10)
被 l_offset := l_chars + 1
行丢弃。如果没有换行符,或者最后一行没有以换行符结尾,还有一些处理。
缓冲区处理 - 我认为 - 意味着 SQL*Plus 然后不会混淆并且不会将输出包装到额外的行上。