首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

ASP 中存取 Oracle 大字段(CLOB/BLOB)完整解決方案

     編輯:Oracle 資料庫基礎

前言:ADO 與 Oracle 大字段的坑

傳統 ADO 透過 OLE DB/ODBC 訪問 Oracle CLOB/BLOB(>4000 字元)時,常遇到「資料截斷」、「型別不匹配」、「資料流不支援」等問題。本文以 VB6/ASP 為例,示範存儲過程 + PL/SQL 表類型 + ADO Command模式,優雅解決大字段讀寫。

架構設計

  • Oracle 端:Package 封裝 PROCEDURE,使用 TABLE OF VARCHAR2 INDEX BY BINARY_INTEGER 模擬陣列輸出大量文本。
  • ADO 端:CommandType = adCmdText,呼叫 {call pkg.proc(?, {resultset N, cols...})} 語法綁定參數與結果集。
  • 游標位置:CursorLocation = adUseClient 確保支援斷開式記錄集。

Oracle 端完整腳本

-- 1. 建表
DROP TABLE person;
CREATE TABLE person (
    ssn     NUMBER(9) PRIMARY KEY,
    fname   VARCHAR2(15),
    lname   VARCHAR2(20),
    bio     CLOB  -- 大文本欄位
);

INSERT INTO person VALUES (555662222, 'Sam', 'Goodwin', '長文本內容...');
INSERT INTO person VALUES (555882222, 'Kent', 'Clark', '另一段長文本...');
COMMIT;

-- 2. Package Spec
CREATE OR REPLACE PACKAGE pkg_person AS
    TYPE t_ssn   IS TABLE OF NUMBER(10)   INDEX BY BINARY_INTEGER;
    TYPE t_fname IS TABLE OF VARCHAR2(15) INDEX BY BINARY_INTEGER;
    TYPE t_lname IS TABLE OF VARCHAR2(20) INDEX BY BINARY_INTEGER;
    TYPE t_bio   IS TABLE OF CLOB         INDEX BY BINARY_INTEGER;  -- CLOB 陣列
    
    PROCEDURE get_all (ssn OUT t_ssn, fname OUT t_fname, lname OUT t_lname, bio OUT t_bio);
    PROCEDURE get_one (p_ssn IN NUMBER, ssn OUT t_ssn, fname OUT t_fname, lname OUT t_lname, bio OUT t_bio);
END pkg_person;
/

-- 3. Package Body
CREATE OR REPLACE PACKAGE BODY pkg_person AS
    PROCEDURE get_all (ssn OUT t_ssn, fname OUT t_fname, lname OUT t_lname, bio OUT t_bio) IS
        CURSOR c IS SELECT ssn, fname, lname, bio FROM person;
        idx NUMBER := 1;
    BEGIN
        FOR r IN c LOOP
            ssn(idx)   := r.ssn;
            fname(idx) := r.fname;
            lname(idx) := r.lname;
            bio(idx)   := r.bio;  -- 直接賦值 CLOB
            idx := idx + 1;
        END LOOP;
    END;

    PROCEDURE get_one (p_ssn IN NUMBER, ssn OUT t_ssn, fname OUT t_fname, lname OUT t_lname, bio OUT t_bio) IS
        CURSOR c IS SELECT ssn, fname, lname, bio FROM person WHERE ssn = p_ssn;
        idx NUMBER := 1;
    BEGIN
        FOR r IN c LOOP
            ssn(idx)   := r.ssn;
            fname(idx) := r.fname;
            lname(idx) := r.lname;
            bio(idx)   := r.bio;
            idx := idx + 1;
        END LOOP;
    END;
END pkg_person;
/

ASP/VB6 端核心代碼

<%@ Language=VBScript %>
<%
Option Explicit
Dim Cn, Cmd, Rs, ConnStr, SQL

' 連接字串 - 使用 Microsoft ODBC for Oracle 或 Oracle Provider for OLE DB
ConnStr = "Provider=MSDAORA.1;User ID=scott;Password=tiger;Data Source=ORCL;Persist Security Info=False"
' 或: "Driver={Microsoft ODBC for Oracle};Server=ORCL;UID=scott;PWD=tiger;"

