虽然您正在处理 CLOB 数据类型,但连接会产生 literals(最大长度 32,767 字节),PL/SQL 不允许在 literal 连接期间超出此最大值。
如果TESTLEI 有足够的行,则其中一个连接中V_MESSAGEATT 的长度会超过此限制,您将获得ORA-06502。如果您在块的末尾添加如下异常处理程序,您可以看到这一点:
declare
v_messageatt CLOB;
attachment_text CLOB;
...
... rest of block here ...
...
EXCEPTION WHEN OTHERS THEN
DECLARE
V_ATTACH_ERROR_CHAR_COUNT NUMBER;
BEGIN
V_ATTACH_ERROR_CHAR_COUNT := DBMS_LOB.getlength(V_MESSAGEATT);
DBMS_OUTPUT.PUT_LINE('Failed to build the attachment:' || V_ATTACH_ERROR_CHAR_COUNT);
END;
END;
/
当您运行上述程序时,您应该会收到如下消息,其中包含一个刚刚超过 32767 的数字:
Failed to build the attachment:32804
要允许构建完整的附件,您可以采取措施避免literal concatenation。这是一个使用 CONCAT 的示例。 (但请注意!你也不能DBMS_OUTPUT 一个巨大的CLOB,所以这个例子也捕获了这个异常并让你知道。
首先制作测试数据:
CREATE TABLE TESTLEI (
CUSTID NUMBER,
CUSTNAME VARCHAR2(128),
EMAIL VARCHAR2(128)
);
INSERT INTO TESTLEI SELECT
LEVEL,
'Person' || LEVEL,
'email' || LEVEL || '@email.abc'
FROM DUAL
CONNECT BY LEVEL < 1000;
现在我们有999 行。
现在修改块以仅在小字符串上使用|| 连接。在大字符串上使用CONCAT:
DECLARE
V_MESSAGEATT CLOB;
ATTACHMENT_TEXT CLOB;
V_CHAR_COUNT NUMBER;
CURSOR MAIN_CURSOR IS
SELECT
CUSTID,
CUSTNAME,
EMAIL
FROM TESTLEI;
MAIN_CURSOR_VAR MAIN_CURSOR%ROWTYPE;
BEGIN
OPEN MAIN_CURSOR;
LOOP
FETCH MAIN_CURSOR INTO MAIN_CURSOR_VAR;
EXIT WHEN
(MAIN_CURSOR%NOTFOUND);
IF MAIN_CURSOR%ROWCOUNT = 1
THEN
V_MESSAGEATT := V_MESSAGEATT || '<tr><th>user ID</th><th>USERNAME</th><th>EMAILID</th></tr>';
END IF;
V_MESSAGEATT := CONCAT(V_MESSAGEATT, '<tr>');
V_MESSAGEATT := CONCAT(V_MESSAGEATT, '<td>' || MAIN_CURSOR%ROWCOUNT || '</td>');
V_MESSAGEATT := CONCAT(V_MESSAGEATT, '<td>' || MAIN_CURSOR_VAR.CUSTID || '</td>');
V_MESSAGEATT := CONCAT(V_MESSAGEATT, '<td>' || MAIN_CURSOR_VAR.CUSTNAME || '</td>');
V_MESSAGEATT := CONCAT(V_MESSAGEATT, '<td>' || MAIN_CURSOR_VAR.EMAIL || '</td>');
V_MESSAGEATT := CONCAT(V_MESSAGEATT, '</tr>');
ATTACHMENT_TEXT := V_MESSAGEATT;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Finished building attachment!!');
CLOSE MAIN_CURSOR;
DECLARE
V_PRINT_ERROR_CHAR_COUNT NUMBER;
BEGIN
--The clob is too big to print. This will fail.
DBMS_OUTPUT.put_line(ATTACHMENT_TEXT);
EXCEPTION WHEN OTHERS THEN
V_PRINT_ERROR_CHAR_COUNT := DBMS_LOB.getlength(V_MESSAGEATT);
DBMS_OUTPUT.PUT_LINE('The attachment was too long to print in DBMS_OUTPUT. Length:' || V_PRINT_ERROR_CHAR_COUNT);
END;
EXCEPTION WHEN OTHERS THEN
DECLARE
V_ATTACH_ERROR_CHAR_COUNT NUMBER;
BEGIN
V_ATTACH_ERROR_CHAR_COUNT := DBMS_LOB.getlength(V_MESSAGEATT);
DBMS_OUTPUT.PUT_LINE('Failed to build the attachment:' || V_ATTACH_ERROR_CHAR_COUNT);
END;
END;
/
您不能按原样打印CLOB;如果您真的想打印它,则需要将其分解。但如果你真的打算做一些事情,比如发送到另一个函数,你应该很高兴。
当你运行上面的,你应该得到类似的东西:
Finished building attachment!!
The attachment was too long to print in DBMS_OUTPUT. Length:77548
PL/SQL procedure successfully completed.