2015-03-11 2 views
0

У меня есть следующие хранимые процедуры для извлечения данных из таблицы на основе 2-х параметров:хранимых процедур неожиданно возвращает 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 с таким кодом? Спасибо

+0

В общем, если бы я хотел отлаживать хранимую процедуру, есть ли какие-либо инструменты, которые я могу использовать для этого, а не просто работать с разными входами, например, пошаговый код? – gt6989b

+0

SSMS обеспечивает отладку из коробки. Просто выберите «Step Into» или «Step Over» из меню «Debug» –

+1

'IF @rundate IS NULL BEGIN ... несколько утверждений ... END' <- BEGIN/END важны здесь! –

ответ

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 раза.

2

Wrapp ваш, если еще состояние с начала/конца

IF @RunDate IS NULL 
BEGIN 
/* your code for if */ 
END 
ELSE 
BEGIN 
/* your code for else */ 
END 

Примечание:

  1. Начинайте и заканчивайте определить ряд Transact-SQL операторов, которые выполняют вместе.
  2. IF ... ELSE конструкция может быть использована в пакетном режиме, в хранимых процедурах, и специальных запросов

Ссылка 1:MSDN IF ELSE

Ссылка 2:MSDN IF ELSE WITH BEGIN END

Смежные вопросы