PLSQL - 字符串缓冲区太小
Posted
技术标签:
【中文标题】PLSQL - 字符串缓冲区太小【英文标题】:PLSQL - character string buffer too small 【发布时间】:2018-04-03 13:29:48 【问题描述】:我正在尝试运行以下查询来检查一堆包含 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 行的字符串缓冲区太小”。
如果我在只有几个模板的小数据集上运行它,它可以工作,但是一旦我在整个 HTML 模板列表上运行它,它就会抛出错误。
我认为该问题与 dbms_lob.substr(data, 4000, 1) 有关,并且可能与由于隐藏字符(或其他原因)超过 4000 字节的子字符串有关,但我不知道如何修复它。
如果我写 dbms_lob.substr(data, 2000, 1) 那么我的子字符串太小了,我会丢失 HTML 文件中的重要数据。如果我让它大于 4000,那么我会立即得到“缓冲区太小”的错误。
有人知道我该如何解决这个问题吗?理想情况下,我想浏览整个“数据”字段,而不仅仅是前 4000 个字符。但是,如果它适用于我的一长串 HTML 文件,前 4000 个字符就可以了。
谢谢
【问题讨论】:
如果在t.data
上不使用dbms_lob.substr
并在外面使用会怎样?
如果您的 HTML 实际上是格式良好的 XML,那么您可以将其解析为 XML,而不是尝试使用正则表达式。
为什么是GROUP BY
?
这段代码似曾相识……***.com/questions/49274050/…
另外,这个问题可能是相关的:***.com/questions/13819551/…
【参考方案1】:
我假设您使用 GROUP BY
来获取不同的值,对吧?在这里使用CONNECT BY
处理大量记录的问题在于它会返回大量重复项。但是GROUP BY
和DISTINCT
不是处理这个问题的正确方法。取出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 发生了什么,但我无法准确重现您的错误。
已编辑
我想我有一个解决办法。请尝试以下方法:
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
在这里比较 CHAR
比比较 CLOB
更好:
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;
希望这会有所帮助。
【讨论】:
嗨,大卫,这解决了问题!这也使我的查询运行得更快,谢谢!您对连接方式的所有假设也是正确的。这主要是由于我对 SQL 的了解有限。感谢您教我一些关于 PRIOR 的新知识。以上是关于PLSQL - 字符串缓冲区太小的主要内容,如果未能解决你的问题,请参考以下文章
执行动态SQL报“字符串缓冲区太小”错误,请问各位高手怎么解决啊