我正在开发一个搜索查询(带有asp.net 3.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)
当我传递所有空参数值时,出现错误:
“无法转换参数值 从String到Int32。“
调用存储过程的asp.net代码是:
//Display search results in GridView;
SqlConnection con = new SqlConnection(strConn);
//string sqlItemSearch = "usp_Item_Search";
SqlCommand cmdItemSearch = new SqlCommand(sqlItemSearch, con);
cmdItemSearch.CommandType = CommandType.StoredProcedure;
cmdItemSearch.Parameters.Add(new SqlParameter("@Item_Num", SqlDbType.VarChar, 30));
cmdItemSearch.Parameters["@Item_Num"].Value = txtItemNumber.Text.Trim();
cmdItemSearch.Parameters.Add(new SqlParameter("@Search_Type", SqlDbType.Int));
cmdItemSearch.Parameters["@Search_Type"].Value = ddlSearchType.SelectedItem.Value;
cmdItemSearch.Parameters.Add(new SqlParameter("@Vendor_Num", SqlDbType.VarChar, 10));
cmdItemSearch.Parameters["@Vendor_Num"].Value = txtVendorNumber.Text.Trim();
cmdItemSearch.Parameters.Add(new SqlParameter("@Search_User_ID", SqlDbType.Int));
cmdItemSearch.Parameters["@Search_User_ID"].Value = ddlSeachUser.SelectedItem.Value;
if (!string.IsNullOrEmpty(txtStartDate.Text))
{
cmdItemSearch.Parameters.Add(new SqlParameter("@StartDate", SqlDbType.DateTime));
cmdItemSearch.Parameters["@StartDate"].Value = Convert.ToDateTime(txtStartDate.Text.Trim());
}
else
{
cmdItemSearch.Parameters.Add(new SqlParameter("@StartDate", SqlDbType.DateTime));
cmdItemSearch.Parameters["@StartDate"].Value = Convert.ToDateTime("01/01/1996");
}
if (!string.IsNullOrEmpty(txtEndDate.Text))
{
cmdItemSearch.Parameters.Add(new SqlParameter("@EndDate", SqlDbType.DateTime));
cmdItemSearch.Parameters["@EndDate"].Value = Convert.ToDateTime(txtEndDate.Text.Trim());
}
else
{
cmdItemSearch.Parameters.Add(new SqlParameter("@EndDate", SqlDbType.DateTime));
cmdItemSearch.Parameters["@EndDate"].Value = Convert.ToDateTime(DateTime.Now);
}
con.Open();
SqlDataAdapter ada = new SqlDataAdapter(cmdItemSearch);
DataSet ds = new DataSet();
ada.Fill(ds);
gvSearchDetailResults.DataSource = ds;
gvSearchDetailResults.DataBind();
pnlSearchResults.Visible = true;
我该如何解决这个问题?
答案 0 :(得分:3)
据我所知,你还没有正确构建字符串。如果没有传入@Item_Num,你最终将没有WHERE关键字......你将只有“FROM [tblItem_Log] AND ...”
我会将所有标准追加为“AND ...”,并在初始声明中使用:
FROM [tbl_Item_Log] WHERE (1=1)
由于您有返回生成的字符串的代码,为什么不将它放入SSMS并尝试运行它?
我还注意到,如果你没有传入日期值,那么你最终会执行一个NULL字符串,因为你的最终连接最终会导致NULL。如果您要使用动态SQL构建查询,则需要密切关注这些事情。
一旦我纠正了我能够运行存储过程而没有任何错误(至少生成看起来像一个有效的SQL语句)。这让我相信它可能是基础表中数据类型的问题。你能为它提供定义吗?
最后一点:个人,我会用
CONVERT(VARCHAR(11), RecDate, 106) AS RecDate
而不是你所拥有的看似不必要的子查询。
另一个编辑: 您可能希望删除检查LTRIM(@Search_User_ID)&lt;&gt;的代码。 ''。这是一个毫无意义的代码,也许特定于您的服务器/连接的设置导致它因类型不匹配而失败。
答案 1 :(得分:1)
IF (Search_User_ID IS NOT NULL)
需要变量
前面的@符号你说你为所有变量传递空字符串但是一个是int,它不能取一个不是int数据的空字符串。不敢相信我没有;第一次注意到。
答案 2 :(得分:0)
为什么不使用这样的单一参数化查询:
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)
答案 3 :(得分:0)
这里确实有几个不同的存储过程。为什么不单独写它们?由switch语句控制的所有内容都可以很容易地在过程代码中。对于LTRIM呼叫也是如此。
您可以使用switch语句从单个SP中调用它们;但我认为首先不合并它们通常会更好。 SP查询将更容易优化,代码将简化。巩固它们并没有太大的收获。
不确定您的业务规则,但您可以使用
简化SQL之外的SQLswitch(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 ...
}
对于提供或不提供商品编号的情况,您似乎也有单独的逻辑。其他领域也一样。您的每个用例看起来都解析为一个非常简单的查询。