SQL Server 2005动态选择

时间:2014-01-15 16:04:42

标签: sql sql-server sql-server-2005

我对SQL非常陌生并努力学习,所以我会提前警告每个人我的错误很可能是显而易见的 - 不要以为我知道我在做什么!这是在SQL Server 2005中。

编辑:以下代码意外误导; my_table不是表格,而是视图。所述视图在两个模式中拼接信息,对其中一个列使用LEFT OUTER JOIN,对其中四个使用stuff((SELECT .....)),当我发布时没有列没有两行分享相同的数据;我已经改变它使用SELECT DISTINCT。

我正在尝试编写一个函数,它将名称的四个部分作为参数 - first,middle,last和title - 并使用LIKE基于这4个部分对给定表运行select。这种天真的方法会返回正确的结果:

ALTER FUNCTION [my_schema].[my_table] (
    @first NVARCHAR(max) = null
    ,@middle NVARCHAR(max) = null
    ,@last NVARCHAR(max) = null
    ,@title NVARCHAR(max) = null
)
RETURNS TABLE AS RETURN(
    SELECT DISTINCT  
        l.foo,
        l.bar,
        l.spam
    FROM my_database.my_schema.my_table l
    WHERE 
        l.FirstName like ISNULL('%'+@last+'%', '%')
        AND l.LastName like ISNULL('%'+@first+'%', '%')
        AND l.MiddleName like ISNULL('%'+@middle+'%', '%')
        AND l.TitleName like ISNULL('%'+@title+'%', '%')
);

问题在于它非常慢。我可以看到缓慢的最明显的原因是非常愚蠢的行为,比较'%';我想要的是SQL通过不进行比较来响应NULL。我还没有找到办法做到这一点;我提出的每个解决方案都会进入有效的SQL语法。

我的问题是“当适当的变量为空时,如何避免与'%'进行LIKE比较?”。我在任何情况下都尽可能地反对使用EXEC,因为我从狂野中获取用户输入并返回潜在的敏感数据,我想尽可能偏执注入 - 这四个变量是疯狂的输入,我想尽可能少地信任他们。

编辑:我已经完成了速度测试,并且已经得出结论,避免额外的LIKE对任何有意义的程度没有帮助。我欢迎任何有关实际加速的建议,并且一旦我重新考虑如何将这些问题放在一起,很可能会很快发布一个新问题。

2 个答案:

答案 0 :(得分:2)

我不确定您是否会获得更好的性能,但我认为Where语句中的以下Case语句也可以正常运行。

WHERE l.FirstName LIKE CASE WHEN @first IS NULL THEN  '%' ELSE '%' + @First + '%' END
AND l.LastName LIKE CASE WHEN @last IS NULL THEN '%' ELSE '%' + @Last + '%' END 
AND ...

答案 1 :(得分:0)

你有几个选择

第一。有这样的可选参数

WHERE 
    (@first IS null or l.FirstName like @first)
    AND 
    (@last IS null or l.LastName  like  @last )
AND
(@middle IS null or l.MiddleName like  @middle )
    AND 
    (@title IS null or l.TitleNamelike  @title )

第二。构建动态SQL

CREATE PROCEDURE GetCustomer
@FirstN nvarchar(20) = NULL,
@LastN nvarchar(20) = NULL,
@CUserName nvarchar(10) = NULL, 
@CID nvarchar(15) = NULL as
DECLARE @sql nvarchar(4000),
SELECT @sql = 'C_FirstName, C_LastName, C_UserName, C_UserID ' + 
'FROM CUSTOMER ' +
'WHERE 1=1 ' +

IF @FirstN  IS NOT NULL
SELECT @sql = @sql + ' AND C_FirstName like @FirstN '
IF @LastN  IS NOT NULL 
SELECT @sql = @sql + ' AND C_LastName like @LastN '
IF @CUserName IS NOT NULL
SELECT @sql = @sql + ' AND C_UserName like @CUserName '
IF @CID IS NOT NULL 
SELECT @sql = @sql + ' AND C_UserID like @CID '
EXEC sp_executesql @sql, N'@C_FirstName nvarchar(20), @C_LastName nvarchar(20),      @CUserName nvarchar(10), @CID nvarchar(15)',
               @FirstN, @LastN, @CUserName, @CID