Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/apache/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
编写可怕的SQL搜索查询(第二阶段)_Sql_Sql Server_Sql Server 2005_Tsql_Dynamic Sql - Fatal编程技术网

编写可怕的SQL搜索查询(第二阶段)

编写可怕的SQL搜索查询(第二阶段),sql,sql-server,sql-server-2005,tsql,dynamic-sql,Sql,Sql Server,Sql Server 2005,Tsql,Dynamic Sql,我正在做一个搜索查询(使用asp.NET3.5前端),它看起来很简单,但很复杂。 完整的查询是: set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go ALTER PROCEDURE [dbo].[usp_Item_Search] @Item_Num varchar(30) = NULL ,@Search_Type int = NULL ,@Vendor_Num varchar(10) = NULL ,@Search_Use

我正在做一个搜索查询(使用asp.NET3.5前端),它看起来很简单,但很复杂。 完整的查询是:

set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go

ALTER PROCEDURE [dbo].[usp_Item_Search]
    @Item_Num varchar(30) = NULL
    ,@Search_Type int = NULL
    ,@Vendor_Num varchar(10) = NULL
    ,@Search_User_ID int = 0
    ,@StartDate smalldatetime = NULL
    ,@EndDate smalldatetime = NULL
AS
DECLARE @SQLstr as nvarchar(4000)

Set @SQLstr = 'SELECT RecID, Vendor_Num, Vendor_Name, InvoiceNum, Item_Num, 
(SELECT CONVERT(VARCHAR(11), RecDate, 106) AS [DD MON YYYY]) As RecDate, NeedsUpdate, RecAddUserID FROM [tbl_ItemLog] where 1=1 '

