【问题标题】:sql parameters which can be optionalsql参数,可以是可选的
【发布时间】:2010-10-28 18:53:30
【问题描述】:

我有这个问题,我需要为我的存储过程设置“可选”参数才能正常工作。 例如,我有这个:

CREATE PROCEDURE [dbo].[Search]
(
 @StartTime datetime = NULL,
 @EndTime datetime = NULL,
 @CustomerEmail nvarchar(255) = NULL,
 @OrderStatusID int
)

现在,在我的 .net 网站中,我有一个类似的示例,请记住,参数可能只有一个,也可能全部都有:

commAdvanced.Parameters.Add("@StartTime", SqlDbType.DateTime).Value = startDate;
commAdvanced.Parameters.Add("@EndTime", SqlDbType.DateTime).Value = endDate;
commAdvanced.Parameters.Add("@CustomerEmail", SqlDbType.nvarchar).Value = null;
commAdvanced.Parameters.Add("@OrderStatusID", SqlDbType.Int).Value = null;

这是查询:

SELECT * FROM Order 
WHERE CreatedOn > CAST(@StartTime as datetime) 
  AND CreatedOn < CAST(@EndTime as datetime)
  AND Order.OrderStatusID = @OrderStatusID 
  AND Order.CustomerEmail = @PaymentStatusID

当我这样做时,我没有得到任何记录,有人可以帮助我我需要更改什么。

【问题讨论】:

  • 你的SELECT声明中的@PaymentStatusID来自哪里?

标签: .net sql procedure


【解决方案1】:

假设选择查询中有错字,不妨试试

AND Order.CustomerEmail = ISNULL(@CustomerEmail, CustomerEmail)
And OrderStatusID = ISNULL(@OrderStatusID, OrderStatusID)

您也不需要将@StartTime 等转换为日期时间。他们已经是那种类型了,不是吗?

【讨论】:

    【解决方案2】:

    根据您的问题,在 4 个参数中,一个或所有参数都可以传递给您的过程。您的查询在 where 子句中检查了所有列。因此,如果我理解正确的话,目前,在所有 4 个参数都以有效数据传递之前,您不会获得任何记录。

    试试这个,我只是在构造一个查询然后执行它。我检查每个参数是否为空,并且只有非空的参数值包含在 where 子句中。

    declare @sqlstring varchar(1000)
    
    set @sqlstring = 'SELECT * FROM Order WHERE 1=1 '
    
    if @StartTime <> null OR @StartTime <> '' 
    BEGIN 
    set @sqlstring = @sqlstring + 'AND CreatedOn > CAST(@StartTime as datetime) ' 
    END 
    
    if @EndTime <> null OR @EndTime <> '' 
    BEGIN 
    set @sqlstring = @sqlstring + 'AND CreatedOn < CAST(@EndTime as datetime) ' 
    END 
    
    if @OrderStatusID <> null OR @OrderStatusID <> '' 
    BEGIN 
    set @sqlstring = @sqlstring + 'AND OrderStatusID = @OrderStatusID ' 
    END 
    
    if @CustomerEmail <> null OR @CustomerEmail <> '' 
    BEGIN 
    set @sqlstring = @sqlstring + 'AND CustomerEmail > @CustomerEmail ' 
    END 
    
    print @sqlstring
    Exec(@sqlstring)
    

    【讨论】:

      【解决方案3】:

      您需要传入DBNull.Value 用于那些您想保留NULL 的参数(不仅仅是.NET null):

      commAdvanced.Parameters.Add("@CustomerEmail", SqlDbType.nvarchar).Value = DBNull.Value;
      commAdvanced.Parameters.Add("@OrderStatusID", SqlDbType.Int).Value = DBNull.Value;
      

      这应该可以解决问题。

      另外:如果您指定varcharnvarchar 类型的参数,我建议始终指定其长度。

      【讨论】:

        【解决方案4】:

        我认为这很简单,因为您的查询不正确。

        让我们以仅提供@StartTime 为例。您的查询将评估为:

        SELECT * FROM Order  
        WHERE CreatedOn > CAST(@StartTime as datetime)  
          AND CreatedOn < null
          AND Order.OrderStatusID = null
          AND Order.CustomerEmail = null
        

        假设 ANSI NULL 为 ON,则与 null 相比,没有任何值返回真结果,因此您的结果集为空。

        我认为 Noel 的答案最接近 - 我建议:

        SELECT * FROM Order  
        WHERE (@StartTime is null or CreatedOn > @StartTime)
          AND (@EndTime is null or CreatedOn < @EndTime)
          AND Order.OrderStatusID = isnull(@OrderStatusID, Order.OrderStatusID)
          AND Order.CustomerEmail = isnull(@CustomerEmail, Order.CustomerEmail)
        

        marc_s 也是正确的——如果你明确想将一个@参数值设置为SQL null,设置为

        commAdvanced.Parameters.Add("@CustomerEmail", SqlDbType.nvarchar).Value = DBNull.Value;          
        commAdvanced.Parameters.Add("@OrderStatusID", SqlDbType.Int).Value = DBNull.Value;   
        

        但是,由于您在存储过程中提供了 null 的默认值(@OrderStatusID 除外 - 错字?),您实际上根本不需要将这些参数添加到命令中。

        【讨论】:

          【解决方案5】:

          请注意:可维护性的最佳解决方案可能不利于性能和可扩展性(请注意,自 SQL Server 2008 以来,竞争环境发生了变化)。

          这是一个相当大的话题,我建议您阅读 Erland Sommarskog 的 Dynamic Search Conditions in T-SQL

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-01-22
            • 1970-01-01
            • 2011-02-25
            • 2015-03-25
            • 2013-05-29
            • 2018-08-10
            相关资源
            最近更新 更多