PLSQL - 字符串缓冲区太小

时间:2018-04-03 13:29:48

标签: sql oracle

我正在尝试运行以下查询来浏览一堆包含HTML页面的CLOB:

SELECT template_id, REGEXP_SUBSTR(clean_html, 'src="[^"]*\.js"', 1, LEVEL, 'i') AS match
  FROM (
    SELECT template_id,  REGEXP_REPLACE(html_text, '<!--.*?-->', '', 1, 0, 'n') AS clean_html
     FROM (
           SELECT t.id as template_id, dbms_lob.substr(t.data, 4000, 1) AS html_text
           FROM template t
     )
  )
CONNECT BY REGEXP_SUBSTR(clean_html, 'src="[^"]*\.js"', 1, LEVEL, 'i') IS NOT NULL
 GROUP BY template_id,
      clean_html,
      LEVEL
order by 1

但是我在第1行和第34行的字符串缓冲区太小了。几乎是在运行我的查询后直接。

如果我在一个只有几个模板的小数据集上运行它,那么一旦我在整个HTML模板列表上运行它,它就会抛出错误。

我认为这个问题与dbms_lob.substr(data,4000,1)有关,可能与子字符串超过4000字节有关,因为隐藏字符(或其他东西?),但我不知道知道如何解决它。

如果我写dbms_lob.substr(data,2000,1),那么我的子字符串太小,我丢失了HTML文件中的重要数据。如果我把它大于4000那么我会立即得到#34;缓冲区太小&#34;错误。

任何人都知道如何解决这个问题?理想情况下,我想查看我的整个数据&#39;字段而不仅仅是前4000个字符。但是,如果它在我长长的HTML文件列表中工作,那么前4000个字符就可以了。

谢谢

1 个答案:

答案 0 :(得分:0)

我假设您正在使用GROUP BY来获取不同的值,对吗?在这里对许多记录使用CONNECT BY的问题是它将返回大量重复项。但GROUP BYDISTINCT不是处理此问题的正确方法。取出GROUP BY并将以下行附加到您的查询中:

AND PRIOR template_id = template_id
AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL

另外,我认为您希望在最里面的查询中添加以下条件:

WHERE REGEXP_LIKE(t.data, 'src="[^"]*\.js"', 'i')

否则,查询将始终为template_id的每个值返回至少一行。

我不太确定CLOB发生了什么,但我还没能完全重现你的错误。

<强> EDITED

我想我有一个解决方案。请尝试以下方法:

SELECT template_id, REGEXP_SUBSTR(clean_html, 'src="[^"]*\.js"', 1, LEVEL, 'i') AS match
  FROM (
    SELECT template_id,  REGEXP_REPLACE(html_text, '<!--.*?-->', '', 1, 0, 'n') AS clean_html
     FROM (
       SELECT t.id as template_id, t.data AS html_text
         FROM template t
        WHERE REGEXP_LIKE(t.data, 'src="[^"]*\.js"', 'i')
     )
  )
CONNECT BY TO_CHAR(REGEXP_SUBSTR(clean_html, 'src="[^"]*\.js"', 1, LEVEL, 'i')) IS NOT NULL
  AND PRIOR template_id = template_id
  AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL;

我认为问题在于CONNECT BY子句

的比较
CONNECT BY REGEXP_SUBSTR(clean_html, 'src="[^"]*\.js"', 1, LEVEL, 'i') IS NOT NULL

此处比较CHARCLOB更好:

CONNECT BY TO_CHAR(REGEXP_SUBSTR(clean_html, 'src="[^"]*\.js"', 1, LEVEL, 'i')) IS NOT NULL

你甚至可以在这里使用DBMS_LOB.SUBSTR()安全:

CONNECT BY DBMS_LOB.SUBSTR(REGEXP_SUBSTR(clean_html, 'src="[^"]*\.js"', 1, LEVEL, 'i'), 4000, 1) IS NOT NULL

最后,我认为你不需要那么多级别的子查询。我想你可以做到以下几点:

SELECT template_id, REGEXP_SUBSTR(clean_html, 'src="[^"]*\.js"', 1, LEVEL, 'i') AS match
  FROM (
    SELECT t.id AS template_id, REGEXP_REPLACE(t.data, '<!--.*?-->', '', 1, 0, 'n') AS clean_html
      FROM template t
     WHERE REGEXP_LIKE(t.data, 'src="[^"]*\.js"', 'i')
  )
CONNECT BY DBMS_LOB.SUBSTR(REGEXP_SUBSTR(clean_html, 'src="[^"]*\.js"', 1, LEVEL, 'i'), 4000, 1) IS NOT NULL
  AND PRIOR template_id = template_id
  AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL;

希望这有帮助。