存儲過程是經編譯後存儲在數據庫中的 T-SQL 代碼塊,接受參數、執行業務邏輯、返回結果。三大核心優勢:
CREATE PROC[EDURE] [schema.]procedure_name [;number]
[ @parameter data_type [ VARYING ] [ = default ] [ OUTPUT ] ] [ ,...n ]
[ WITH { RECOMPILE | ENCRYPTION | RECOMPILE, ENCRYPTION } ]
[ FOR REPLICATION ]
AS sql_statement [ ...n ]
| 選項 | 說明 |
|---|---|
@parameter | 參數名,@ 開頭,最多 2100 個 |
data_type | 任意標量類型;cursor 僅限 OUTPUT 且需 VARYING |
VARYING | 僅用於游標輸出參數,表示結果集動態構造 |
default | 默認值,可為常量或 NULL,支持 LIKE 通配符 |
OUTPUT | 標記為輸出參數,調用端可讀取返回值 |
RECOMPILE | 不緩存計劃,每次重新編譯,適合參數嗅探敏感場景 |
ENCRYPTION | 加密定義文本,防止通過 syscomments 查看 |
FOR REPLICATION | 僅供複製代理調用,不可直接 EXEC |
假設示例表 UserAccount(UserID, UserName, PassWord, RegisterTime, RegisterIP)。
CREATE PROC GetUserAccount AS SELECT * FROM UserAccount;
CREATE PROC InUserAccount AS
INSERT UserAccount(UserName, PassWord, RegisterTime, RegisterIP) VALUES (9,9,'2013-01-02',9);
CREATE PROC InUserAccountRe AS
INSERT UserAccount(...) VALUES (10,10,'2013-01-02',10);
RETURN @@ROWCOUNT;
CREATE PROC GetUserAccountRe
@UserName NCHAR(20),
@UserID INT OUTPUT
AS
IF @UserName > 5 SELECT @UserID = COUNT(*) FROM UserAccount WHERE UserID > 25;
ELSE SET @UserID = 1000;
CREATE PROC GetUserAccountRe1
@UserName NCHAR(20), @UserID INT OUTPUT
AS
IF @UserName > 5 SELECT @UserID = COUNT(*) FROM UserAccount WHERE UserID > 25;
ELSE SET @UserID = 1000;
RETURN @@ROWCOUNT;
CREATE PROC GetUserAccountRe2
@UserName NCHAR(20), @UserID INT OUTPUT
AS
IF @UserName > 5 SELECT @UserID = COUNT(*) FROM UserAccount WHERE UserID > 25;
ELSE SET @UserID = 1000;
SELECT * FROM UserAccount;
RETURN @@ROWCOUNT;
CREATE PROC GetUserAccountRe3 AS
SELECT * FROM UserAccount;
SELECT * FROM UserAccount WHERE UserID > 5;
private SqlCommand CreateCmd(string spName)
{
var cmd = new SqlCommand(spName, _conn) { CommandType = CommandType.StoredProcedure };
return cmd;
}
// 1. 單結果集 → SqlDataAdapter.Fill(DataSet)
public void RunGetUserAccount()
{
using (var da = new SqlDataAdapter(CreateCmd("GetUserAccount")))
{
var ds = new DataSet(); da.Fill(ds); rpt.DataSource = ds; rpt.DataBind();
}
}
// 2. 無參執行 → ExecuteNonQuery
public void RunInUserAccount()
{
using (_conn) { _conn.Open(); lbl.Text = CreateCmd("InUserAccount").ExecuteNonQuery().ToString(); }
}
// 3. 獲取 RETURN 值
public void RunInUserAccountRe()
{
var cmd = CreateCmd("InUserAccountRe");
var pRet = new SqlParameter("rval", SqlDbType.Int) { Direction = ParameterDirection.ReturnValue };
cmd.Parameters.Add(pRet);
_conn.Open(); cmd.ExecuteNonQuery(); _conn.Close();
lbl.Text = $"{pRet.Value}"; // 返回值
}
// 4. 輸入/輸出參數
public void RunGetUserAccountRe()
{
var cmd = CreateCmd("GetUserAccountRe");
cmd.Parameters.AddWithValue("@UserName", "7");
var pOut = new SqlParameter("@UserID", SqlDbType.Int) { Direction = ParameterDirection.Output };
cmd.Parameters.Add(pOut);
_conn.Open(); cmd.ExecuteNonQuery(); _conn.Close();
lbl.Text = pOut.Value.ToString();
}
// 5. RETURN + 輸入 + 輸出
public void RunGetUserAccountRe1()
{
var cmd = CreateCmd("GetUserAccountRe1");
cmd.Parameters.AddWithValue("@UserName", "7");
cmd.Parameters.Add("@UserID", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("rval", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
_conn.Open(); cmd.ExecuteNonQuery(); _conn.Close();
lbl.Text = $"Out:{cmd.Parameters["@UserID"].Value} Ret:{cmd.Parameters["rval"].Value}";
}
// 6. 輸出參數 + 結果集 + RETURN
public void RunGetUserAccountRe2()
{
var cmd = CreateCmd("GetUserAccountRe2");
cmd.Parameters.AddWithValue("@UserName", "7");
cmd.Parameters.Add("@UserID", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.Parameters.Add("rval", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
_conn.Open(); cmd.ExecuteNonQuery();
var ds = new DataSet(); new SqlDataAdapter(cmd).Fill(ds);
rpt.DataSource = ds; rpt.DataBind(); _conn.Close();
lbl.Text = $"Out:{cmd.Parameters["@UserID"].Value} Ret:{cmd.Parameters["rval"].Value}";
}
// 7. 多結果集 → DataSet.Tables[0], Tables[1]...
public void RunGetUserAccountRe3()
{
var ds = new DataSet();
new SqlDataAdapter(CreateCmd("GetUserAccountRe3")).Fill(ds);
rpt1.DataSource = ds.Tables[0].DefaultView; rpt1.DataBind();
rpt2.DataSource = ds.Tables[1].DefaultView; rpt2.DataBind();
}
| 變量 | 含義 |
|---|---|
@@IDENTITY | 最後插入的標識列值(跨表、跨觸發器,慎用) |
SCOPE_IDENTITY() | 當前作用域最後插入的標識值(推薦) |
@@ROWCOUNT | 上條語句影響行數 |
@@ERROR | 上條語句錯誤號(0 為成功) |
@@TRANCOUNT | 當前活動事務嵌套層數 |
@@VERSION | 服務器版本、處理器、安裝日期 |
GETDATE() | 當前系統時間 |
USER_NAME() | 當前登錄用戶名 |
存儲過程是 SQL Server 開發的基石。掌握參數方向(Input/Output/ReturnValue)、結果集處理(DataAdapter/Reader)、事務與錯誤控制,配合 using 模式管理連接生命週期,即可構建高性能、可維護的數據訪問層。