Неверный синтаксис рядом с ключевым словом CASE (функция SQL) - PullRequest
0 голосов
/ 12 июня 2018

Я портирую большое приложение Access на SQL-сервер, при этом я работал над переписыванием всех функций VBA как функций SQL.Я не могу получить следующую инструкцию создания функции для выполнения.Кажется, я использую 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 голосов
/ 12 июня 2018

вам, вероятно, нужно что-то вроде этого:

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
0 голосов
/ 13 июня 2018

Stop.Во-первых, не используйте двойные кавычки в качестве разделителя строк.Вы смешали использование одинарных и двойных кавычек, что является огромной проблемой.На самом деле, я предлагаю вам полностью остановиться и потратить некоторое время на изучение tsql и хороших методов программирования.

Стоп.Поскольку прямой перенос кода с одной платформы на другую обычно приводит к незначительным ошибкам (которые трудно найти / исправить) и низкой производительности.Кроме того, код часто будет трудно понять / использовать / отлаживать.Для этой конкретной проблемы, вероятно, было бы более целесообразно поместить эти диапазоны в таблицу и присоединиться к ней / выбрать из нее.Я предполагаю, что можно было бы пойти по этому пути в Access - что не внушает уверенности в дизайне схемы или кода.Используя таблицу, вы можете (и должны) также создать правильное ограничение, чтобы предотвратить попадание недействительных данных в вашу базу данных.Вообще говоря, скалярные функции, которые действуют как справочные таблицы, будут работать плохо.

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

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 имеет гораздо более ограниченную область.Не распространяйте плохие решения.Да, это увеличивает усилия при переносе, но в конечном итоге это будет лучше.

Когда вы видите переменные или столбцы с именами, которые имеют повторяющийся шаблон, это обычно указывает на проблемы схемы.Выбор одного из трех значений для поиска может быть правильным при «настройке» чего-либо, но это, скорее всего, должно быть сделано до сохранения строк в вашей базе данных.«GM» не является особенно хорошо названной переменной, поэтому она не дает никаких подсказок относительно того, что это означает или как она используется.Возможно, существует «первичный» код, используемый для установления взаимосвязи, и другие вторичные коды, которые необходимо сохранить по какой-то неопределенной причине.Это невозможно узнать без знания системы.

Это должно дать вам представление о том, как делать вещи.Но это только демонстрация концепции.

0 голосов
/ 12 июня 2018

У вас есть:

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

Используемая вами конструкция называется «поток управления», потому что она находится на уровне программирования блока T-SQL.Не существует case, который является условием потока управления в T-SQL.Предположительно, вы намереваетесь что-то вроде:

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