「ベスト プラクティス」の 1 つは、ストアド プロシージャを介してデータにアクセスすることです。このシナリオが優れている理由がわかりました。私の動機は、データベースとアプリケーション ロジックの分割 (ストアド プロシージャの動作が同じ場合、テーブルを変更できます)、SQL インジェクションに対する防御 (ユーザーは "select * from some_tables" を実行できず、ストアド プロシージャのみを呼び出すことができます)、およびセキュリティ(ストアドプロシージャでは、ユーザーがデータを選択/挿入/更新/削除できない、安全な「何でも」にすることができますが、これは彼らのためではありません)。
私が知らないのは、動的フィルターを使用してデータにアクセスする方法です。
MSSQL 2005 を使用しています。
テーブルがある場合:
CREATE TABLE tblProduct (
ProductID uniqueidentifier -- PK
, IDProductType uniqueidentifier -- FK to another table
, ProductName nvarchar(255) -- name of product
, ProductCode nvarchar(50) -- code of product for quick search
, Weight decimal(18,4)
, Volume decimal(18,4)
)
次に、4 つのストアド プロシージャ ( create / read / update / delete ) を作成する必要があります。
「作成」のストアド プロシージャは簡単です。
CREATE PROC Insert_Product ( @ProductID uniqueidentifier, @IDProductType uniqueidentifier, ... etc ... ) AS BEGIN
INSERT INTO tblProduct ( ProductID, IDProductType, ... etc .. ) VALUES ( @ProductID, @IDProductType, ... etc ... )
END
「削除」のストアドプロシージャも簡単です。
CREATE PROC Delete_Product ( @ProductID uniqueidentifier, @IDProductType uniqueidentifier, ... etc ... ) AS BEGIN
DELETE tblProduct WHERE ProductID = @ProductID AND IDProductType = @IDProductType AND ... etc ...
END
「更新」のストアド プロシージャは「削除」のストアド プロシージャと似ていますが、これが正しい方法であるかどうかはわかりません。すべての列を更新するのは効率的ではないと思います。
CREATE PROC Update_Product( @ProductID uniqueidentifier, @Original_ProductID uniqueidentifier, @IDProductType uniqueidentifier, @Original_IDProductType uniqueidentifier, ... etc ... ) AS BEGIN
UPDATE tblProduct SET ProductID = @ProductID, IDProductType = @IDProductType, ... etc ...
WHERE ProductID = @Original_ProductID AND IDProductType = @Original_IDProductType AND ... etc ...
END
そして、最後の「読み取り」のストアド プロシージャは、私にとっては少し謎です。複雑な条件のフィルター値を渡す方法 いくつかの提案があります:
where条件を渡すためのXMLパラメータの使用:
CREATE PROC Read_Product ( @WhereCondition XML ) AS BEGIN
DECLARE @SELECT nvarchar(4000)
SET @SELECT = 'SELECT ProductID, IDProductType, ProductName, ProductCode, Weight, Volume FROM tblProduct'
DECLARE @WHERE nvarchar(4000)
SET @WHERE = dbo.CreateSqlWherecondition( @WhereCondition ) --dbo.CreateSqlWherecondition is some function which returns text with WHERE condition from passed XML
DECLARE @LEN_SELECT int
SET @LEN_SELECT = LEN( @SELECT )
DECLARE @LEN_WHERE int
SET @LEN_WHERE = LEN( @WHERE )
DECLARE @LEN_TOTAL int
SET @LEN_TOTAL = @LEN_SELECT + @LEN_WHERE
IF @LEN_TOTAL > 4000 BEGIN
-- RAISE SOME CONCRETE ERROR, BECAUSE DYNAMIC SQL ACCEPTS MAX 4000 chars
END
DECLARE @SQL nvarchar(4000)
SET @SQL = @SELECT + @WHERE
EXEC sp_execsql @SQL
END
しかし、1回のクエリで「4000」文字という制限は見苦しいと思います。
次の提案は、すべての列にフィルター テーブルを使用することです。フィルター値をフィルター テーブルに挿入し、フィルターの ID を使用してストアド プロシージャを呼び出します。
CREATE TABLE tblFilter (
PKID uniqueidentifier -- PK
, IDFilter uniqueidentifier -- identification of filter
, FilterType tinyint -- 0 = ignore, 1 = equals, 2 = not equals, 3 = greater than, etc ...
, BitValue bit , TinyIntValue tinyint , SmallIntValue smallint, IntValue int
, BigIntValue bigint, DecimalValue decimal(19,4), NVarCharValue nvarchar(4000)
, GuidValue uniqueidentifier, etc ... )
CREATE TABLE Read_Product ( @Filter_ProductID uniqueidentifier, @Filter_IDProductType uniqueidentifier, @Filter_ProductName uniqueidentifier, ... etc ... ) AS BEGIN
SELECT ProductID, IDProductType, ProductName, ProductCode, Weight, Volume
FROM tblProduct
WHERE ( @Filter_ProductID IS NULL
OR ( ( ProductID IN ( SELECT GuidValue FROM tblFilter WHERE IDFilter = @Filter_ProductID AND FilterType = 1 ) AND NOT ( ProductID IN ( SELECT GuidValue FROM tblFilter WHERE IDFilter = @Filter_ProductID AND FilterType = 2 ) )
AND ( @Filter_IDProductType IS NULL
OR ( ( IDProductType IN ( SELECT GuidValue FROM tblFilter WHERE IDFilter = @Filter_IDProductType AND FilterType = 1 ) AND NOT ( IDProductType IN ( SELECT GuidValue FROM tblFilter WHERE IDFilter = @Filter_IDProductType AND FilterType = 2 ) )
AND ( @Filter_ProductName IS NULL OR ( ... etc ... ) )
END
しかし、この提案は少し複雑だと思います。
このタイプのストアド プロシージャを実行するための「ベスト プラクティス」はありますか?