IF (@Item_Num IS NOT NULL and LTRIM(@Item_Num) <> '')
    Begin
        If @Search_Type = 0
            BEGIN
                Set @SQLstr = @SQLstr +  'AND Item_Num LIKE ''' + @Item_Num + '%'''
            END
        If @Search_Type = 1
            BEGIN
                Set @SQLstr = @SQLstr + 'AND Item_Num LIKE ''%' + @Item_Num + '%'''
            END
        If @Search_Type = 2
            BEGIN
                Set @SQLstr = @SQLstr + 'AND Item_Num LIKE ''%' + @Item_Num + ''''
            END
    End

IF (@Vendor_Num IS NOT NULL and LTRIM(@Vendor_Num) <> '')
    Begin
        Set @SQLstr = @SQLstr + ' AND Vendor_Num = ''' + @Vendor_Num + ''''
    End

IF (@Search_User_ID IS NOT NULL and @Search_User_ID > 0)
    Begin
        Set @SQLstr = @SQLstr + ' AND RecAddUserID = ' + convert(nvarchar(20),@Search_User_ID)
    End

Set @SQLstr = @SQLstr + ' AND (RecDate BETWEEN ''' + convert(nvarchar(10),@StartDate,106) + ''' AND ''' + convert(nvarchar(10),@EndDate,106) + ''')'

PRINT (@SQLstr)
--Execute (@SQLstr)
我如何解决这个问题

IF (Search_User_ID IS NOT NULL) 
变量前面需要一个@符号


您说您正在为所有变量传递空字符串,但其中一个是int,它不能接受不是int数据的空字符串。不敢相信我没有;我第一次没注意到。

为什么不使用如下单参数化查询:

select 
   recdid,
   Vendor_Num,
   Vendor_Name,
   InvoiceNum,
   Item_Num, 
   CONVERT(VARCHAR(11), RecDate, 106) as RecDate,
   NeedsUpdate, 
   RecAddUserID 
FROM 
  [tbl_ItemLog] as t
where
   (((Item_num like @Item_Num + '%' and @Search_Type = 0) OR
    (Item_num like '%' + @Item_Num + '%' and @Search_Type =  1) OR
    (Item_num like '%' + @Item_Num + '%' and @Search_Type = 2))  
        OR
    @Item_Num IS NULL) AND
   (Vendor_Num = @Vendor_Num OR @Vendor_Num IS NULL) AND
   (RecAddUserId = @Search_User_Id OR @Search_User_Id IS NULL) AND
   (RecDate BETWEEN @StartDate AND @EndDate)

据我所知,你没有完全正确地构建字符串。如果没有传入@Item_Num,您将没有WHERE关键字。。。您只需要“从[tblItem_Log]和…”

我将所有标准的附录都设为“和…”,并且作为您最初的陈述,使用:

FROM [tbl_Item_Log] WHERE (1=1)
既然您有返回生成字符串的代码,为什么不将其放入SSMS并尝试运行它呢

我还注意到,如果不传入日期值,最终将执行一个空字符串,因为最终的连接将导致一个空字符串。如果要使用动态SQL来构建查询,您需要密切关注这些问题

一旦我纠正了这个错误,我就能够在没有任何错误的情况下运行存储过程(至少生成看起来像是有效的SQL语句的内容)。这使我相信底层表中的数据类型可能有问题。你能给出这个定义吗

最后一点:就个人而言,我会使用

CONVERT(VARCHAR(11), RecDate, 106) AS RecDate
而不是您拥有的看似不必要的子查询

又一次编辑:
您可能希望删除检查LTRIM(@Search\u User\u ID)')的代码。这是一段毫无意义的代码,可能是服务器/连接的特定设置导致它失败,因为类型不匹配。

这里确实有几个不同的存储过程。为什么不把它们分开写呢?由switch语句控制的所有内容都可以在过程代码中轻松实现。LTRIM调用也是如此

您可以使用switch语句从单个SP调用它们;但我认为一开始最好不要合并它们。SP查询将更容易优化,代码也将简化。通过整合它们,您不会获得多少收益

不确定您的业务规则,但您可以在SQL之外使用

switch(search_type) {    
case 1:  
    do_query_type_1(args);  
    break;  
case 2:  
    do_query_type_2(args);  
    break;  
case 3:  
    do_query_type_3(args);  
    break;  
default:  
    whatever ...  
}

另外,对于是否提供项目编号的情况,您似乎有单独的逻辑。其他字段也一样。您的每个用例看起来都可以解析为一个非常简单的查询。

请注意,这更简洁,但实际上更慢(性能方面)。在将其插入我的应用程序之前,我需要研究一下您的响应。谢谢你的建议。与动态SQL的性能相比,这是一个倒退。像这样的查询将确保几乎每次都进行硬解析,除非参数完全相同。还有参数嗅探的风险…我需要休假。我没有抓住where条款的问题。就返回的记录数而言,1=1是否会打乱查询?@DotNetRookie:
WHERE 1=1
将得到优化,这是一种很好的方法,可以指定一个WHERE子句,在动态SQL等情况下很容易附加到该子句。这很好。但我仍然得到错误消息。“无法将参数值从字符串转换为Int32。”@DotNetRookie-请发布调用语法。也就是说,当你说你传递所有“空”参数值时,你是什么意思?传递空参数意味着用户没有为Item_Num、Search_Type、Vendor_Num、Search_user_ID etcI输入值。我真的不明白这是如何“几个”不同的存储过程。请你说得具体一点好吗?另外,你正在使用致命的“带前导通配符的字符串”搜索键,这将保证索引扫描或更糟的搜索。当然。每个搜索类型都有一个存储过程。和if(vendornum){}else if(search_user_id){}else{}您在谈论哪个int变量?@search_user_id您需要通过发送NUll非空字符串“”来测试它,不带任何值。查看您的ASP代码。。。您确定下拉列表框的值是整数吗?它是否可能获取显示值而不是索引?在我看来,SQLServer不会在错误消息中给出Int32,这是一个.NET错误。很好。dropdownlist的第一个值是“请选择一个值”,它的索引值不是0。现在我收到另一条错误消息:“将字符串转换为smalldatetime数据类型时,转换失败。”
switch(search_type) {    
case 1:  
    do_query_type_1(args);  
    break;  
case 2:  
    do_query_type_2(args);  
    break;  
case 3:  
    do_query_type_3(args);  
    break;  
default:  
    whatever ...  
}