Резюме : Это ужасная идея. Медленно отступайте, и никто не пострадает.
Отказ от ответственности: я не несу ответственности за расходы на любую терапию, требуемую после прочтения после этой точки.
Из вашего Обновления 2 видно, что вы управляете форматом CheckRule
. Гораздо проще потребовать от пользователя разграничить Code
s, например используя '«A04»'
вместо 'A04'
, вместо того, чтобы пытаться найти их с помощью TSQL. Вам не нужно беспокоиться о таких проблемах, как замена 'A02'
на 66
, когда CheckRule
равен 'A026 - BA02'
, и получение '666 - B66'
.
То, что следует, просто ужасно. Он демонстрирует подход грубой силы к получению выражений с разделенными «переменными», например, '«A04»'
, заменяя все вхождения каждой "переменной" ее целочисленным значением, оценивая полученное выражение и получая результат.
Вместо использования чего-то столь неприятного, как курсор, он использует два вложенных курсора для перемещения по CheckRule
s и Code
s. Было бы более эффективно анализировать «переменные» из выражения и подставлять значения по мере необходимости, а не использовать метод «попробуй все», но TSQL не преуспевает в реализации парсеров .
Для дополнительного кредита это также приносит благословение охвата SQL-инъекция . Попробуйте CheckRule
как 'A01; select 1 / 0;'
. Не пытайтесь, например, '-1; drop database LuckyGuess;'
.
-- Sample data.
declare @Samples as Table
( SampleId Int Identity, Code NVarChar(8), IntValue Int, CheckRule NVarChar(64), Result Bit );
insert into @Samples ( Code, IntValue, CheckRule ) values
( N'A01', 14, N'«A02» - «A03»' ),
( N'A02', 24, N'«A04»' ),
( N'A03', 10, N'«A04»' ),
( N'A04', 12, N'«A02» / 2' );
select * from @Samples;
-- Process the data.
declare Oy cursor forward_only fast_forward read_only
for select SampleId, Code, IntValue, CheckRule from @Samples;
declare @SampleId as Int, @Code as NVarChar(8), @IntValue as Int, @CheckRule as NVarChar(64);
declare Vey cursor forward_only fast_forward read_only
for select Code, IntValue from @Samples;
declare @VariableCode as NVarChar(8), @VariableIntValue as Int
-- For each row's CheckRule ...
open Oy;
fetch next from Oy into @SampleId, @Code, @IntValue, @CheckRule;
while @@Fetch_Status = 0
begin
-- Copy the CheckRule so that we can build the @Expression to evaluate.
declare @Expression as NVarChar(64) = @CheckRule;
-- For each Code that could appear in an @Expression ...
open Vey;
fetch next from Vey into @VariableCode, @VariableIntValue;
while @@Fetch_Status = 0
begin
-- Replace any occurrences of the Code in the @Expression with the corresponding integer value.
set @Expression = Replace( @Expression, N'«' + @VariableCode + N'»',
Cast( @VariableIntValue as NVarChar(10) ) );
fetch next from Vey into @VariableCode, @VariableIntValue;
end;
close Vey;
-- Make the @Expression an executable statement.
set @Expression = N'set @IntResult = ' + @Expression;
declare @Result as Int;
-- Evaluate the @Expression and get the @Result .
execute sp_executesql @Expression, N'@IntResult Int output', @IntResult = @Result output;
select @SampleId as SampleId, @Code as Code, @IntValue as IntValue, @CheckRule as CheckRule,
@Expression as Expression, @Result as Result;
fetch next from Oy into @SampleId, @Code, @IntValue, @CheckRule;
end;
close Oy;
deallocate Oy;
Если это не ясно, не надо. Просто не надо.