首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 呼叫存儲過程完整指南:參數綁定、結果集處理與常見坑點

     編輯:Delphi

前言

TADOStoredProc 是 Delphi 通過 ADO 調用 SQL Server / Oracle / PostgreSQL 等數據庫存儲過程的標準組件。網上範例常忽略參數方向、數據類型映射、結果集與輸出參數共存等細節,導致「參數不存在」「類型不匹配」等錯誤。本文給出生產級調用模板與避坑清單。

組件佈局(設計時)

  1. 放置 TADOConnection (名 ADOConn) 並配置連接字符串。
  2. 放置 TADOStoredProc (名 ADOSP_GetAbove),Connection := ADOConn。
  3. 放置 TDataSource (名 DS_GetAbove),DataSet := ADOSP_GetAbove。
  4. 放置 TDBGrid (名 DBGrid1),DataSource := DS_GetAbove。

運行時調用標準流程

with DataModule1.ADOSP_GetAbove do
begin
  ProcedureName := 'GetAbove';           { 1. 指定過程名 }
  Parameters.Clear;                      { 2. 清舊參數 }

  { 3. 手動建立參數:名稱、類型、方向、長度、默認值 }
  Parameters.CreateParameter('@tableName', ftString, pdInput, 50, 'MyTable');
  Parameters.CreateParameter('@strDate',   ftString, pdInput, 20, '2024-01-01');
  { 輸出參數示例 }
  Parameters.CreateParameter('@RetCode',   ftInteger, pdOutput, 0, 0);
  Parameters.CreateParameter('@RetMsg',    ftString,  pdOutput, 200, '');

  { 4. 賦值輸入參數 }
  Parameters.ParamByName('@tableName').Value := edtTable.Text;
  Parameters.ParamByName('@strDate').Value   := edtDate.Text;

  try
    Open;                                { 5. 返回結果集用 Open }
    { 或 ExecProc 不返回結果集 }
  except
    on E: Exception do
    begin
      ShowMessage('執行失敗: ' + E.Message);
      Exit;
    end;
  end;

  { 6. 讀取輸出參數 }
  ShowMessage(Format('RetCode=%d, RetMsg=%s',
    [Parameters.ParamByName('@RetCode').Value,
     Parameters.ParamByName('@RetMsg').Value]));

  { 7. 綁定網格 (設計時已綁可省略) }
  DBGrid1.DataSource := DataModule1.DS_GetAbove;
end;

關鍵細節深度解析

參數方向常量

常量含義典型用途
pdInput僅輸入WHERE 條件、分頁參數
pdOutput僅輸出返回碼、錯誤信息、新生成 ID
pdInputOutput輸入輸出累計值、雙向數據
pdReturnValue返回值SQL Server RETURN @val

數據類型映射 (ftXxx → SQL 類型)

  • ftString / ftWideString → VARCHAR/NVARCHAR (長度參數必須 ≥ 實際長度)
  • ftInteger / ftSmallint → INT/SMALLINT
  • ftLargeint → BIGINT
  • ftFloat / ftBCD → FLOAT/DECIMAL
  • ftDateTime / ftTimeStamp → DATETIME/DATETIME2
  • ftBlob / ftMemo → VARBINARY(MAX)/NVARCHAR(MAX)
  • ftBoolean → BIT
  • ftGuid → UNIQUEIDENTIFIER

表值參數 (TVP) 傳遞表名/臨時表

SQL Server 2008+ 支援 READONLY 表值參數,Delphi 需構造 TDataSet (如 TClientDataSet) 填充數據,再用 ftDataSet 或 ftCursor 類型參數傳遞。屬進階用法,此處不展開。

結果集與輸出參數共存

Open 返回結果集時,**輸出參數值在結果集關閉前不可讀** (SQL Server 行為)。兩種處理:

  1. 先 Open 讀數據,最後 Close 再讀輸出參數。
  2. 或用 NextRecordSet 跳過結果集直接讀輸出參數 (ADO 2.6+)。

常見錯誤與解決

現象原因解決
「Parameter '@x' not found」參數名大小寫/拼寫錯誤、或未 CreateParameter用 ParamByName 索引,嚴格對應 SP 定義
「Data type mismatch」ftXxx 與 SQL 類型不匹配 (如 ftString 長度不足)核對長度、改用 ftWideString/ftLargeint 等
輸出參數為 Null在 Open 結果集未 Close 前讀取移至 Close 後讀取
「Syntax error near '@tableName'」動態 SQL 拼接表名時未用 QUOTENAME 或參數化失敗表名不可參數化,需白名單驗證後拼接
多結果集只取第一個SP 含多個 SELECT循環 while not EOF do ...; NextRecordSet;

最佳實踐封裝:通用調用函數

type
  TSPParam = record
    Name: string;
    DataType: TFieldType;
    Direction: TParameterDirection;
    Size: Integer;
    Value: Variant;
  end;

function ExecStoredProc(ADOConn: TADOConnection; const SPName: string;
  const InputParams: array of TSPParam; 
  out OutputParams: array of Variant; 
  out DataSet: TADODataSet): Boolean;
var
  SP: TADOStoredProc;
  i: Integer;
begin
  Result := False;
  SP := TADOStoredProc.Create(nil);
  try
    SP.Connection := ADOConn;
    SP.ProcedureName := SPName;
    SP.Parameters.Clear;
    for i := Low(InputParams) to High(InputParams) do
      with InputParams[i] do
        SP.Parameters.CreateParameter(Name, DataType, Direction, Size, Value);
    SP.Open;
    DataSet := TADODataSet.Create(nil);
    DataSet.Connection := ADOConn;
    DataSet.CommandText := SPName;
    DataSet.CommandType := cmdStoredProc;
    DataSet.Open;  { 複製結果集 }
    SetLength(OutputParams, SP.Parameters.Count);
    for i := 0 to SP.Parameters.Count - 1 do
      if SP.Parameters[i].Direction in [pdOutput, pdInputOutput, pdReturnValue] then
        OutputParams[i] := SP.Parameters[i].Value;
    Result := True;
  except
    SP.Free;
    raise;
  end;
end;

總結

掌握 CreateParameter 手動定義、方向/類型精確映射、結果集與輸出參數生命週期協同,即可構建健壯的存儲過程調用層。建議封裝通用 Helper 統一異常處理、日誌記錄、參數驗證,減少業務代碼樣板碼。

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