如何有条件地过滤WHERE子句中的列?

Val*_*Val 13 t-sql conditional dynamic where-clause

没错,第十个条件列问题:

我正在编写一个存储过程,它接受一个映射到几个标志列之一的输入参数.筛选请求列的最佳方法是什么?我目前正在使用SQL2000,但即将转向SQL2008,所以如果可以的话,我会采用现代解决方案.

在sproc中查询的表格看起来像

ID ...  fooFlag  barFlag  bazFlag  quuxFlag
--      -------  -------  -------  --------
01         1        0       0          1
02         0        1       0          0
03         0        0       1          1
04         1        0       0          0
Run Code Online (Sandbox Code Playgroud)

我想做点什么

select ID, name, description, ...
from myTable
where (colname like @flag + 'Flag') = 1
Run Code Online (Sandbox Code Playgroud)

所以,如果我打电话给exec uspMyProc @flag = 'foo'我,我会回到第1和第4行.

我知道我不能直接在SQL中用parens做这个部分.为了做动态SQL,我必须将整个查询填充到一个字符串中,在WHERE子句中连接@flag param,然后执行字符串.除了在进行动态SQL时我得到的肮脏感觉,我的查询相当大(我选择了几十个字段,加入了5个表,调用了几个函数),所以它是一个巨大的字符串,因为一行在3行WHERE过滤器中.

或者,我可以有4个查询副本,并在CASE语句中选择它们.这使得SQL代码可以直接执行(并且受语法高亮等影响)但是以重复大块代码为代价,因为我不能仅在WHERE子句上使用CASE.

还有其他选择吗?可以应用任何棘手的连接或逻辑操作?或者我应该克服它并执行动态SQL?

Gab*_*ams 20

有几种方法可以做到这一点:

您可以使用case语句执行此操作.

select ID, name, description, ...
from myTable
where CASE
    WHEN @flag = 'foo' then fooFlag
    WHEN @flag = 'bar' then barFlag
END = 1
Run Code Online (Sandbox Code Playgroud)

你可以使用IF.

IF (@flag = 'foo') BEGIN
    select ID, name, description, ...
    from myTable
    where fooFlag = 1
END ELSE IF (@flag = 'bar') BEGIN
    select ID, name, description, ...
    from myTable
    where barFlag = 1
END

....
Run Code Online (Sandbox Code Playgroud)

您可以使用带有大量括号的复杂where子句.

select ID, name, description, ...
from myTable
where (@flag = 'foo' and fooFlag = 1)
OR (@flag = 'bar' and barFlag = 1) OR ...
Run Code Online (Sandbox Code Playgroud)

你可以用动态sql做到这一点:

DECLARE @SQL nvarchar(4000)

SELECT @SQL = N'select ID, name, description, ...
from myTable
where (colname like ''' + @flag + 'Flag'') = 1'

EXECUTE sp_ExecuteSQL @SQL, N''
Run Code Online (Sandbox Code Playgroud)

还有更多,但我认为其中一个会让你前进.