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 调用,有时不需要通过 EXACT VALUE调用。例如,我需要 MORE THAN 给定的 accesslevelId 或 LESS THAN。

当前程序只能通过使用处理EXACT

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 来传递运算符。或者你可以传入两个值,例如

@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     

(尽管正如 Aaron 指出的那样 - 您传入的 <> 并没有真正反映语句中的比较运算符 - 将其更改为有意义的东西:))

在你的情况下:

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

也许使用一点 @CompareAccessLevelToMin 而不是 varchar() 作为 @accessType 参数。尽管如此,仍然无法告诉您将其设置为“假”是什么意思。

于 2012-07-09T13:16:26.510 回答