,如果你的源列實際上是一個NCLOB,而不是CLOB你會得到這個錯誤。這是OK:
create table t42 (id number, dt date, post_text clob);
insert into t42 (id, dt, post_text) values (1, sysdate, dbms_random.string('p', 4000));
select id, dbms_lob.substr(post_text, 4000, 1) from t42;
但是這樣的錯誤,只是改變CLOB到NCLOB,任何長度大於2000:
create table t42 (id number, dt date, post_text nclob);
insert into t42 (id, dt, post_text) values (1, sysdate, dbms_random.string('p', 4000));
select id, dbms_lob.substr(post_text, 4000, 1) from t42;
SQL Error: ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 1
這是AL32UTF8和AL16UTF16作爲數據庫和國家字符集。
所以如果你的源表是NCLOB,你只能提取前2000個字符放到你的stream_text
表中。
如果源列是CLOB並且前4000個字符包含任何多字節字符,那麼您還會看到這一點。 dbms_log.substr(x, 4000, 1)
總是獲取CLOB的前4000個字符,該字符可能超過4000個字節 - 這是SQL上下文中VARCHAR2值的最大大小,即使它聲明爲varchar2(4000 char)
,因爲它仍然不能超過4000-字節限制。
如果你想獲得最大的4000個字符了,那麼你可以做到這一點通過PL/SQL VARCHAR2變量,另外還有substrb()
電話:
DECLARE
CURSOR CUR IS
SELECT SEQ$STREAM_TEXT.NEXTVAL AS ID,
T.POST_TEXT,
T.DT AS DT,
'READY' AS STATE,
S.ID AS STREAM_ID
FROM ACTIVITY_EVENT T
LEFT JOIN STREAM S
ON S.OLD_ID = T.ID
WHERE T.POST_TEXT IS NOT NULL;
TMP_TEXT VARCHAR2(4000);
BEGIN
FOR R IN CUR
LOOP
TMP_TEXT := SUBSTRB(DBMS_LOB.SUBSTR(R.POST_TEXT, 4000, 1), 1, 4000);
INSERT INTO STREAM_TEXT (ID, TEXT, DT, STATE, STREAM_ID)
VALUES (R.ID, TMP_TEXT, R.DT, R.STATE, R.STREAM_ID);
END LOOP;
END;
/
的substrb(..., 1, 4000)
部分將無法在SQL工作,要麼,因爲內部表達仍然過大,但它在PL/SQL中起作用。您將獲得前4000個字符的前4000個字節。 (儘管如果第4000個字節是通過多字節字符的中途,您仍然可能會遇到問題)。
我猜對了目標表中的列名,所以很明顯使用真正的列名。如果你有大量的數據,做批量插入會更好;獲取到一個集合中,並使用FORALL來批量插入而不是逐行插入;像這樣的東西可以作爲一個起點:
DECLARE
TYPE TMP_REC_TYPE IS RECORD (
ID STREAM_TEXT.ID%TYPE,
POST_TEXT ACTIVITY_EVENT.POST_TEXT%TYPE,
TEXT STREAM_TEXT.TEXT%TYPE,
DT STREAM_TEXT.DT%TYPE,
STATE STREAM_TEXT.STATE%TYPE,
STREAM_ID STREAM_TEXT.STREAM_ID%TYPE
);
TYPE TMP_REC_TAB_TYPE IS TABLE OF TMP_REC_TYPE;
TMP_REC_TAB TMP_REC_TAB_TYPE;
RC SYS_REFCURSOR;
BEGIN
OPEN RC FOR
SELECT SEQ$STREAM_TEXT.NEXTVAL AS ID,
T.POST_TEXT,
NULL AS TEXT,
T.DT AS DT,
'READY' AS STATE,
S.ID AS STREAM_ID
FROM ACTIVITY_EVENT T
LEFT JOIN STREAM S
ON S.OLD_ID = T.ID
WHERE T.POST_TEXT IS NOT NULL;
LOOP
FETCH RC BULK COLLECT INTO TMP_REC_TAB LIMIT 100;
FOR I IN 1..TMP_REC_TAB.COUNT LOOP -- populate text field
TMP_REC_TAB(I).TEXT := SUBSTRB(
DBMS_LOB.SUBSTR(TMP_REC_TAB(I).POST_TEXT, 4000, 1), 1, 4000);
END LOOP;
FORALL I IN 1..TMP_REC_TAB.COUNT -- bulk insert
INSERT INTO STREAM_TEXT (ID, TEXT, DT, STATE, STREAM_ID)
VALUES (TMP_REC_TAB(I).ID, TMP_REC_TAB(I).TEXT, TMP_REC_TAB(I).DT,
TMP_REC_TAB(I).STATE, TMP_REC_TAB(I).STREAM_ID);
EXIT WHEN RC%NOTFOUND;
END LOOP;
END;
/
請爲涉及的表添加DDL語句。另外,你有沒有嘗試在'INSERT'中添加列列表?在「INSERT」語句中省略列表是不好的做法 - 這將保證將來會導致維護問題。 –
這會失敗,同樣的問題'SELECT t.id,DBMS_LOB.substr(t.post_text,4000,1)FROM ACTIVITY_EVENT t WHERE t.POST_TEXT IS NOT NULL' –
我對請求做了一些改動。我認爲緩衝區大小的問題。但不知道如何清除緩衝區。 –