預存程序 是儲存在資料庫中、經預先編譯的一組 T-SQL 陳述式集合,類似應用程式中的「方法」或「函式」。它接受輸入參數、執行邏輯、可傳回輸出參數或傳回值,並能將結果集直接回傳給呼叫端。
EXEC proc_name params,而非冗長的 T-SQL 批次。EXECUTE 權限,無需直接 SELECT/INSERT/UPDATE/DELETE 資料表權限,實現資料存取控制。| 類型 | 前綴 | 說明 |
|---|---|---|
| 系統預存程序 | sp_ / xp_ | 儲存於 master,所有資料庫可呼叫,管理用 |
| 擴展預存程序 | xp_ | 呼叫外部 DLL (C/C++),如 xp_cmdshell,安全風險高 |
| 使用者自訂預存程序 | 自訂 (建議 usp_ / proc_) | 業務邏輯核心,本文重點 |
EXEC sp_databases; -- 列出所有資料庫
EXEC sp_tables; -- 列出所有資料表
EXEC sp_columns 'student'; -- 列出資料表欄位
EXEC sp_helpindex 'student'; -- 列出索引
EXEC sp_helpconstraint 'student'; -- 列出約束
EXEC sp_helptext 'sp_who'; -- 查看預存程序原始碼
EXEC sp_rename 'student', 'stuInfo'; -- 重新命名資料表
EXEC sp_renamedb 'oldDB', 'newDB'; -- 重新命名資料庫
EXEC sp_helpdb; -- 資料庫資訊摘要
EXEC sp_helpdb 'master'; -- 指定資料庫詳細資訊
CREATE PROC[EDURE] [schema.]procedure_name
@param1 datatype [= default] [OUTPUT],
@param2 datatype [= default] [OUTPUT],
...
AS
BEGIN
SET NOCOUNT ON; -- 抑制「受影響的資料列數」訊息,提升效能
-- T-SQL 陳述式
SELECT ...
INSERT ...
UPDATE ...
DELETE ...
-- 設定輸出參數
@output_param = @internal_var
END
GO
CREATE PROCEDURE usp_GetAllOffices
AS
BEGIN
SET NOCOUNT ON;
SELECT OfficeID, OfficeName FROM dbo.Office_Info;
END
GO
-- 呼叫
EXEC usp_GetAllOffices;
CREATE PROCEDURE usp_GetOfficeById
@OfficeID INT
AS
BEGIN
SET NOCOUNT ON;
SELECT OfficeName FROM dbo.Office_Info WHERE OfficeID = @OfficeID;
END
GO
-- 呼叫 (位置對應)
EXEC usp_GetOfficeById 2;
-- 或具名呼叫 (建議,順序不拘)
EXEC usp_GetOfficeById @OfficeID = 2;
CREATE PROCEDURE usp_GetOfficeNameById
@OfficeID INT,
@OfficeName NVARCHAR(100) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT @OfficeName = OfficeName FROM dbo.Office_Info WHERE OfficeID = @OfficeID;
END
GO
-- 呼叫 (必須宣告變數接收)
DECLARE @Name NVARCHAR(100);
EXEC usp_GetOfficeNameById @OfficeID = 4, @OfficeName = @Name OUTPUT;
SELECT @Name AS OfficeName;
CREATE PROCEDURE usp_CheckOfficeExists
@OfficeID INT
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT 1 FROM dbo.Office_Info WHERE OfficeID = @OfficeID)
RETURN 1; -- 存在
ELSE
RETURN -1; -- 不存在
END
GO
-- 呼叫 (用變數接收 RETURN 值)
DECLARE @Ret INT;
EXEC @Ret = usp_CheckOfficeExists @OfficeID = 2;
PRINT @Ret; -- 1 或 -1
usp_ (User Stored Procedure) 或 proc_,避免 sp_ (系統保留,會先去 master 找,效能稍差)。usp_GetCustomerOrders。CREATE PROCEDURE usp_DynamicSearch
@TableName SYSNAME, -- 白名單驗證後再用
@ColName SYSNAME,
@Value NVARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
DECLARE @sql NVARCHAR(MAX);
-- 簡易白名單防注入
IF @TableName NOT IN (N'Orders', N'Customers') OR @ColName NOT IN (N'CustID', N'OrderID')
THROW 50001, 'Invalid object name', 1;
SET @sql = N'SELECT * FROM ' + QUOTENAME(@TableName) + N' WHERE ' + QUOTENAME(@ColName) + N' = @val;';
EXEC sp_executesql @sql, N'@val NVARCHAR(100)', @val = @Value;
END
CREATE PROCEDURE usp_TransferFunds
@FromAcc INT, @ToAcc INT, @Amount MONEY
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION;
UPDATE Accounts SET Balance -= @Amount WHERE AccID = @FromAcc;
UPDATE Accounts SET Balance += @Amount WHERE AccID = @ToAcc;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
THROW; -- 重新拋出錯誤給呼叫端
END CATCH
END
Ctrl+M 開啟實際執行計畫,或使用 SET STATISTICS IO, TIME ON。OPTION (RECOMPILE) 或使用區域變數指派參數值。SELECT OBJECT_NAME(object_id) AS ProcName, execution_count, total_elapsed_time/execution_count AS avg_elapsed_ms
FROM sys.dm_exec_procedure_stats
WHERE database_id = DB_ID()
ORDER BY avg_elapsed_ms DESC;
預存程序是 SQL Server 開發的基石。善用 輸入/輸出參數、傳回值、結果集 三種回傳機制,配合 SET NOCOUNT ON、TRY...CATCH、sp_executesql 參數化動態 SQL,即能建構高效能、安全、可維護的資料存取層。