ストアド プロシージャの作成 (データベース エンジン)
ストアド プロシージャの作成には、Transact-SQL ステートメントの CREATE PROCEDURE を使用します。
ストアド プロシージャを作成する前に、次の点に注意してください。
CREATE PROCEDURE ステートメントは、1 つのバッチ内で他の SQL ステートメントと組み合わせて使用することはできません。
プロシージャを作成するには、データベースに対して CREATE PROCEDURE 権限、プロシージャが作成されるスキーマに対して ALTER 権限を所持している必要があります。CLR ストアド プロシージャの場合は、<method_specifier> で参照されるアセンブリを所有しているか、そのアセンブリの REFERENCES 権限を所持している必要があります。
ストアド プロシージャはスキーマ スコープが設定されたオブジェクトで、その名前は識別子の規則に従う必要があります。
ストアド プロシージャは現在のデータベースにのみ作成することができます。
ストアド プロシージャを作成する場合、次の事項を指定する必要があります。
任意の入力パラメーターと、呼び出し側のプロシージャまたはバッチへの出力パラメーター。
他のプロシージャの呼び出しなど、データベース内での処理を実行するプログラミング ステートメント。
呼び出し側のプロシージャまたはバッチに返され、成功、失敗、および失敗の原因を示すステータス値。
発生する可能性のあるエラーをキャッチし、処理するために必要なエラー処理ステートメント。
ERROR_LINE や ERROR_PROCEDURE などのエラー処理関数を、ストアド プロシージャで指定できます。詳細については、「Transact-SQL での TRY...CATCH の使用」を参照してください。
ストアド プロシージャの命名
sp_ をプレフィックスに使用してストアド プロシージャを作成しないことをお勧めします。SQL Server では、システム ストアド プロシージャを指定するために sp_ プレフィックスを使用しています。選択した名前が、今後のシステム プロシージャと競合する可能性があります。アプリケーションでスキーマ以外の修飾名参照が使用されていて、独自のプロシージャ名がシステム プロシージャ名と競合していると、その名前は独自のプロシージャではなく、システム プロシージャにバインドされるので、アプリケーションの機能が停止することになります。
システム ストアド プロシージャと同じ名前のユーザー定義のストアド プロシージャ、および修飾されていないか、dbo スキーマにあるユーザー定義ストアド プロシージャは実行されません。システム ストアド プロシージャが代わりに実行されます。次の例でその動作を示します。
USE AdventureWorks2008R2;
GO
CREATE PROCEDURE dbo.sp_who
AS
SELECT FirstName, LastName FROM Person.Person;
GO
EXEC sp_who;
EXEC dbo.sp_who;
GO
DROP PROCEDURE dbo.sp_who;
GO
明示的なスキーマ修飾子を使用することで、わずかにパフォーマンスも向上します。データベース エンジンが複数のスキーマを検索してプロシージャを見つける必要がない場合は、名前の解決が若干速くなります。詳細については、「ストアド プロシージャの実行」を参照してください。
一時ストアド プロシージャ
プライベート一時ストアド プロシージャとグローバル一時ストアド プロシージャは、一時テーブルと同様に、プロシージャ名にプレフィックスとして # と ## を付けて作成できます。# は、ローカル一時ストアド プロシージャを表します。## は、グローバル一時ストアド プロシージャを表します。一時ストアド プロシージャは、SQL Server がシャットダウンされるまで存在します。
一時ストアド プロシージャは、Transact-SQL ステートメントやバッチの実行プランの再利用をサポートしていない、旧バージョンの SQL Server に接続する際に便利です。SQL Server 2000 以降に接続するアプリケーションでは、一時ストアド プロシージャの代わりにシステム ストアド プロシージャ sp_executesql を使用する必要があります。ローカル一時プロシージャを実行できるのは、そのプロシージャを作成した接続のみです。接続が閉じられると、ローカル一時プロシージャは自動的に削除されます。
グローバル一時ストアド プロシージャは、すべての接続で実行できます。グローバル一時ストアド プロシージャは、そのプロシージャを作成したユーザーが使用していた接続が閉じられ、他のすべての接続で現在実行中の同じバージョンのプロシージャが完了するまで存在します。プロシージャの作成に使用した接続が閉じられると、それ以降はそのグローバル一時ストアド プロシージャを実行することはできなくなります。既にプロシージャの実行を開始している接続だけは、そのストアド プロシージャの実行を完了させることができます。
プレフィックスとして # または ## が付いていないストアド プロシージャを tempdb データベースに直接作成した場合、そのストアド プロシージャは、SQL Server がシャットダウンされたときに自動的に削除されます。これは、SQL Server を起動するたびに tempdb が作成し直されるためです。tempdb に直接作成したプロシージャは、接続の作成が終了した後も存在します。
注 |
---|
一時ストアド プロシージャを過剰に使用すると、tempdb のシステム テーブルで競合が発生し、パフォーマンスに影響することがあります。代わりに sp_executesql を使用することをお勧めします。sp_executesql はシステム テーブルにデータを保存しないので、この問題は発生しません。 |
CLR ストアド プロシージャを一時ストアド プロシージャとして作成することはできません。
例
A. 単純なプロシージャと複雑な SELECT の併用
次のストアド プロシージャは、ビューからすべての従業員 (フルネーム)、役職名、部署名を返します。このストアド プロシージャはパラメーターをまったく使用しません。
USE AdventureWorks2008R2;
GO
IF OBJECT_ID ( 'HumanResources.uspGetAllEmployees', 'P' ) IS NOT NULL
DROP PROCEDURE HumanResources.uspGetAllEmployees;
GO
CREATE PROCEDURE HumanResources.uspGetAllEmployees
AS
SET NOCOUNT ON;
SELECT LastName, FirstName, Department
FROM HumanResources.vEmployeeDepartmentHistory;
GO
ストアド プロシージャ uspGetEmployees は次のように実行されます。
EXECUTE HumanResources.uspGetAllEmployees;
GO
-- Or
EXEC HumanResources.uspGetAllEmployees;
GO
-- Or, if this procedure is the first statement within a batch:
HumanResources.uspGetAllEmployees;
B. パラメーターを指定した単純なプロシージャの使用
次のストアド プロシージャは、指定した従業員 (フルネーム)、役職名、部署名のみをビューから返します。このストアド プロシージャは、渡されたパラメーターと完全に一致するものを受け入れます。
USE AdventureWorks2008R2;
GO
IF OBJECT_ID ( 'HumanResources.uspGetEmployees', 'P' ) IS NOT NULL
DROP PROCEDURE HumanResources.uspGetEmployees;
GO
CREATE PROCEDURE HumanResources.uspGetEmployees
@LastName nvarchar(50),
@FirstName nvarchar(50)
AS
SET NOCOUNT ON;
SELECT FirstName, LastName,Department
FROM HumanResources.vEmployeeDepartmentHistory
WHERE FirstName = @FirstName AND LastName = @LastName;
GO
ストアド プロシージャ uspGetEmployees は次のように実行されます。
EXECUTE HumanResources.uspGetEmployees N'Ackerman', N'Pilar';
-- Or
EXEC HumanResources.uspGetEmployees @LastName = N'Ackerman', @FirstName = N'Pilar';
GO
-- Or
EXECUTE HumanResources.uspGetEmployees @FirstName = N'Pilar', @LastName = N'Ackerman';
GO
-- Or, if this procedure is the first statement within a batch:
HumanResources.uspGetEmployees N'Ackerman', N'Pilar';
C. 単純なプロシージャをワイルドカード パラメーターと共に使用する
次のストアド プロシージャは、特定の複数の従業員 (氏名を提供) と、その役職および部署名を、ビューから返します。このストアド プロシージャは、渡されたパラメーターのパターン検索を行いますが、パラメーターが指定されない場合は、あらかじめ設定された既定値 (文字 D で始まる姓) を使用します。
USE AdventureWorks2008R2;
GO
IF OBJECT_ID ( 'HumanResources.uspGetEmployees2', 'P' ) IS NOT NULL
DROP PROCEDURE HumanResources.uspGetEmployees2;
GO
CREATE PROCEDURE HumanResources.uspGetEmployees2
@LastName nvarchar(50) = N'D%',
@FirstName nvarchar(50) = N'%'
AS
SET NOCOUNT ON;
SELECT FirstName, LastName, Department
FROM HumanResources.vEmployeeDepartmentHistory
WHERE FirstName LIKE @FirstName AND LastName LIKE @LastName;
GO
uspGetEmployees2 ストアド プロシージャは、多くの組み合わせで実行できます。ここでは、一部の組み合わせのみを示します。
EXECUTE HumanResources.uspGetEmployees2;
-- Or
EXECUTE HumanResources.uspGetEmployees2 N'Wi%';
-- Or
EXECUTE HumanResources.uspGetEmployees2 @FirstName = N'%';
-- Or
EXECUTE HumanResources.uspGetEmployees2 N'[CK]ars[OE]n';
-- Or
EXECUTE HumanResources.uspGetEmployees2 N'Hesse', N'Stefen';
-- Or
EXECUTE HumanResources.uspGetEmployees2 N'H%', N'S%';
D. OUTPUT パラメーターの使用
次の例では、指定した金額を超えない価格の製品の一覧を返す uspGetList ストアド プロシージャを作成します。ここでは、複数の SELECT ステートメントと複数の OUTPUT パラメーターを使用する例を示しています。外部プロシージャ、バッチ、または複数の Transact-SQL ステートメントは、OUTPUT パラメーターを使用して、プロシージャの実行中に設定された値にアクセスできます。
USE AdventureWorks2008R2;
GO
IF OBJECT_ID ( 'Production.uspGetList', 'P' ) IS NOT NULL
DROP PROCEDURE Production.uspGetList;
GO
CREATE PROCEDURE Production.uspGetList @Product varchar(40)
, @MaxPrice money
, @ComparePrice money OUTPUT
, @ListPrice money OUT
AS
SET NOCOUNT ON;
SELECT p.[Name] AS Product, p.ListPrice AS 'List Price'
FROM Production.Product AS p
JOIN Production.ProductSubcategory AS s
ON p.ProductSubcategoryID = s.ProductSubcategoryID
WHERE s.[Name] LIKE @Product AND p.ListPrice < @MaxPrice;
-- Populate the output variable @ListPprice.
SET @ListPrice = (SELECT MAX(p.ListPrice)
FROM Production.Product AS p
JOIN Production.ProductSubcategory AS s
ON p.ProductSubcategoryID = s.ProductSubcategoryID
WHERE s.[Name] LIKE @Product AND p.ListPrice < @MaxPrice);
-- Populate the output variable @compareprice.
SET @ComparePrice = @MaxPrice;
GO
uspGetList を実行し、$700 より安い Adventure Works 製品 (バイク) の一覧を返します。ここでは流れ制御言語と共に OUTPUT パラメーターの @Cost および @ComparePrices を使用して、[メッセージ] ウィンドウにメッセージを返します。
注 |
---|
プロシージャの作成中および変数の使用中に、OUTPUT 変数を定義する必要があります。パラメーター名と変数名は一致する必要はありませんが、データ型とパラメーターの位置は一致する必要があります (ただし、@ListPrice= variable が使用されている場合を除きます)。 |
DECLARE @ComparePrice money, @Cost money
EXECUTE Production.uspGetList '%Bikes%', 700,
@ComparePrice OUT,
@Cost OUTPUT
IF @Cost <= @ComparePrice
BEGIN
PRINT 'These products can be purchased for less than
$'+RTRIM(CAST(@ComparePrice AS varchar(20)))+'.'
END
ELSE
PRINT 'The prices for all products in this category exceed
$'+ RTRIM(CAST(@ComparePrice AS varchar(20)))+'.'
次に結果セットの一部を示します。
Product List Price
-------------------------------------------------- ------------------
Road-750 Black, 58 539.99
Mountain-500 Silver, 40 564.99
Mountain-500 Silver, 42 564.99
...
Road-750 Black, 48 539.99
Road-750 Black, 52 539.99
(14 row(s) affected)
These items can be purchased for less than $700.00.
関連項目