将多个SQL查询压缩到单个查询中,以便参数可用于不同的数据类型

时间:2013-01-14 15:24:00

标签: asp.net sql-server vb.net parameters

我希望将多个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'))
  )

3 个答案:

答案 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而不是类型。但是,我保留了版本的类型名称。