Как использовать оператор case в скалярной функции в SQL? - PullRequest
15 голосов
/ 21 февраля 2011

Я хочу получить одно значение из функции, используя оператор case.Я попробовал следующее, но это не работает:

CREATE FUNCTION [FATMS].[fnReturnByPeriod]
(

    @Period INT

)
RETURNS int
AS
BEGIN

    SELECT CASE @Period 
             when 1 then 1
             when @Period >1 and @Period <=7 then 1
             when @Period >7 and @Period <=30 then 1
             when @Period >30 and @Period<=90 then 1
             when @Period >90 and @Period <=180 then 1
             when @Period >180 and @Period <=360 then 1
             else 0
           END

    RETURN @Period
END

Ответы [ 6 ]

17 голосов
/ 21 февраля 2011

Существует два типа выражения CASE : простой и поисковый.Вы должны выбрать один или другой - вы не можете использовать смесь обоих типов в одном выражении.

Попробуйте это:

SELECT CASE
    WHEN @Period = 1 THEN 1
    WHEN @Period > 1 AND @Period <= 7 THEN 2
    WHEN @Period > 7 AND @Period <= 30 then 3
    -- etc...
    ELSE 0
END

Кроме того, вам нужно присвоить результат чему-то какдругие уже указали.

15 голосов
/ 21 февраля 2011

Когда вы используете RETURN @Period, вы должны присвоить значение @Period.В следующем примере показано, как структурировать код так, чтобы не нужно было объявлять локальную переменную.

5 голосов
/ 21 февраля 2011

Объявите вторую переменную и затем установите это значение, потому что вы не сбрасываете @Period.

Например:

DECLARE @Output AS INT

SELECT @Output = CASE @Period 
                 WHEN 1 then 1     
                 WHEN @Period > 1 AND @Period <= 7 THEN 1      -- Should be 2 
                 WHEN @Period > 7 AND @Period <= 30 THEN 1     -- Should be 3
                 WHEN @Period > 30 AND @Period<= 90 THEN 1     -- Should be 4
                 WHEN @Period > 90 AND @Period <= 180 THEN 1   -- Should be 5  
                 WHEN @Period > 180 AND @Period <= 360 THEN 1  -- Should be 6   
                 ELSE 0 END;

RETURN @Output;

Я оставил это так, как я предполагаю, что вы собираетесь изменить свои значения для каждого из этих CASE утверждений.

1 голос
/ 22 февраля 2011

Вот подход, основанный на SET, для написания вашей функции в SQL Server 2008

CREATE FUNCTION [FATMS].[fnReturnByPeriod]
(
    @Period INT
)
RETURNS int
AS
BEGIN
    return isnull((SELECT min(v)
    from (values
     (1,1),
     (7,2),
     (30,3),
     (90,4),
     (180,5),
     (360,6)) t(n,v)
    where n >= @Period and @period>0), 0)
END

Как вы написали, все ветви CASE возвращают 1, так что вы также можете использовать

return case when @period between 1 and 360 then 1 else 0 end
1 голос
/ 21 февраля 2011

Как это "не работает"?Выдает ли ошибка при попытке выполнить его?Возвращает ли он неожиданный результат?

Вне моей головы, есть несколько проблем:

Ваше утверждение case возвращает 1 во всех случаях.

Оператор case также объединяет два различных типа семантики CASE:

CASE @Period 
WHEN <condition> THEN <result>
WHEN <other condition> THEN <result>
ELSE <result>
END

или

CASE
WHEN @Period = <value> THEN <result>
WHEN @Period = <other value> THEN <result>
ELSE <result>
END

Вторая форма позволяет использовать несвязанные условия,тогда как первый может проверять только различные значения @Period.

Кроме того, вы возвращаете значение @Period, а не значение, сгенерированное оператором CASE.

1 голос
/ 21 февраля 2011

Вы нигде не назначаете @Period.Попробуйте с when @Period >1 and @Period <=7 then SET @Period = 1 и впоследствии для всех остальных строк.

SQL не имеет неявных возвратов, поэтому вам всегда нужно задавать переменные, прежде чем их возвращать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...