好的,无数次条件列问题:
我正在编写一个存储过程,它接受一个映射到多个标志列之一的输入参数。筛选请求列的最佳方法是什么?我目前正在使用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
我想做点什么
select ID, name, description, ...
from myTable
where (colname like @flag + 'Flag') = 1
所以,如果我像exec uspMyProc @flag = 'foo'
那样调用sproc,我会回到第1行和第4行。
我知道我不能直接在SQL中用parens做这个部分。为了做动态SQL,我必须将整个查询填充到一个字符串中,在WHERE子句中连接@flag param,然后执行字符串。除了在进行动态SQL时我得到的肮脏感觉,我的查询相当大(我选择了几十个字段,加入了5个表,调用了几个函数),所以它是一个巨大的字符串,因为一行在3行WHERE过滤器中。
或者,我可以有4个查询副本,并在CASE语句中选择它们。这使得SQL代码可以直接执行(并且受语法高亮等影响)但是以重复大块代码为代价,因为我不能仅在WHERE子句上使用CASE。
还有其他选择吗?可以应用任何棘手的连接或逻辑操作?或者我应该克服它并执行动态SQL?
答案 0 :(得分:20)
有几种方法可以做到这一点:
您可以使用案例陈述来执行此操作。
select ID, name, description, ...
from myTable
where CASE
WHEN @flag = 'foo' then fooFlag
WHEN @flag = 'bar' then barFlag
END = 1
您可以使用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
....
你可以有一个带有很多括号的复杂where子句。
select ID, name, description, ...
from myTable
where (@flag = 'foo' and fooFlag = 1)
OR (@flag = 'bar' and barFlag = 1) OR ...
您可以使用动态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''
还有更多,但我认为其中一个会让你前进。
答案 1 :(得分:4)
“或者,我可以有4个查询副本,并在CASE语句中选择它们。”
您不需要复制整个查询4次,只需将所有可能性添加到查询的单个副本中的where子句中:
select ID, name, description, ...
from myTable
where (@flag = 'foo' and fooFlag = 1) OR (@flag = 'bar' and barFlag = 1) OR ...
答案 2 :(得分:3)
我要做的是CASE
开头的一些变量。例如:
DECLARE
@fooFlag int,
@barFlag int,
@bazFlag int,
@quuxFlag int
SET @fooFlag = CASE WHEN @flag = 'foo' THEN 1 ELSE NULL END
SET @barFlag = CASE WHEN @flag = 'bar' THEN 1 ELSE NULL END
SET @bazFlag = CASE WHEN @flag = 'baz' THEN 1 ELSE NULL END
SET @quuxFlag = CASE WHEN @flag = 'quux' THEN 1 ELSE NULL END
SELECT ID, name, description, ...
FROM myTable
WHERE (fooFlag >= ISNULL(@fooFlag, 0) AND fooFlag <= ISNULL(@fooFlag, 1))
AND (barFlag >= ISNULL(@barFlag, 0) AND barFlag <= ISNULL(@barFlag, 1))
AND (bazFlag >= ISNULL(@bazFlag, 0) AND bazFlag <= ISNULL(@bazFlag, 1))
AND (quuxFlag >= ISNULL(@quuxFlag, 0) AND quuxFlag <= ISNULL(@quuxFlag, 1))
这个查询的好处在于,因为“flags”的可能值是有界的,所以您可以将所有条件计算为先决条件,而不是将列包装在其中。这保证了对索引的任何列进行高性能索引查找,并且不需要编写任何动态SQL。而且出于显而易见的原因,它比编写4个单独的查询要好。
答案 3 :(得分:1)
int应该被接受为varchar值
declare @CompanyID as varchar(10) = '' -- or anyother value
select * from EmployeeChatTbl chat
where chat.ConversationDetails like '%'+@searchKey+'%'
and
(
(0 = CASE WHEN (@CompanyID = '' ) THEN 0 ELSE 1 END)
or
(chat.CompanyID = @CompanyID)
)
<强> 工作 强>
当存在companyID时,则基于它进行过滤,否则,跳过过滤。
答案 4 :(得分:0)
您可以为每个可能的标志列设置一个参数,然后检查参数是否为null或列中的值是否等于参数。然后传入1表示要检查的标志,并将其他标志保留为空。
select id, name, description, ...
from myTable
where (@fooFlag is null or fooFlag = @fooFlag) AND
(@barFlag is null or barFlag = @barFlag) AND
...
老实说,这似乎是构建动态LINQ查询并在进入SQL2008后跳过SPROC的理想选择。
答案 5 :(得分:0)
where
case when @value<>0 then Field else 1 end
=
case when @value<>0 then @value else 1 end