存储过程偶然会意外返回2个结果

时间:2015-03-11 16:37:06

标签: sql sql-server-2008 debugging stored-procedures

我有以下存储过程来根据2个参数从表中获取数据:

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

-- =============================================
-- Author:      Dmitry Kreslavskiy
-- Create date: 2015-01-12
-- Description: spGetCreditBenchmarkCurves
-- =============================================

/* spGetCreditBenchmarkCurves
 * Get the list of credit benchmark spread records, if necessary fixing
 * currency and latest ValueDate <= RunDate.
 *     \param[in]  RunDate    Run date of the search (uses the last date up to
 *                            this time), NULL = all
 *     \param[in]  Ccy        Use only this currency
 *     \return     Table (Ccy, ValueDate, TenorSize, TenorUnit, Value)
 */

ALTER PROCEDURE [dbo].[spGetCreditBenchmarkCurves]
(
    @RunDate date       = NULL,
    @Ccy     varchar(3) = NULL
)
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    IF @RunDate IS NULL
       IF @Ccy IS NULL
           SELECT *
             FROM [dbo].CreditBenchmarkCurves
       ELSE -- @Ccy is supplied
             SELECT *
               FROM [dbo].CreditBenchmarkCurves
              WHERE Ccy = @Ccy
    ELSE -- @RunDate is supplied
       /* It could be that the table does not have any valid data on @RunDate,
        * so find the latest date before @RunDate with valid data, and store
        * this in @ExactDate, to use it in a query directly.
        *
        * (Same thing could be done using an INNER JOIN instead of 2 selects,
        *  but it is much clearer code to do it step by step. Also, I have a
        *  feeling this implementation is faster as well.)
        */
       DECLARE @ExactDate date
       SET @ExactDate = (SELECT MAX(ValueDate)
                           FROM [dbo].CreditBenchmarkCurves
                          WHERE ValueDate <= @RunDate)
       IF @Ccy IS NULL
           SELECT *
             FROM [dbo].CreditBenchmarkCurves
            WHERE ValueDate = @ExactDate
       ELSE -- @Ccy is supplied
           SELECT *
             FROM [dbo].CreditBenchmarkCurves
            WHERE ValueDate = @ExactDate AND
                  Ccy       = @Ccy
END

GO

此代码偶尔返回一个值表,如预期的那样:

EXEC dbo.spGetCreditBenchmarkCurves @RunDate = '2015-02-27', @Ccy = 'AUD'

但是传递默认运行日期会产生一个完整的表和一个空表:

EXEC dbo.spGetCreditBenchmarkCurves @RunDate = NULL, @Ccy = 'AUD'
EXEC dbo.spGetCreditBenchmarkCurves

错误是什么,如何使用此类代码执行2 SELECT个语句? 谢谢

2 个答案:

答案 0 :(得分:2)

用开始/结束

来包装你的if else条件
IF @RunDate IS NULL
BEGIN 
 /* your code for if */
END
ELSE
BEGIN
/* your code for else */
END

注意:

  1. BEGIN和END定义了一系列Transact-SQL语句 一起执行。
  2. IF ... ELSE构造可以在批处理,存储过程中使用, 在临时查询中
  3. 参考1: MSDN IF ELSE

    参考2: MSDN IF ELSE WITH BEGIN END

答案 1 :(得分:2)

此代码

ALTER PROCEDURE [dbo].[spGetCreditBenchmarkCurves]
(
    @RunDate date       = NULL,
    @Ccy     varchar(3) = NULL
)
AS
BEGIN
    IF @RunDate IS NULL
       IF @Ccy IS NULL
           SELECT *
             FROM [dbo].CreditBenchmarkCurves
       ELSE -- @Ccy is supplied
             SELECT *
               FROM [dbo].CreditBenchmarkCurves
              WHERE Ccy = @Ccy
    ELSE 
       DECLARE @ExactDate date
       SET @ExactDate = (SELECT MAX(ValueDate)
                           FROM [dbo].CreditBenchmarkCurves
                          WHERE ValueDate <= @RunDate)
       IF @Ccy IS NULL
           SELECT *
             FROM [dbo].CreditBenchmarkCurves
            WHERE ValueDate = @ExactDate
       ELSE -- @Ccy is supplied
           SELECT *
             FROM [dbo].CreditBenchmarkCurves
            WHERE ValueDate = @ExactDate AND
                  Ccy       = @Ccy
END

等于:

ALTER PROCEDURE [dbo].[spGetCreditBenchmarkCurves]
(
    @RunDate date       = NULL,
    @Ccy     varchar(3) = NULL
)
AS
BEGIN
    IF @RunDate IS NULL
    BEGIN
       IF @Ccy IS NULL
       BEGIN
           SELECT * FROM [dbo].CreditBenchmarkCurves
       END
       ELSE BEGIN
           SELECT * FROM [dbo].CreditBenchmarkCurves WHERE Ccy = @Ccy
       END
    END
    ELSE BEGIN
       DECLARE @ExactDate date
    END

   SET @ExactDate = (SELECT MAX(ValueDate)
                       FROM [dbo].CreditBenchmarkCurves
                      WHERE ValueDate <= @RunDate)
   IF @Ccy IS NULL
       SELECT *
         FROM [dbo].CreditBenchmarkCurves
        WHERE ValueDate = @ExactDate
   ELSE -- @Ccy is supplied
       SELECT *
         FROM [dbo].CreditBenchmarkCurves
        WHERE ValueDate = @ExactDate AND
              Ccy       = @Ccy

END

如果没有BEGIN END,则DECLARE @ExactDate date被视为ELSE块。实际上,如果@RunDate IS NULL选择将发生2次。