「Developers, Developers, Developers…」
— Steve Ballmer,2000 年 PDC,談 .Net
第 4 章的 AI 能力固然是開發者故事的一大塊,但 SQL Server 2025 給開發者的禮物遠不止於此。本章將帶你看遍 JSON、T-SQL、Change Event Streaming(CES)與內建 REST API 等亮點。
十年來最強的開發者版本#
SQL Server 2016 為開發者帶來 Query Store、JSON 支援、Temporal Tables、PolyBase、In-Memory OLTP 強化、Dynamic Data Masking 等。SQL Server 2016 SP1 更讓 Standard Edition 取得近乎與 Enterprise 一致的 T-SQL 介面。
SQL Server 2025 的開發者亮點:

Figure 5-1: SQL Server 2025 為開發者打造
| 功能 | 說明 |
|---|---|
| Data API Builder(DAB) | 在資料庫前端提供 REST 與 GraphQL 介面 |
| JSON | 原生 json 資料型別、JSON 索引、新 T-SQL 函式 |
| T-SQL | 正規表示式(RegEx)、新函式 |
| Change Event Streaming(CES) | 從交易日誌串流變更事件,CDC 替代方案 |
| REST API | sp_invoke_external_rest_endpoint 直接從引擎呼叫 REST |
| GitHub Copilot for SQL | mssql 擴充套件深度整合 GitHub Copilot |
| mssql-python | Microsoft 自製的全新 Python driver,預計與 SQL Server 2025 GA 同期 |
Data API Builder(DAB)#
DAB 並非 SQL Server 2025 的新概念(前身為 Project Hawaii,2023 年春開放公開預覽),但在 SQL Server 2025 上潛力極大:
- 在 SQL Server 之上提供 REST 或 GraphQL API
- 取代 ODBC、ADO.Net 等 TDS 連線的「plumbing code」
- 可獨立部署,或整合 Azure Static Web Apps、Container Apps、AKS、Web App for Containers
- 文件:
https://aka.ms/dab
Developer Edition 的雙風味#
過去若正式環境使用 Standard Edition,無法以 Developer Edition 完整測試其限制(Developer Edition 等同 Enterprise)。
SQL Server 2025 提供兩種風味:
- 模擬 Enterprise Edition
- 模擬 Standard Edition
開發者不再需要為了「測試 Standard 限制」而消耗一份正式授權。
JSON#
SQL Server 2016 開始支援 JSON,但僅以 nvarchar 文字儲存:
- 文件大時資料庫膨脹
- 任何更新都要重寫整段文字
- 必須先用
ISJSON()驗證 - 索引只能建在文字型別欄位上
Microsoft Mechanics 主持人 Jeremy Chapman 形容 SQL Server 2025 的新 JSON:「relational database 裡的 NoSQL database」。
原生 json 資料型別#
優點:
- 更快讀取:文件已經解析
- 更快寫入:可只更新單一值,不必重寫整份文件
- 更省空間:壓縮最佳化(MVP Daniel Hutmacher 的測試顯示節省約 50%)
- 既有程式碼相容
- 內部使用 LOB 結構,每筆最大 2GB
- 強制有效 JSON:插入無效 JSON 會直接報錯(
Msg 13609) - 支援
modify直接更新內部單一值
JSON 索引#
- 採用類似 XML 索引的結構(非傳統 B-tree)
- 可用
CREATE JSON INDEX建立在整欄或某個 JSON 路徑(path) JSON_PATH、JSON_VALUE、JSON_CONTAINS等可受惠
新 T-SQL 函式#
JSON_ARRAYAGG:把多列彙總成單一 JSON 陣列JSON_OBJECTAGG:以 key/value 對輸出 JSONJSON_CONTAINS:路徑搜尋(含巢狀陣列)
範例:使用 json 資料型別#
USE orders;
-- 取出單一 JSON 值
SELECT o.order_id,
JSON_VALUE(o.order_info, '$.AccountNumber') AS account_number
FROM dbo.Orders o;
-- 把所有列彙總成單一 JSON 陣列
SELECT JSON_ARRAYAGG(o.order_info)
FROM dbo.Orders o;
-- 以 key/value 對輸出
SELECT JSON_OBJECTAGG(o.order_id : o.order_info)
FROM dbo.Orders o;
-- 直接修改 JSON 內部值,不必整列重寫
UPDATE dbo.Orders
SET order_info.modify('$.Quantity', 2)
WHERE order_id = 1;
Figure 5-2: 取出單一 JSON 值並以結果集回傳