Set Cn = Server.CreateObject("ADODB.Connection")
Cn.CursorLocation = 3  ' adUseClient
Cn.Open ConnStr

' 取得所有記錄(含 CLOB)
SQL = "{call pkg_person.get_all({resultset 4, ssn, fname, lname, bio})}"
Set Cmd = Server.CreateObject("ADODB.Command")
With Cmd
    Set .ActiveConnection = Cn
    .CommandText = SQL
    .CommandType = 1  ' adCmdText
End With

Set Rs = Server.CreateObject("ADODB.Recordset")
Rs.CursorType = 3  ' adOpenStatic
Rs.LockType = 1    ' adLockReadOnly
Set Rs.Source = Cmd
Rs.Open

' 讀取 CLOB 欄位(Rs("bio") 直接回傳字串,ADO 自動處理 LOB 讀取)
Do Until Rs.EOF
    Response.Write "SSN: " & Rs("ssn") & "<br>"
    Response.Write "Name: " & Rs("fname") & " " & Rs("lname") & "<br>"
    Response.Write "Bio Length: " & Len(Rs("bio")) & "<br><hr>"
    Rs.MoveNext
Loop

Rs.Close
Cn.Close
Set Rs = Nothing: Set Cmd = Nothing: Set Cn = Nothing
%>

關鍵技術點解析

問題解決方案
CLOB 超過 4000 字元無法直接 SELECTPL/SQL 陣列輸出 + {resultset N, ...} 語法,ADO 將 LOB 當作 LONG VARCHAR 流式讀取
ADO 無法綁定 PL/SQL TABLE 類型使用 Oracle 專屬 {call ... {resultset ...}} 語法,由 OLE DB Provider 解析為多行結果集
游標在關閉連接後失效CursorLocation = adUseClient 建立客戶端游標,數據緩存在本地
寫入 CLOB改用 DBMS_LOB.WRITEAPPEND 或 EMPTY_CLOB() + RETURNING INTO 綁定 adLongVarChar 參數分塊寫入

寫入 CLOB 範例(參數綁定)

SQL = "DECLARE l_clob CLOB; BEGIN " & _
      "  INSERT INTO person(ssn, fname, lname, bio) VALUES (?, ?, ?, EMPTY_CLOB()) " & _
      "  RETURNING bio INTO l_clob; " & _
      "  DBMS_LOB.WRITEAPPEND(l_clob, ?, ?); " & _
      "  COMMIT; END;"

Set Cmd = Server.CreateObject("ADODB.Command")
Cmd.ActiveConnection = Cn
Cmd.CommandText = SQL
Cmd.CommandType = 1

' 參數順序:ssn, fname, lname, length, data
Cmd.Parameters.Append Cmd.CreateParameter("p_ssn", 3, 1, , 999999999)     ' adInteger
Cmd.Parameters.Append Cmd.CreateParameter("p_fname", 200, 1, 20, "New")    ' adVarChar
Cmd.Parameters.Append Cmd.CreateParameter("p_lname", 200, 1, 20, "User")    ' adVarChar
Cmd.Parameters.Append Cmd.CreateParameter("p_len", 3, 1, , Len(longText))   ' adInteger
Cmd.Parameters.Append Cmd.CreateParameter("p_data", 201, 1, Len(longText), longText) ' adLongVarChar

Cmd.Execute

常見錯誤排查

  • 「資料類型不匹配」:確認 Provider 為 MSDAORA 或 OraOLEDB.Oracle,舊版 MSDASQL+ODBC 不支援 LOB 參數綁定。
  • 「操作不支援」:CursorLocation 必須設 adUseClient (3)。
  • CLOB 內容被截斷:檢查 ADO Connection String 是否含 ChunkSize 參數,或改用 GetChunk/AppendChunk 分塊讀寫。
  • 中文亂碼:確保 NLS_LANG 環境變數正確(如 AMERICAN_AMERICA.ZHS16GBK 或 AL32UTF8),資料庫、Client、網頁編碼三統一。

現代化建議

新專案建議改用 Oracle Managed Data Access (ODP.NET Managed Driver) + ASP.NET Core / Entity Framework Core,原生支援 CLOB/BLOB、JSON、XMLType,無需 PL/SQL 陣列繞道,效能與維護性大幅提升。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved