2

動的WHERE句が必要な場合は、私が使用できます。

CREATE PROCEDURE [dbo].[sp_sel_Articles]
      @articleId            INT              = NULL
    , @title            NVARCHAR(250)    = NULL
    , @accessLevelId    INT              = NULL
AS
BEGIN
     SELECT *
     FROM table_Articles Art
     WHERE
          (Art.ArticleId = @articleId OR @articleId IS NULL)
          AND (Art.Title LIKE '%' + @title + '%' OR @title IS NULL)
          AND (Art.AccessLevelId = @accessLevelId OR @accessLevelId IS NULL)
END

したがって、このプロシージャを呼び出すことができます-たとえば-ArticleIdによってのみ

EXEC [sp_sel_Articles] @articleId = 3

ただし、AccessLevelIdで呼び出す必要がある場合もあれば、正確な値では呼び出さない場合もあります。たとえば、指定されたaccesslevelIdより多くまたはLESSTHANが必要になります。

現在の手順では、使用することによってのみ正確な値を処理できます

Art.AccessLevelId = @accessLevelId

プロシージャにCONDITIONタイプと値を指定することもできますか?この例では非常に奇妙に思えるかもしれませんが、ご容赦ください。

CREATE PROCEDURE [dbo].[sp_sel_Articles]
          @articleId            INT              = NULL
        , @title            NVARCHAR(250)    = NULL
        , @accessLevelId    INT              = NULL
        , **@accessLevelIdCondition**
    AS
    BEGIN
         SELECT *
         FROM table_Articles Art
         WHERE
              (Art.ArticleId = @articleId OR @articleId IS NULL)
              AND (Art.Title LIKE '%' + @title + '%' OR @title IS NULL)
              AND (Art.AccessLevelId **@accessLevelIdCondition** @accessLevelId OR @accessLevelId IS NULL)
    END

たぶん関数が使えるのか、わかりません。この柔軟性を必要とするプロシージャは少なくとも20あるので、すべてのプロシージャにIF ELSE条件を記述するのではなく、可能な限り、より優れた、よりグローバルなソリューションが必要になります。

前もって感謝します、

4

4 に答える 4

3

演算子を渡すには、おそらく動的 SQL を使用する必要があります。または、2 つの値を渡すこともできます。

@MinAccessLevelID INT,
@MaxAccessLevelID INT

...
WHERE (
   (@MinAccessLevelID IS NULL AND @MaxAccessLevelID IS NULL)
   OR 
   (AccessLevelID >= @MinAccessLevelID AND AccessLevelID <= @MaxAccessLevelID)
)

正確な値 (例: 3 のみ) が必要な場合は、両方の値に 3 を渡すだけです。3 以上が必要な場合は 20000000000 を @Max パラメータに渡します。3 以下のすべてが必要な場合は 0 を渡します。

しかし、これらの順列がより複雑になるにつれて、動的 SQL だけを使用した方がよいことがわかります ( optimize for ad hoc workloadsset を使用すると、プラン キャッシュの再利用とパラメータ スニッフィングの阻止にも適しています)。

于 2012-07-09T13:12:53.953 に答える
2

適用する前に、この www.sommarskog.se/dynamic_sql.html をお読みください。

  CREATE PROCEDURE [dbo].[sp_sel_Articles] 
              @articleId            INT              = NULL 
            , @title            NVARCHAR(250)    = NULL 
            , @accessLevelId    INT              = NULL 
            , @accessLevelIdCondition varchar(100)
        AS 
        BEGIN 
                DECLARE @SQL varchar(8000)
    SET @SQL='
         SELECT * 
         FROM table_Articles Art 
         WHERE 
              (Art.ArticleId = '+cast(@articleId as varchar(100))+' OR '+cast(@articleId as varchar(100))+'IS NULL) 
              AND (Art.Title LIKE ''%'' + @title + ''%'' OR @title IS NULL) 
              AND (Art.AccessLevelId '+@accessLevelIdCondition+ cast(@accessLevelId as varchar(100))+' OR '+cast(@accessLevelId as varchar(100))+' IS NULL) '
    EXEC(@sql)
        END 
于 2012-07-09T13:15:14.750 に答える
1

クエリ文字列を作成するだけで、いつでも動的クエリを作成できます

execute ('select count(*) from table' ) 

したがって、ストアド プロシージャに入力されたパラメーターを使用して、実行可能なクエリ文字列を作成することもできます。

于 2012-07-09T13:13:50.590 に答える
1

case ステートメントを使用できます - 正しくフォーマットされていないと少しおかしく見えるかもしれませんが、次のようなものを試すことができます:

SELECT Columns FROM SomeTable
WHERE 1 = CASE
              WHEN @SomeOption = '<>' AND SomeValue >= @SomeMinParam AND SomeValue <= SomeMaxParam THEN 1
              WHEN @SomeOption '=' AND SomeValue = @SomeMinParam THEN 1
              ELSE 0
          END     

(ただし、アーロンが指摘したように - あなたが渡す <> は実際にはステートメントの比較演算子を反映していません - これを意味のあるものに変更してください:))

あなたの場合:

CREATE PROCEDURE [dbo].[sp_sel_Articles]
    @articleId            INT              = NULL,
    @title            NVARCHAR(250)    = NULL,
    @MinaccessLevelId    INT              = NULL,
    @MaxaccessLevelId     INT          = NULL,
    @accessType       varchar(5)       = '<>'
AS
BEGIN
 SELECT *
 FROM table_Articles Art
 WHERE
      (Art.ArticleId = @articleId OR @articleId IS NULL)
      AND (Art.Title LIKE '%' + @title + '%' OR @title IS NULL)
      AND 1 = CASE 
                  WHEN @accessType = '<>' AND (Art.AccessLevelId = @MinaccessLevelId OR @accessLevelId IS NULL) THEN 1
                  WHEN @accessType = '=' AND (Art.AccessLevelId >= @MinaccessLevelId OR Art.AccessLevelId <= @MaxaccessLevelId) THEN 1
                  ELSE 0
              END
END

@accessType パラメータの varchar() の代わりに、少し @CompareAccessLevelToMin を使用してください。ただし、「false」に設定することの意味がわからないという問題はまだあります。

于 2012-07-09T13:16:26.510 に答える