Figure 5-3: 把所有列以 JSON 形式輸出

Figure 5-4: 將所有列彙總為單一 JSON 文件

Figure 5-5: 以 key/value 對輸出 JSON
範例:JSON 索引#
USE contactsdb;
-- 巢狀陣列搜尋(無索引時是 scan)
SELECT JSON_VALUE(jdoc, '$.name') AS name,
JSON_QUERY(jdoc, '$.tags') AS tags
FROM contacts
WHERE JSON_CONTAINS(jdoc, 'fitness', '$.tags[*]') = 1;
-- 建立 JSON 索引
DROP INDEX IF EXISTS [ji_contacts] ON contacts;
CREATE JSON INDEX ji_contacts ON contacts(jdoc) FOR ('$');
Figure 5-6: 從資料表中擷取 JSON 值

Figure 5-7: 不使用 JSON 索引時於資料表搜尋值

Figure 5-8: 使用 JSON 索引的執行計畫
JSON 索引支援壓縮等選項。完整語法見
https://learn.microsoft.com/sql/t-sql/statements/create-json-index-transact-sql。
T-SQL 強化#
正規表示式(Regular Expressions, RegEx)#
SQL Server 2025(dbcompat 170)終於支援 RegEx,遵循 POSIX 標準。
| 函式 | 對應傳統做法 |
|---|---|
REGEXP_LIKE | 取代 LIKE |
REGEXP_REPLACE | 強化版 REPLACE |
REGEXP_SUBSTR | 強化版 SUBSTRING |
REGEXP_INSTR | 結合 CHARINDEX + PATINDEX |
REGEXP_COUNT | 結合 LEN + REPLACE |
REGEXP_MATCHES | 回傳所有符合的 substring(資料表) |
REGEXP_SPLIT_TO_TABLE | 以 RegEx 切字成資料表 |
範例:CHECK constraint 用 RegEx 驗證 email 與電話#
CHECK (REGEXP_LIKE(Email, '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'))
CHECK (REGEXP_LIKE(PhoneNumber,
'^(?:\+\d{1,3}[ -]?)?(?:\([2-9]\d{2}\)[ -]?\d{3}-\d{4}|[2-9]\d{2}[ -]?\d{3}-\d{4})$'))複雜的 email/phone 驗證,傳統 LIKE 幾乎做不到,現在一行 RegEx 搞定。
範例:複雜搜尋#
-- 找 .org 結尾、local part 含 .will + 至少 3 個英文字母的 email
SELECT [Name], Email
FROM dbo.EMPLOYEES
WHERE REGEXP_LIKE(LOWER(Email), '^[^@]*\.will[a-z]{3,}@[a-z0-9.-]+\.org$');其他 T-SQL 強化#
| 函式 / 功能 | 說明 |
|---|---|
PRODUCT() | 數值乘積彙總,取代 EXP(SUM(LOG(...))) 的繞遠路;支援 batch mode、忽略 NULL、OVER 子句 |
BASE64_ENCODE / BASE64_DECODE | 內建 Base64 編碼(依 RFC 4648 §4) |
EDIT_DISTANCE、EDIT_DISTANCE_SIMILARITY | Fuzzy string 比對(編輯距離) |
JARO_WINKLER_DISTANCE、JARO_WINKLER_SIMILARITY | Fuzzy 比對的 de facto 標準(GA 後可能仍需 PREVIEW_FEATURES) |
CURRENT_DATE | ANSI 標準的當天日期函式 |
SUBSTRING | length 改為選填(符合 ANSI) |
UNISTR | 處理多重 Unicode 跳脫序列,方便插入 emoji 等字元 |
|| | ANSI 字串串接運算子,等同 + 與 CONCAT |
DATEADD | 第二個 number 參數支援 bigint |
-- PRODUCT
SELECT GroupId, PRODUCT(Value) AS ProductOfValues
FROM MyTable
GROUP BY GroupId;
-- UNISTR:插入 emoji
SELECT UNISTR(N'Hello \\+1F603');適用情境:複利、機率、良率、幾何平均等。把運算放在 T-SQL,比在應用程式做更快。
Change Event Streaming(CES)#
CDC、CT 與 CES 的差異#
| 功能 | 取得變更方式 | 傳輸 | 主要痛點 |
|---|---|---|---|
| Change Tracking(CT) | 系統表記錄哪些列變更(無資料歷程) | 應用程式查詢 | — |
| Change Data Capture(CDC) | LogReader Agent job 寫到系統表 | 應用程式查詢 | 仰賴 Agent、清理 job、I/O 雙倍、寫入產生額外 log |
| Change Event Streaming(CES) | 背景 worker 直接讀 transaction log | 推送(push) 到 Azure Event Hub | 需 PREVIEW_FEATURES |
運作方式#
CES 重用 Synapse Link(SQL Server 2022)的引擎元件。啟用後可看到
wait_type = SYNAPSE_LINK_COMMIT的背景 worker。worker 採池化(pool)設計,多資料庫啟用 CES 不會耗盡 worker pool。
- 以 per-database 為單位
- 目前唯一支援的目的端是 Azure Event Hub
- Synapse Link 是把變更落到 Azure Storage Landing Zone;CES 則直接 stream HTTP 到 Event Hub
- 訊息採 CloudEvents 標準(CNCF 規格)
- 兩種傳輸協定:AMQP(Event Hubs 標準)或 Kafka(Apache Kafka on Event Hubs 相容端點)
訊息格式#
- INSERT → 新列
- UPDATE → 舊列 + 新列
- DELETE → 被刪的列
- 訊息自描述 schema——包含資料庫、資料表、欄位定義,可以建構通用處理系統
限制與注意事項#
重要限制:
- 必須啟用
PREVIEW_FEATURES- CES 會延後 log truncation——log record 無法在訊息成功送達 Event Hub 前截斷;但如果應用消費端慢,不會影響 truncation
- 不能與下列共存:Fabric Mirroring、Transactional Replication、CDC、Synapse Link
- Change Tracking(CT)可與 CES 共存
- 啟用 CES 的表 不能 TRUNCATE
- DDL 可變更,但不會發出 DDL 訊息,後續訊息會反映 schema 變更
- 沒有初始 snapshot——如需要,由開發者自行處理
範例:Contoso 出貨問題(CES + Azure Function + AI Agent)#
這個範例需要:
- Azure 訂閱(不能用免費)
- Azure Event Hub、Azure Function App、Azure AI Foundry 中的 AI Agent
- SQL Server 2025 Developer/Enterprise Edition(混合模式驗證 + sysadmin 登入)
- VSCode 用以執行 Azure Function
流程#
flowchart LR
A["SQL Server 2025\nOrders 資料表"] -- "INSERT" --> B["CES"]
B -- "CloudEvents" --> C["Azure Event Hub"]
C --> D["Azure Function"]
D -- "判定預估出貨日 > 30 天" --> E["Azure AI Agent\n(gpt-4.5-preview)"]
E -- "建議的解決方案" --> D
D -- "更新客戶/物流" --> F["後續處理"]
Figure 5-9: 使用 CES 解決出貨問題
啟用 CES#
-- 1. 建立資料庫、啟用 PREVIEW_FEATURES、建立 DATABASE SCOPED CREDENTIAL
USE [ContosoOrders];
-- 2. 啟用 CES
EXEC sys.sp_enable_event_stream;
-- 3. 建立 stream group 並加入資料表(指向 Azure Event Hub)
-- 4. 檢查設定
EXEC sys.sp_help_change_feed;
EXEC sys.sp_help_change_feed_table @source_schema = 'dbo', @source_name = 'Orders';監視訊息#
SELECT * FROM sys.dm_change_feed_log_scan_sessions
ORDER BY start_time DESC;
Figure 5-10: 在 Data Explorer 中檢視來自 CES 的測試訊息
看到
error_count > 0時,查sys.dm_change_feed_errors取得錯誤細節。
Azure Function 程式片段(C#)#
public async Task Run(
[EventHubTrigger("<AEH>", Connection = "<AEHspace>_<policy>_EVENTHUB")]
EventData[] events)
{
// 解析 CES 訊息
if (DateTime.TryParse(currentRow["SalesDate"]?.ToString(), out DateTime salesDate)
&& DateTime.TryParse(currentRow["EstimatedShipDate"]?.ToString(), out DateTime estShip))
{
if ((estShip - salesDate).TotalDays > 30)
{
await CheckShipment(currentRow); // 呼叫 AI Agent
}
}
}AI Agent 的 system instruction:「分析 Contoso 訂單的出貨資訊,評估是否需要尋找替代方案以加速延遲的出貨。」
下達一筆 75 天才出貨的訂單,AI Agent 會自動回傳處理建議。

Figure 5-11: 出貨案例 AI 協助的結果
CES 將是開發者建構事件驅動架構的未來;Fabric Mirroring 偏向多數使用者的預設選擇。後續路線圖包括 Kafka 等更多目的端。
REST API:sp_invoke_external_rest_endpoint#
起源:Project Solaria#

Figure 5-12: Project Solaria 私人預覽
2022 年的 Project Solaria 原本針對 Azure Functions,後來擴展為「在 SQL Server 引擎內透過 HTTPS 呼叫任意 REST 端點」。命名靈感來自 Asimov 的小說《The Naked Sun》中的 Solaria 行星——當時在 SQL 中支援 REST 被視為「異端傳統」。
安全性#
安全前提:
- 必須先啟用
external rest endpoint enabled伺服器設定- 使用者需
EXECUTE ANY EXTERNAL ENDPOINT權限(預設只有 sysadmin)- 必須 HTTPS——所有流量以 TLS 加密
預設是「關」的;不需要額外的「關閉開關」。
語法#
EXECUTE @returnValue = sp_invoke_external_rest_endpoint
[ @url = ] N'url'
[ , [ @payload = ] N'request_payload' ]
[ , [ @headers = ] N'http_headers_as_json_array' ]
[ , [ @method = ] 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' ]
[ , [ @timeout = ] seconds ]
[ , [ @credential = ] credential ]
[ , @response OUTPUT ]
[ , [ @retry_count = ] # of retries if there are errors ]重要參數#
- URL:HTTPS endpoint
- Method:預設
POST - Headers:metadata;SQL Server 一律自動注入
content-type: application/json; charset=utf-8、accept: application/json、user-agent: <EDITION>/<VERSION> - Payload:JSON / XML / 文字
- Response:
OUTPUT參數(NVARCHAR(MAX)) - Credential:
DATABASE SCOPED CREDENTIAL,可為 API key 或 Managed Identity;用IDENTITY = 'HTTPEndpointHeaders'把值塞進 headers
引擎行為#
引擎細節:
- 同步呼叫;T-SQL 須等待 REST 服務回應
- SQL worker thread 以 preemptive 模式執行,避免阻塞 SQLOS scheduler
- 並發上限:150 個 worker thread 或 10% 的 max worker threads——超過會出
Msg 10928wait_type = HTTP_EXTERNAL_CONNECTION
回傳值#
- 0:HTTPS 成功(HTTP 2xx)
- 非 0:HTTP 狀態碼
- HTTPS 連線本身失敗:拋例外
Msg 11558:REST 回傳的 JSON 無法被解析
社群應用範例#
| 作者 | 場景 |
|---|---|
| Anthony Nocentino(Pure Storage MVP) | Pure Storage REST API + SQL snapshot 備份目錄 |
| Anthony Nocentino + Andy Yun | Pure Storage I/O 指標 + SQL Server 端到端效能監控 |
| Andrew Pruski | 從 SQL Server 內存取 Kubernetes API |
範例:用 REST API 完成 RAG 故事#

Figure 5-13: 為 RAG 加入向量搜尋
延續第 4 章的向量搜尋,再呼叫 chat completion 模型分析結果。
-- STEP 1: 把向量搜尋結果存入暫存表
DROP TABLE IF EXISTS #ProcResult;
CREATE TABLE #ProcResult
(
ProductName NVARCHAR(200) NULL,
ProductDescription NVARCHAR(MAX) NULL,
StockLevel INT NULL
);
INSERT INTO #ProcResult (ProductName, ProductDescription, StockLevel)
EXEC find_relevant_products_vector_search
@prompt = N'Show me stuff for extreme outdoor sports',
@stock = 100,
@top = 20;
-- STEP 2: 把結果格式化成 JSON
DECLARE @resultSetJson NVARCHAR(MAX);
SELECT @resultSetJson =
(
SELECT ProductName, ProductDescription
FROM #ProcResult
FOR JSON PATH, INCLUDE_NULL_VALUES
);
-- STEP 3: 組裝 chat completion 的 payload
DECLARE @escapedJson NVARCHAR(MAX) = STRING_ESCAPE(@resultSetJson, 'json');
DECLARE @url NVARCHAR(MAX) = N'https://<azureai>/openai/deployments/gpt-4o/chat/completions?api-version=2025-01-01-preview';
DECLARE @credential NVARCHAR(4000) = N'https://<azureai>.openai.azure.com';
DECLARE @userPrompt NVARCHAR(MAX) = N'Are these good products for someone who is an extreme sports enthusiast. Anything missing?';
DECLARE @payload NVARCHAR(MAX) =
N'{
"messages": [
{ "role": "system", "content": "You are a helpful assistant that analyzes small SQL result sets about products from an outdoor sports company. Be concise, structured, and actionable." },
{ "role": "user", "content": "' + @userPrompt + '"},
{ "role": "user", "content": "' + @escapedJson + '"}
],
"temperature": 0.7
}';
-- STEP 4: 呼叫 chat completion 模型
DECLARE @statusCode INT, @response NVARCHAR(MAX);
EXEC @statusCode = sp_invoke_external_rest_endpoint
@url = @url,
@method = N'POST',
@payload = @payload,
@credential = @credential,
@response = @response OUTPUT,
@timeout = 120;
-- STEP 5: 取出回應內容
SELECT c.content
FROM OPENJSON(@response, '$.result.choices')
WITH ( content NVARCHAR(MAX) '$.message.content' ) AS c;
Figure 5-14: 於 Azure AI Foundry 取得 AI 模型的端點
常見錯誤:
- HTTP 429:「Requests to the OpenAI API have been throttled. Please retry after some time.」需要增加資源或加上延遲
- HTTP 400:payload 格式錯誤,
@response會帶詳細錯誤模型回應仍是 JSON 結構,需用
OPENJSON取出$.message.content。
模型實際回傳的內容會分析產品適合度、缺口(缺少安全護具、特殊配件、服飾、其他極限運動裝備、維修工具)並給出強化建議——全部在 T-SQL 與 SQL Server 安全邊界內完成。
現代的 SQL 開發者#
SQL 開發者回來了。把半結構化文件交給原生 JSON、把 RegEx 留在 T-SQL、用 CES 建構事件驅動架構,再用 sp_invoke_external_rest_endpoint 串接地端或雲端 REST 服務(含 chat completion 模型);結合第 4 章的向量搜尋,便能打造現代資料應用平台。
- 開發者最新動態:
https://aka.ms/sqldev - Azure SQL Devs’ Corner:
https://devblogs.microsoft.com/azure-sql
下一章將進入 Azure Arc,把 SQL Server 與雲端連結起來。