html 在Oracle中执行视图时出现连接字段转换错误

vcudknz3  于 2022-12-16  发布在  Oracle
关注(0)|答案(2)|浏览(131)

我有一个视图(DB_ADMIN.VW_DBA_MONITOR_CURRENTLYEXEC),可以可视化Oracle中的事务。此视图利用了系统中已经存在的事务:x一米一纳米一x、x一米二纳米一x、x一米三纳米一x和x一米四纳米一x。
柱的结构和类型如下:

我有一个过程尝试使用这样的视图,在特定条件下将输出格式化为单个HTML字符串,然后通过电子邮件发送。

DECLARE
    V_BODY_TEXT CLOB;
BEGIN
    select utl_i18n.unescape_reference(xmlagg(xmlelement(e,'
        <tr>
            <td>' || ltrim(rtrim(TO_CLOB(SID))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(SQL_ID))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(USERNAME))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(ONAME))) || '</th> 
            <td>' || ltrim(rtrim(TO_CLOB(MACHINE))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(WAIT_CLASS))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(EVENT))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(MODULE))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(LOGON_TIME))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(START_TIME))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(TIME))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(SQL_TEXT))) || '</th>
        </tr>
    ','').extract('//text()')).getclobval()) x
    INTO V_BODY_TEXT
    FROM DB_ADMIN.VW_DBA_MONITOR_CURRENTLYEXEC WHERE "TIME" > 300;
               
END;

执行上述代码时出现的错误是因为连接的结果只允许4000个字符,无论我是尝试逐字段转换(TO_CLOB)还是转换整个连接的字符串,每次都得到相同的错误。

关于上面的代码,使用了TO_CLOB函数,是我最后一次尝试尝试解决的问题。
所述错误也不允许对其应用任何“substring”或“len”类型的操作。
我也尝试过创建一个包含CLOB类型的所有字段的表,然后插入视图的结果,现在对表使用上面的过程,但是每当生成的html代码超过4000个字符时,我总是得到相同的错误。
因此,我去这个社区看看他们给我什么其他的选择来摆脱这个问题。

4ioopgfo

4ioopgfo1#

如果初始化参数MAX_STRING_SIZE = STANDARD,则xmlelement函数最多只能接受4000个字符,如果MAX_STRING_SIZE = EXTENDED,则xmlelement函数最多只能接受32767个字符,因此在进程的早期转换为CLOB是没有意义的。
另外,utl_i18n.unescape_reference函数只接受VARCHAR2输入,而不接受CLOB。请参阅此处。这是查询最有可能失败的地方。
请尝试以下操作,专门使用VARCHAR2,从NUMBER和DATE类型进行显式转换,并将聚合保存到最后的最大字符串中:

DECLARE
    V_BODY_TEXT CLOB;
BEGIN
    select xmlagg(utl_i18n.unescape_reference(xmlelement(e,'
        <tr>
            <td>' || TO_CHAR(SID) || '</th>  
            <td>' || ltrim(rtrim(SQL_ID)) || '</th>  
            <td>' || ltrim(rtrim(USERNAME)) || '</th>  
            <td>' || ltrim(rtrim(ONAME)) || '</th> 
            <td>' || ltrim(rtrim(MACHINE)) || '</th>  
            <td>' || ltrim(rtrim(WAIT_CLASS)) || '</th>  
            <td>' || ltrim(rtrim(EVENT)) || '</th>  
            <td>' || ltrim(rtrim(MODULE)) || '</th>  
            <td>' || TO_CHAR(LOGON_TIME,'DD-MON-YYYY') || '</th>  
            <td>' || TO_CHAR(START_TIME,'DD-MON-YYYY') || '</th>  
            <td>' || TO_CHAR(TIME) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(SQL_TEXT))) || '</th>
        </tr>
    ',''))) x
    INTO V_BODY_TEXT
    FROM DB_ADMIN.VW_DBA_MONITOR_CURRENTLYEXEC WHERE "TIME" > 300;
           
END;
hl0ma9xz

hl0ma9xz2#

XMLType方法自Oracle 11 gr 2以来已被弃用,使用现代(尽管很难了解XML)SQL函数来访问XML数据,而不会出现额外的序列化/反序列化问题:

  • XMLQUERY用于提取。
  • XMLCAST用于反序列化。它将&amp;等HTML/XML内容解码为它们的文本值。

下面是用零填充的三个字符的示例,最多5000字节(因此导致varchar2的值过大)

with t(col) as (
  select
    xmlelement(e,
      to_clob(rpad('<>&', 4000, '0'))
      || to_clob(rpad('0', 1000, '0'))
    )
  from dual
)
, deser as (
  select
    xmlcast(xmlquery(
      '//text()'
      passing col
      returning content
    ) as clob) as res
  from t
)
select
  length(res),
  trim(trailing '0' from res) as res
from deser

字符串
| 长度(分辨率)|保留|
| - ------|- ------|
| 五千|〈〉和|
fiddle

相关问题