我正在使用SQL Server 2008 R2版本。我有一个简单的表,有多列。 EmpId
中列为nvarchar(50)
我正在编写一个存储过程,在其中我收到一个输入,该输入可以具有以下值之一。
'12345'
'12345, 56789, 98987'
null
我想要的是什么:
如果empid是单个empId,则返回
select *
from table_name
where EmpId = @empId
如果empid是多个以逗号分隔的值,则只返回
select *
from table_name
where EmpId in (select * from dbo.splitstring(@empId))
如果empId为null,则返回
Select *
from table_name
不需要where子句。
为了涵盖这三个条件,我正在尝试:
DECLARE @empId nvarchar(2000)
SET @empId = '97050001,97050003, 97050004'
SELECT TOP 10 empId
FROM Employee
WHERE empId in (COALESCE((select * from dbo.splitstring(@empId)),[empId]))
我收到以下错误:
子查询返回的值超过1。当子查询遵循=,!=,<,< =,>,> =或子查询用作表达式时,不允许这样做。
我理解错误。 COALESCE()
期待单个值,但当我得到逗号分隔值时,splitstring
函数会返回多个值。
我不想构建动态查询,所以除了使用if else块复制代码,我检查empId是否为null运行select * from table_name
否则运行select * from table name where empId in ()
。我有什么选择?
要将逗号分隔的字符串拆分为表格,我正在使用此函数:
CREATE FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
RETURNS
@returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN
DECLARE @name NVARCHAR(255)
DECLARE @pos INT
WHILE CHARINDEX(',', @stringToSplit) > 0
BEGIN
SELECT @pos = CHARINDEX(',', @stringToSplit)
SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)
INSERT INTO @returnList
SELECT @name
SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
END
INSERT INTO @returnList
SELECT @stringToSplit
RETURN
END
答案 0 :(得分:2)
尝试使用更复杂的分裂字符串功能。
sp_executesql
此版本的效果会更好,因为
mailx
因参数化执行计划缓存而导致更好的执行计划。 答案 1 :(得分:1)
取决于您的需求: -
我不想构建动态查询,因此除了复制代码之外 使用if else阻止我检查empId是否为null运行select * from table_name else运行select * from table name,其中empId in()
为避免重复,请使用下一种方法: -
DECLARE @empId nvarchar(2000)
set @empId = '97050001,97050003,97050004'
if CHARINDEX(',',@empId) > 0 -- multiple Values
begin
set @empId = '''' + replace (@empId,',',''',''') + ''''
end
else if @empId is null
begin
set @empId = 'select empId from Employee'
end
exec ('select top 10 empId from Employee where empId in (' + @empId + ')' )
这种方法处理三种情况: -
Null
。答案 2 :(得分:0)
案例1和2都可以针对您已为案例2编写的代码进行处理。您只需为案例3添加OR
条件。
select *
from table_name
where @empId is NULL
or EmpId in (select * from dbo.splitstring(@empId))
话虽如此,IN
包含select语句的子句通常是不好的做法,原因如下
在你的情况下,如果splitstring
只返回了几行,那么它可能会带来很大的不同,但以下是这种查询的更通用的方法。
select *
from table_name t
left join dbo.splitstring(@empId) s
on t.EmpId = s.Name
where @empId is NULL
or s.Name is not NULL
您可以随意检查查询和配置文件的执行计划,看看哪个更快,尽管您的初始实现应该没问题。引用Donald Knuth,"过早的优化是所有邪恶的根源。"
<强>更新强>
在仔细检查@empId
为空且非空的情况下使用的执行计划之后,看起来上面的查询将始终使用相同的执行计划,即加入{{1的内容无论in
是否为空,都可以使用子句。正如@ m-ali所指出的那样,这可能并不理想。
为确保每种情况下的正确执行计划,您可以将其分为两个查询:
@empId
我已经在SSMS中验证了正确的执行计划。
免责声明:我还没有对其进行分析,但@ m-ali建议的字符串拆分也可能更快。