如果存储过程的值为null

时间:2015-08-22 08:10:49

标签: sql sql-server sql-server-2008 tsql

我有一个存储过程,我必须在其中连接10个表并使用WHERE条件根据存储过程中传递的参数过滤记录。例如:

create procedure proc1
    @var1 varchar(100) = null,
    @var2 varchar(100) = null,
    @var3 varchar(100) = null,
    @var4 varchar(100) = null,
    ........   
    @var10 varchar(100) = null
as
begin
    insert into #a
    select * from
    (
        select * from 
            tab1 as a
            inner join tab2 as b on a.rollnumber = b.rollnumber
            inner join tab3 as c on c.city = b.city
            ........
            inner join tab10 as j on J.id = i.id
        where 
            a.id = isnull(@var1,a.id) and 
            b.id = isnull(@var2,b.id) and 
            c.id = isnull(@var3,c.id) and 
            ...........
            J.id = isnull(@var10,j.id)
    ) as abc

    if (select count(*) from #a) < 10 
    begin
        select * from #a
    end
    else 
    begin
        print 'Cannot display the records as count is more than 10'
    end
end

上面的存储过程工作正常,但它很慢,因为WHERE子句中有10个条件。我想要的是如果没有向存储过程提供某些参数,则跳过该条件。例如,如果只将3个参数传递给存储过程,则WHERE子句应跳过WHERE子句中的其余参数。这将使程序更有效。因此,如果未传递@var1,则应返回a.id的所有值。

3 个答案:

答案 0 :(得分:1)

Erland Sommarskog有一篇非常好的文章Dynamic Search Conditions in T‑SQL。他解释了可以使用的几种方法,并将建立动态SQL与@ lad2025建议和使用OPTION(RECOMPILE)进行比较。

我个人在这些查询中使用OPTION(RECOMPILE)。您使用SQL Server 2008,因此这个选项是一个不错的选择。如果您确实通过动态SQL路由,请务必阅读他的另一篇文章The Curse and Blessings of Dynamic SQL

所以,你的程序就是这样的:

create procedure proc1
    @var1 varchar(100) = null,
    @var2 varchar(100) = null,
    @var3 varchar(100) = null,
    @var4 varchar(100) = null,
    ........   
    @var10 varchar(100) = null
as
begin
    insert into #a
    select * from
    (
        select * 
        from
            tab1 as a
            inner join tab2 as b on a.rollnumber = b.rollnumber
            inner join tab3 as c on c.city = b.city
            ........
            inner join tab10 as j on J.id = i.id
        where 
            (a.id = @var1 OR @var1 IS NULL)
            and (b.id = @var2 OR @var2 IS NULL)
            and (c.id = @var3 OR @var3 IS NULL)
            ...........
            and (J.id = @var10 OR @var10 IS NULL)
    ) as abc
    OPTION(RECOMPILE);

    if (select count(*) from #a) < 10 
    begin
        select * from #a
    end
    else 
    begin
        print 'Cannot display the records as count is more than 10'
    end
end

顺便说一下,通过查看count()并不清楚你想要实现的目标,但也许你需要的只是简单的TOP(10)来返回最多10个第一行。如果您确实使用ORDER BY来一致地返回结果,请务必添加TOP子句。如果您不知道,可以使用过程的另一个参数来指示要返回的最大行数并在TOP(@ParamMaxRowCount)中使用它。有时候返回结果集的存储过程并不常见,有时只打印一条消息。

答案 1 :(得分:0)

让我们玩Dynamic - SQL:

CREATE PROCEDURE [dbo].[my_procedure]
     @var1 VARCHAR(100) = NULL,
     @var2 VARCHAR(100) = NULL,
     @var3 VARCHAR(100) = NULL,
     @var4 VARCHAR(100) = NULL,
     /* ........  */ 
     @var10 VARCHAR(100) = NULL,
     @debug INT         = 0
AS
BEGIN
SET NOCOUNT ON;

DECLARE 
    @sql        NVARCHAR(MAX),                                
    @paramlist  NVARCHAR(4000),                              
    @nl         CHAR(2) = CHAR(13) + CHAR(10);


/* Main query here */
SELECT @sql = 
   'SELECT * 
    FROM tab1 AS a
    INNER JOIN tab2 AS b
      ON a.rollnumber = b.rollnumber
    INNER JOIN tab3 AS c
      ON c.city = b.city
    /* ........ and so on */
    INNER JOIN tab10 AS j
      ON J.id = i.id
    WHERE 1 = 1 ' + @nl;

IF @var1 IS NOT NULL                                            
    SELECT @sql += ' AND a.id = @var1' + @nl;  

IF @var2 IS NOT NULL                                            
    SELECT @sql += ' AND b.id = @var2' + @nl;  

/* ... */

IF @var10 IS NOT NULL                                            
    SELECT @sql += ' AND j.id = @var10' + @nl;

/* If sorting needed just add it;
SELECT @sql += ORDER BY a.id;
*/

IF @debug = 1
    PRINT @sql;


SELECT @paramlist = 
      '@var1     VARCHAR(100),   
       @var2     VARCHAR(100),
       /* ... */
       @var10     VARCHAR(100)';

/*CREATE TABLE #temp definition here */

INSERT INTO #temp(col1, col2, ...)
EXEC [dbo].[sp_executesql]
           @sql,
           @paramlist,
           @var1,
           @var2,
           /* ... */
           @var10;

IF @@ROWCOUNT < 10 
THEN
    SELECT *       /* Use column names */
    FROM #temp;
ELSE
    PRINT 'Cannot display the records as count is more than 10';
END

如果想查看查询,则用作任何正常的存储过程+ debug:

 EXEC [dbo].[my_procedure]
            @var1 = 'AAA'
           ,@var2 = 'BBB'
           ,@debug = 1;
  • 格式化就是一切,特别是在使用Dynamic-SQL时。
  • 而不是SELECT COUNT(*) FROM #temp使用@@ROWCOUNT;
  • 从SP打印不是一个好习惯,最好返回一些值以在OUT参数中指示它。
  • 如果您不喜欢WHERE 1 = 1,您可以先检查所有参数是否为NULL并跳过它。
  • 您根本不需要使用动态SQL,只需使用IF THEN ELSE IF THEN ELSE IF ... ELSE并执行难以维护的代码的大量复制(如果使用代码行来衡量您的工作效率,那么它很有用)

答案 2 :(得分:-1)

您只需要提供正在使用的参数。

如果只需要传递Var1的值。

proc1 @Var1 = Var1Value

如果需要传递Var6的值。

Proc1 @Var6 = Var6Value

请使用此案例

 where case @var1 when null then 1 else  a.id end =  case @var1 when null then 1 else  @var1 end 

希望这会对你有所帮助 感谢