SQL Server 原生無內建「字串首字母大寫」(Title Case) 函數。本文提供一個純 T-SQL 純量函數 fn_toTitleCase,透過啟用 Ole Automation Procedures 建立 MSScriptControl.ScriptControl COM 物件,在 JavaScript 執行環境中使用正則表達式完成轉換,再將結果回傳 SQL Server。
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
安全性警告:啟用 Ole Automation 允許 T-SQL 執行 COM 物件,擴大攻擊面。生產環境請嚴格評估風險,或改用 CLR 整合 (更安全)、應用層處理、或純 T-SQL 實作。
USE tempdb;
GO
IF OBJECT_ID('dbo.fn_toTitleCase', 'FN') IS NOT NULL
DROP FUNCTION dbo.fn_toTitleCase;
GO
CREATE FUNCTION dbo.fn_toTitleCase (@inStr VARCHAR(8000))
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE @str VARCHAR(8000);
DECLARE @object INT;
DECLARE @r VARCHAR(800);
-- 建構 JavaScript 程式碼字串
SET @str = 'var data = "' + @inStr + '"; ' +
'var reg = /\b(\w)|\s(\w)/g; ' +
'data = data.toLowerCase(); ' +
'data.replace(reg, function(m) { return m.toUpperCase(); });';
-- 建立 ScriptControl COM 物件
EXEC sp_OACreate 'MSScriptControl.ScriptControl', @object OUTPUT;
EXEC sp_OASetProperty @object, 'Language', 'javascript';
-- 執行 JS 並取得回傳值
EXEC sp_OAMethod @object, 'eval', @r OUTPUT, @str;
-- 釋放 COM 物件
EXEC sp_OADestroy @object;
RETURN @r;
END
GO
SELECT dbo.fn_toTitleCase('create function fn_toTitleCase(@inStr varchar(8000)) returns varchar(8000)');
輸出結果:
Create Function Fn_Totitlecase(@Instr Varchar(8000)) Returns Varchar(8000)
/\b(\w)|\s(\w)/g 比對:單字開頭字母 (\b\w) 或 空白後字母 (\s\w)toLowerCase() 統一小寫,再 replace() 逐一大寫sp_OAMethod ... 'eval' 在 ScriptControl 執行並取回結果| 方案 | 優點 | 缺點 | 安全性 |
|---|---|---|---|
| 本文 COM 方案 | 程式碼簡短、支援複雜正則 | 需啟用 Ole Automation、效能較差、相容性風險 | 低 |
| CLR 純量函數 | 效能佳、型別安全、受控環境 | 需部署組件、權限設定 (EXTERNAL_ACCESS) | 高 |
| 純 T-SQL 迴圈/遞迴 CTE | 無額外相依、最安全 | 程式碼較長、效能隨字串長度線性增長 | 最高 |
| 應用層 (C#/Java/Python) 處理 | 最靈活、效能最好、易維護 | 需修改應用程式碼 | 最高 |
CREATE FUNCTION dbo.fn_TitleCase_TSQL (@input NVARCHAR(MAX))
RETURNS NVARCHAR(MAX)
AS
BEGIN
DECLARE @result NVARCHAR(MAX) = LOWER(@input);
DECLARE @pos INT = 1;
DECLARE @len INT = LEN(@result);
DECLARE @prevChar NCHAR(1) = ' '; -- 視前一字元為空白,首字元會大寫
WHILE @pos <= @len
BEGIN
DECLARE @currChar NCHAR(1) = SUBSTRING(@result, @pos, 1);
IF @prevChar IN (' ', '-', '_', '.', '''', '(', '[', '{', CHAR(9), CHAR(10), CHAR(13))
SET @result = STUFF(@result, @pos, 1, UPPER(@currChar));
SET @prevChar = @currChar;
SET @pos += 1;
END
RETURN @result;
END