需要在 Delphi 中計算字串形式的數學運算式 (如 '123+34*11'、'SQRT(POWER(2,10))')?無需撰寫解析器或引入腳本引擎,利用 ADO 的 SELECT <運算式> 特性,讓資料庫引擎替你算好。本文展示這個「另類」且實用的技巧。
大多數 SQL 資料庫 (Access、SQL Server、SQLite、Firebird、Oracle、PostgreSQL) 允許 SELECT 後直接跟純量運算式,不需 FROM 子句。ADO TADOQuery 執行後,結果集第一欄即為運算結果。
uses ADODB;
function EvalExpression(const Expr: string; ADOConn: TADOConnection): Variant;
var
Qry: TADOQuery;
begin
Qry := TADOQuery.Create(nil);
try
Qry.Connection := ADOConn;
Qry.SQL.Text := 'SELECT ' + Expr; // 直接拼接運算式
Qry.Open;
if not Qry.IsEmpty then
Result := Qry.Fields[0].Value
else
Result := Null;
finally
Qry.Free;
end;
end;
// 使用範例
var
Conn: TADOConnection;
Val: Variant;
begin
Conn := TADOConnection.Create(nil);
try
Conn.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Test.mdb;';
Conn.LoginPrompt := False;
Conn.Open;
Val := EvalExpression('123+34*11', Conn); // 497
Val := EvalExpression('SQRT(144)', Conn); // 12 (Access 函數)
Val := EvalExpression('IIF(1>0, "Yes", "No")', Conn); // "Yes" (Access 立即函數)
finally
Conn.Free;
end;
end;
| 類別 | 範例 | 備註 |
|---|---|---|
| 算術運算 | 123+34*11, (5+3)*2 | 標準運算子優先序 |
| 數學函數 | SQRT(16), LOG(10), SIN(PI()/2) | 依資料庫引擎支援度 |
| 字串函數 | UCASE('hello'), LEFT('abcde',3) | Access: UCASE/LEFT/MID/LEN |
| 日期時間 | DATE(), DATEADD('d',7,NOW()) | Access: DATE/NOW/DATEADD |
| 條件邏輯 | IIF(Score>=60,'Pass','Fail') | Access 專有 IIF |
| 轉換函數 | CINT('123'), CDBL(3.14) | Access: CINT/CDBL/CCUR |
若內建函數不足,可在資料庫端定義使用者自訂函數 (UDF):
' Access VBA 模組
Public Function MyFactorial(ByVal n As Long) As Double
Dim i As Long, r As Double
r = 1
For i = 2 To n: r = r * i: Next
MyFactorial = r
End Function
// Delphi 呼叫
Val := EvalExpression('MyFactorial(5)', Conn); // 120
| 面向 | 分析 | 建議 |
|---|---|---|
| 效能 | 每次呼叫需 Round-trip 到資料庫引擎,約 1-5ms | 批次計算時用單一 Query 多行 UNION ALL SELECT ...;高頻計算改用本地解析器 |
| SQL 注入 | 直接拼接使用者輸入極度危險 | 嚴格驗證輸入字元集 (僅允許數字、運算子、函數名白名單);或使用參數化查詢 (但運算式本身難參數化) |
| 資料庫相依 | 函數名、語法因引擎而異 | 封裝介面隔離引擎差異;單元測試覆蓋目標資料庫 |
| 連線開銷 | 頻繁開關連線慢 | 共用長連線 TADOConnection;連線池 |
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| ADO SELECT (本文) | 零程式碼解析、支援資料庫函數、利用現有連線 | 需資料庫連線、效能較低、注入風險 | 報表運算式、動態公式配置、偶發計算 |
| Expression Evaluator 元件 (如 EvalExpress) | 純本地、高效能、語法可控 | 需第三方元件、函數庫有限 | 即時試算表、規則引擎 |
| Pascal Script / DWScript | 完整腳本語言、支援變數/流程控制 | 整合複雜、體積大 | 使用者自訂邏輯、插件系統 |
| 自寫遞迴下降解析器 | 完全控制、無依賴 | 開發成本高、易出錯 | 教學、極簡專案 |
「用資料庫算數學」是一個巧妙的 Side-effect 應用。在已有 ADO 連線的專案中,臨時需要計算動態運算式時,這招能立即解決問題。但請記住:嚴格輸入驗證與效能評估是上線前必做功課。對於核心業務高頻計算,請投資正規解析器或腳本引擎。