我希望将多个SQL Server查询压缩到单个查询中,以便参数可用于不同的数据类型。这些类型是日期,数字或字符串。该参数称为:@ SearchValue。
在强类型数据集中,我们有下面列出的3个查询。
这是针对ASP.Net的VB.Net代码隐藏文件,但我认为这个问题也可能对非ASP.Net也有好处。
如果用户在搜索TextBox中输入日期,我会调用此文件:
查询:
SELECT ID, PaymentAmount, PaymentDate, WhatWasPaymentFor
FROM Payments
WHERE (ParentID = @ParentID) AND
(PaymentDate = @SearchValue)
从VB.Net代码隐藏调用日期搜索查询:
tblObject = theTableAdapter.GetDataByPaymentDate(dcmParentsId, TextBoxSearch.Text)
If tblObject.Count() > 0 Then
GridViewSummary.DataSource = tblObject
GridViewSummary.DataBind()
End If
其他的仅用于数字,最后一个用于其他一切。
这个只用于数字:
SELECT PaymentDate, PaymentAmount, WhatWasPaymentFor, ID
FROM Payments
WHERE (ParentID = @ParentID) AND
(PaymentAmount = @SearchValue)
当其他2个查询找不到任何数据时,会调用此文件:
SELECT PaymentDate, PaymentAmount, WhatWasPaymentFor, ID
FROM Payments
WHERE (ParentID = @ParentID) AND
((WhatWasPaymentFor LIKE '%' + @SearchValue + '%') OR
(@SearchValue = 'ALL'))
所有这些编码都按原样运行,我这样做是因为如果我尝试使用非日期值调用.GetDataByPaymentDate,则会出现错误。
有没有办法使用单个查询来处理按日期,数字和字符串的搜索?
*更新*
感谢所有的示例查询。我正在尝试SQL Server Management Studio中的所有示例查询,以查看结果。
我这个基于Gordon的查询,但它没有返回任何数据:
DECLARE @SearchValue VARCHAR = '01/01/2012'
DECLARE @SearchType VARCHAR = 'Dates'
DECLARE @ParentID INT = 3
SELECT ID, PaymentAmount, PaymentDate, WhatWasPaymentFor
FROM Payments cross join
(select @SearchValue as sv) const
WHERE ParentID = @ParentID AND
(case when @SearchType = 'Dates' and ISDATE(const.sv) = 1
then (case when PaymentDate = CAST(const.sv AS datetime) then 'true' else 'false' end)
when @SearchType = 'Numbers' and ISNUMERIC(const.sv) = 1
then (case when PaymentAmount = cast(const.sv as Int) then 'true' else 'false' end)
when @SearchType = 'Everything Else'
then (case when WhatWasPaymentFor LIKE '%' + const.sv + '%' OR const.sv='ALL' then 'true' else 'false' end)
end) = 'true'
这是基于gh9中的一个并提取数据。谢谢gh9:
DECLARE @SearchValue VARCHAR = 'Books'
DECLARE @ParentID INT = 3
DECLARE @PaymentDate DATETIME = NULL
DECLARE @PaymentAmount MONEY = NULL
SELECT ID, PaymentAmount, PaymentDate, WhatWasPaymentFor
FROM Payments
WHERE ParentID = @ParentID
AND (@paymentDate is null OR PaymentDate = @Paymentdate)
AND (@paymentAmount is null OR paymentAmount = @paymentAmount)
AND ((@SearchValue is null OR
(WhatWasPaymentFor LIKE '%' + @SearchValue + '%' OR @SearchValue='ALL'))
)
答案 0 :(得分:1)
这使您可以利用不必将搜索值转换为您需要的任何内容,也可以更具可读性。根据需要修改语法,但关键思想是使用sql server能够使用空参数和短路逻辑来评估强类型参数,而不是转换为所需的数据类型。
@ParentID INT
@PaymentAmount INT = NULL
@PaymentDate Datetime = null
@GenericSearchTerm varchar(100) = null
AS
BEGIN
SELECT
ID,
PaymentAmount,
PaymentDate,
WhatWasPaymentFor
FROM Payments
WHERE @ParentID = @ParentID
AND ( (@paymentDate is null OR PaymentDate = @Paymentdate))
AND (@paymentAmount is null OR paymentAmount = @paymentAmount))
AND ( @GenericSearchTerm is null OR ((WhatWasPaymentFor LIKE '%' + @GenericSearchTerm + '%' OR @SearchValue='ALL'))
编辑:根据@andriyM评论更新答案
答案 1 :(得分:0)
如何添加@SearchType的第三个参数和('datetime','int'或'nvarchar')的可能值,并在WHERE子句中使用它来将@SearchValue强制转换为适当的类型进行比较。类似的东西:
SELECT
ID,
PaymentAmount,
PaymentDate,
WhatWasPaymentFor
FROM Payments
WHERE @ParentID = @ParentID
AND (
(@SearchType = 'datetime' AND PaymentDate = CAST(@SearchValue AS datetime))
OR
(@SearchType = 'int' AND PaymentAount = CAST(@SearchValue AS int))
OR
(@SearchType = 'nvarchar' AND
(WhatWasPaymentFor LIKE '%' + @SearchValue + '%' OR @SearchValue='ALL')
);
答案 2 :(得分:0)
这受到了Bstateham的回答的启发,但它做了两件事。首先,它将值存储在表中,将它们从常量转换为变量。其次,它使用case
,因为这可以保证短路。
这导致类似:
SELECT ID, PaymentAmount, PaymentDate, WhatWasPaymentFor
FROM Payments cross join
(select @SearchValue as sv) const
WHERE @ParentID = @ParentID AND
(case when @SearchType = 'datetime' and ISDATE(const.sv) = 1
then (case when PaymentDate = CAST(const.sv AS datetime) then 'true' else 'false' end)
when @SearchType = 'int' and ISNUMERIC(const.sv) = 1
then (case when PaumentAmount = cast(const.sv as Int) then 'true' else 'false' end)
when @SearchType = 'nvarchar'
then (case when WhatWasPaymentFor LIKE '%' + const.sv + '%' OR const.sv='ALL' then 'true' else 'false' end)
end) = 'true'
我还在验证检查中添加了转换为整数和日期(不完美,但会有所帮助)。此外,您应该在目标字段之后命名@SearchType而不是类型。但是,我保留了版本的类型名称。