关键字CASE(SQL函数)附近的语法不正确

时间:2018-06-12 19:52:19

标签: sql sql-server function sql-server-2008-r2 sql-function

我正在将一个大型Access应用程序移植到SQL服务器,这样做我一直在努力将所有VBA函数重写为SQL函数。我无法获得以下create function语句来执行。貌似我使用CASE不正确?感谢任何帮助,这是我第一次尝试SQL函数。

CREATE FUNCTION dbo.[NAL_PolicyCode]
(
@gm1 float, 
@gm2 float = 1,
@gm3 float = 1,
@typ varchar(10) = ''
)
RETURNS VarChar(10)
AS BEGIN
DECLARE @gm float;
SET @gm = @gm1;
SET @gm = CASE 
    WHEN @gm2 < @gm THEN @gm2 END 
SET @gm = CASE
    WHEN @gm3 < @gm THEN @gm3 END 

SET @gm = Round(@gm, 3);

IF(@typ = 'MS')
    BEGIN
        (CASE WHEN @gm < 0.03 THEN 
                    PolicyCode = '1B'
             WHEN @gm < 0.05 THEN
                    PolicyCode = '1C'
             WHEN @gm < 0.08 THEN
                    PolicyCode = '1D'
             WHEN @gm < 0.12 THEN
                    PolicyCode = '1E'
             WHEN @gm < 0.16 THEN
                    PolicyCode = '1F'
             WHEN @gm < 0.24 THEN
                    PolicyCode = '1G'
             WHEN @gm < 0.29 THEN
                    PolicyCode = '1H'
             WHEN @gm < 0.47 THEN
                    PolicyCode = '1J'
             ELSE
                    PolicyCode = '1K'
                    END) 
    END
ELSE IF(@typ = 'PL')
    BEGIN
        (CASE WHEN @gm < 0.35 THEN
                PolicyCode = "8"
             WHEN @gm < 0.45 THEN
                PolicyCode = "P"
             WHEN @gm < 0.58 THEN
                PolicyCode = "V"
             WHEN @gm < 0.7 THEN
                PolicyCode = "4"
            ELSE
                PolicyCode = "R"
                END) 
    END
ELSE
    BEGIN
        (CASE WHEN @gm < 0.16 THEN
                PolicyCode = "Y"
             WHEN @gm < 0.24 THEN
                PolicyCode = "Z"
             WHEN @gm < 0.29 THEN
                PolicyCode = "X"
            WHEN @gm < 0.36 THEN
                PolicyCode = "9"
             WHEN @gm < 0.41 THEN
                PolicyCode = "J"
             WHEN @gm < 0.47 THEN
                PolicyCode = "N"
             WHEN @gm < 0.55 THEN
                PolicyCode = "D"
             WHEN @gm < 0.63 THEN
                PolicyCode = "S"
             WHEN @gm < 0.75 THEN
                PolicyCode = "T"
            ELSE
                PolicyCode = "U"
                END) 
    END
END;

3 个答案:

答案 0 :(得分:1)

你有:

IF(@typ = 'MS')
    BEGIN
        (CASE WHEN @gm < 0.03 THEN 
                    PolicyCode = '1B'
         . . .

您正在使用的构造称为&#34;控制流&#34;,因为它处于编程T-SQL块的级别。没有case是T-SQL中的控制流子句。据推测,你打算这样的事情:

IF(@typ = 'MS')
    BEGIN
        SET @PolicyCode = (CASE WHEN @gm < 0.03 THEN PolicyCode = '1B'
                                  . . .

答案 1 :(得分:1)

停止。首先,不要使用双引号作为字符串分隔符。你混合了单引号和双引号 - 这是一个巨大的问题。事实上,我建议你完全停下来,花些时间学习tsql和良好的编程习惯。

停止。因为从一个平台到另一个平台的直接代码端口通常会出现细微的错误(很难找到/修复)和性能不佳。此外,代码通常很难理解/使用/调试。对于这个特殊问题,将这些范围放在表中并加入/选择它可能更有意义。我猜想有人可以在Access中采用这种方式 - 这不会激发对架构或代码设计的信心。使用表,您可以(并且应该)创建适当的约束以防止无效数据渗入您的数据库。一般来说,充当查找表的标量值函数表现不佳。

为了帮助说明这个概念,下面使用表变量来存储逻辑引用的值。注意加入最后一个select语句所需的神秘逻辑。我会回到那个。

set nocount on;
declare @PolicyCodes table (Typ varchar(2) not null, PolicyCode varchar(2) not null, 
    MinVal decimal(2,2) not null, MaxVal decimal(2,2) not null);

insert @PolicyCodes (Typ, PolicyCode, MinVal, MaxVal)
values 
    ('MS', '1B', 0,    0.02),  ('MS', '1C', 0.03, 0.04), 
    ('MS', '1D', 0.05, 0.07),  ('MS', '1E', 0.08, 0.11),
    ('MS', '1K', 0.12, 0.99),
    ('PL', '8',  0,    0.34),  ('PL', 'P',  0.35, 0.44),
    ('PL', 'R',  0.45, 0.99),
    ('??', 'Y',  0,    0.15),  ('??', 'Z',  0.16, 0.23),
    ('??', 'Z',  0.24, 0.99);
--select * from @PolicyCodes order by Typ, MinVal, MaxVal;

with cte as (
select * from (values 
   (1, 'MS', 0.20, 0.04, 0.99), --1C
   (2, 'MS', 0.99, 0.70, 0.11), --1E
   (3, 'MS', 0.05, 0.06, 0.07), --1D
   (4, '??', 0.16, 0.17, 0.00)  --Y
) as TestVals (ID, Typ, gm1, gm2, gm3)
)
select cte.*, PC.* 
from cte inner join @PolicyCodes as PC
on cte.Typ = PC.Typ
and case
   when cte.gm1 < cte.gm2 and cte.gm1 < cte.gm3 then cte.gm1 
   when cte.gm2 < cte.gm3 then cte.gm2
   else cte.gm3 end between PC.MinVal and PC.MaxVal
order by cte.ID;

首先,请注意这只是您逻辑的一个子集。缩小规模以供讨论和调查;在尝试整个事情之前先咬一下。如果我试图消化代码的拼写错误或错误,您需要调整此逻辑。

其次,请注意我没有使用float或舍入逻辑。这似乎对我很怀疑。也许这在Access中有意义 - 我对它没有直接的了解。但四舍五入意味着通用汽车的价值领域受到更多限制。不要宣传错误的决定。是的 - 这确实增加了迁移的工作量,但最终会更好。

当您看到名称具有重复模式的变量或列时,这通常表示架构问题。在“设置”某些内容时,选择用于查找的三个值中的哪一个可能没问题 - 但这很可能在您将数据库保存到数据库之前完成。 “GM”并不是一个特别明确的变量,因此它没有提供关于它的含义或使用方式的线索。也许有一个“主要”代码用于建立关系和其他二级代码,需要保留一些不明确的原因。没有系统知识就不可能知道。

这应该会给你如何做事的想法。但它只是这个概念的一个示范。

答案 2 :(得分:0)

你可能需要这样的东西:

CREATE FUNCTION dbo.[NAL_PolicyCode]
(
@gm1 float, 
@gm2 float = 1,
@gm3 float = 1,
@typ varchar(10) = ''
)
RETURNS VarChar(10)

BEGIN

DECLARE
@GM float,
@PolicyCode varchar(10)


set @GM =(  select min(gm) from (
            select @gm1 AS gm union
            select @gm2 union
            select @gm3) x
            );
SET @gm = Round(@gm, 3);

SET @PolicyCode = (
SELECT 
CASE WHEN @typ = 'MS' THEN 
        (
    CASE     WHEN @gm < 0.03 THEN  '1B'
             WHEN @gm < 0.05 THEN '1C'
             WHEN @gm < 0.08 THEN '1D'
             WHEN @gm < 0.12 THEN '1E'
             WHEN @gm < 0.16 THEN '1F'
             WHEN @gm < 0.24 THEN '1G'
             WHEN @gm < 0.29 THEN '1H'
             WHEN @gm < 0.47 THEN '1J'
             ELSE'1K' END
        )
WHEN @typ = 'PL' THEN 
        (
    CASE     WHEN @gm < 0.35 THEN '8'
             WHEN @gm < 0.45 THEN 'P'
             WHEN @gm < 0.58 THEN 'V'
             WHEN @gm < 0.7 THEN '4'
            ELSE 'R'   END 
        )
ELSE 
        (
CASE        WHEN @gm < 0.16 THEN 'Y'
             WHEN @gm < 0.24 THEN 'Z'
             WHEN @gm < 0.29 THEN 'X'
            WHEN @gm < 0.36 THEN '9'
             WHEN @gm < 0.41 THEN 'J'
             WHEN @gm < 0.47 THEN 'N'
             WHEN @gm < 0.55 THEN 'D'
             WHEN @gm < 0.63 THEN 'S'
             WHEN @gm < 0.75 THEN 'T'
            ELSE 'U'
                END
        )
END
)

RETURN @PolicyCode;

END