0

我希望将几个 SQL Server 查询压缩到一个查询中,这样一个参数就可以用于不同的数据类型。这些类型是日期、数字或字符串。该参数称为:@SearchValue。

在强类型数据集中,我们有下面列出的 3 个查询。

这适用于带有 VB.Net 代码隐藏文件的 ASP.Net,但我认为这个问题也可能适用于非 ASP.Net。

如果用户在搜索文本框中输入日期,我称之为:

询问:

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'))
  )
4

3 回答 3

1

这使您可以利用不必将 searchvalue 转换为您需要的任何内容的优势,而且更具可读性。根据需要修改语法,但关键思想是使用 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 评论更新答案

于 2013-01-14T20:32:34.833 回答
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')
        );
于 2013-01-14T18:28:42.617 回答
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。但是,我保留了带有类型名称的版本。

于 2013-01-14T20:28:35.080 回答