如何在IN子句中避免使用多个IF语句进行动态查询

时间:2016-08-17 14:27:01

标签: sql sql-server tsql sql-server-2012

我有以下情况:如何以有效的方式编写代码。

DECLARE @sql   VARCHAR(MAX) = ''
DECLARE @where VARCHAR(MAX) = ''

IF @is_clean_label = 1
   SET @where = @where+ N'Clean Label,'

IF @Is_KeyInterview = 1
   SET @where = @where+N'Key Interview,'

IF @Is_SpecialReport = 1
   SET @where = @where+N'Special Report,'

SET @sql = N' SELECT * FROM TABLE WHERE  Name in ('+@where+')'

EXEC (@sql)

如果上面的语句在没有添加参数的情况下抛出错误

  

')'附近的语法不正确。

如果没有条件适用,则需要返回所有值。

是否可以避免动态SQL?

6 个答案:

答案 0 :(得分:1)

首先,努力找到一种非动态的SQL方式。

"技巧"下面是考虑查找表的计数。

恕我直言,忽略所有"试试这个"包括动态sql答案。如果问题可以在没有动态sql的情况下解决,那应该是恕我直言。你可以在这里阅读一些问题:http://sqlmag.com/database-performance-tuning/don-t-fear-dynamic-sql即使你使用它,也有不错的方法和愚蠢的方式来使用它。

    IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
    begin
            drop table #TableOne
    end


    CREATE TABLE #TableOne
    ( 
    SurrogateKeyIDENTITY int not null IDENTITY (1,1) , 
    MyLabel varchar(16)
    )

    Insert into #TableOne ( MyLabel ) select 'Clean Label' UNION ALL select 'Clean Label' UNION ALL select 'Key Interview' UNION ALL select 'Key Interview' UNION ALL select  'Special Report' UNION ALL select  'Special Report' UNION ALL select 'NotAMatch' UNION ALL select  'NotAMatch'


Declare @LookupMatchTable Table (KeyVal varchar(50))
if(1=1) /* use your bool flags here */
begin
    Insert Into @LookupMatchTable (KeyVal) Select 'Clean Label'
end
if(1=1) /* use your bool flags here */
begin
    Insert Into @LookupMatchTable (KeyVal) Select 'Key Interview'
end
if(1=1) /* use your bool flags here */
begin
    Insert Into @LookupMatchTable (KeyVal) Select 'Special Report'
end

declare @LookupMatchTableCount int 
select @LookupMatchTableCount = (select count(*) from @LookupMatchTable)


SELECT * FROM #TableOne t1 WHERE ( @LookupMatchTableCount = 0 OR EXISTS (Select KeyVal  from @LookupMatchTable lmt where lmt.KeyVal = t1.MyLabel ) )

/* now show if there are no entries in the look up table, everything comes back */
delete from @LookupMatchTable
select @LookupMatchTableCount = (select count(*) from @LookupMatchTable)
SELECT * FROM #TableOne t1 WHERE ( @LookupMatchTableCount = 0 OR EXISTS (Select KeyVal  from @LookupMatchTable lmt where lmt.KeyVal = t1.MyLabel ) )


/* now show that if there is something in the lookup table that doesn't match the "real" table......no rows returned */
delete from @LookupMatchTable
    Insert Into @LookupMatchTable (KeyVal) Select 'No Match Whatsoever'
select @LookupMatchTableCount = (select count(*) from @LookupMatchTable)
SELECT * FROM #TableOne t1 WHERE ( @LookupMatchTableCount = 0 OR EXISTS (Select KeyVal  from @LookupMatchTable lmt where lmt.KeyVal = t1.MyLabel ) )




    IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
    begin
            drop table #TableOne
    end

答案 1 :(得分:1)

你可以在where子句中使用case语句做几乎你想做的事情,它允许你基本上将你的IF然后逻辑移动到where子句。

SELECT *
FROM
    TableName
WHERE
    (CASE
       WHEN @is_clean_label = 1 AND Name = 'Clean Label' THEN 1
       ELSE 0
    END) = 1
    OR
    (CASE
       WHEN @Is_KeyInterview = 1 AND Name = 'Key Interview' THEN 1
       ELSE 0
    END) = 1
    OR
    (CASE
       WHEN @Is_SpecialReport = 1 AND Name = 'Special Report' THEN 1
       ELSE 0
    END) = 1
    OR
    (CASE
       WHEN (COALESCE(@Is_SpecialReport,0) + COALESCE(@Is_KeyInterview,0) + COALESCE(@Is_SpecialReport,0))  = 0 THEN 1
       ELSE 0
    END) = 1

我也经常使用John写的表格路线,但我认为展示这种技术非常重要,因为它很有用。我也同意其他一些评论,当它不是真正需要时,远离动态sql!

答案 2 :(得分:0)

由于您拥有连接逻辑,您的@where变量将包含前面的comma

删除第一个comma,你应该好好去!

SET @where = STUFF(@where, 1, 1, '')
SET @sql = N' SELECT * FROM TABLE WHERE  Name in ('+@where+')'

答案 3 :(得分:0)

也许无需动态更新以包含所有无选择

Declare @InList Table (KeyVal varchar(50),Include int)

Insert Into @InList 
values ('Clean Label', @is_clean_label),
       ('Key Interview', @Is_KeyInterview),
       ('Special Report', @Is_SpecialReport)

SELECT * 
FROM TABLE 
WHERE Name IN (SELECT KeyVal 
               FROM @InList 
               WHERE Include = (SELECT MAX(sign(Include)) FROM @InList))

答案 4 :(得分:0)

您的脚本存在一些问题。

首先,in列表中的前导逗号。

其次,没有设置标志时你不会处理

第三,您不是在in列表中添加单引号:

DECLARE @sql   NVARCHAR(MAX) = ''
DECLARE @where NVARCHAR(MAX)

IF  @is_clean_label = 1
SET @where = isnull(@where + ',','')+ N'''Clean Label'''

IF  @Is_KeyInterview = 1
SET @where = isnull(@where + ',','')+ N'''Key Interview'''

IF  @Is_SpecialReport = 1
SET @where = isnull(@where + ',','')+ N'''Special Report'''

SET @sql = N' SELECT * FROM TABLE'
            + case when @where <> ''
                    then ' WHERE  Name in ('+@where+')'
                    else ''
                    end
EXEC (@sql)

答案 5 :(得分:0)

忘了动态SQL。请查询以下查询,并告知我是否需要进行任何更改。

select * from TABLE 
where (Name ='Clean Label' or @is_clean_label=0) 
and ((Name ='Key Interview' or @Is_KeyInterview=0))
and ((Name ='Special Report' or @Is_SpecialReport=0))