Овој пример не е толку поврзан со SQL-InterActive туку повеќе со начинот на програмирање T-SQLa. Пошто знаеме колку се програмските примери вредни, го вклучивме во упатствата.
Примерот добро илустрира рекурзии, складирани процедури. Главната процедура е наменета за израчунување математички изрази, кои ги внесуваме во форма на низи алфанумерички знаци.
Процедурите се направени така, што ако го отстраниме --!! пред print командите, го гледаме текот на извршувањето и рекурзиите.
Помошна процедура, која враќа аргументи
create procedure [dbo].[dl_PA_ParserGetArg]
@sExpression varchar(8000),
@lLeft bit,
@iOperand int,
@iLimit integer output,
@mResult float output,
@sEr varchar(8000) output
-- тест параметри
-- декларирај
-- @sExpression varchar(8000),
-- @lLeft bit,
-- @iOperand int,
-- @iLimit integer,
-- @mResult money,
-- @sEr varchar(8000)
--
-- set @sExpression='2*3'
-- set @lLeft=1
-- set @iOperand=2
-- exec dl_PA_GetArg @sExpression, @lLeft, @iOperand, @iLimit output,@mResult output, @sEr output
-- --!! print '-----'
-- --!! print @iLimit
-- --!! print cast(@mResult as char)
-- --!! print @sEr
as
declare
@sTempArg varchar(8000)
set nocount on
set @sTempArg = ' '+@sExpression+' ' -- ова е само за да се справи со ограничувањата во циклусот (да не добиеме j[0])
set @iOperand = @iOperand + 1
--!! print ' @sTempArg='+@sTempArg+'#'
--!! print ' @iOperand=' + Str(@iOperand) + '#' + SubString(@sTempArg,@iOperand,1)
if @lLeft=1
begin -- лев аргумент
set @iLimit = @iOperand - 1
--!! print ' лев аргумент'
--!! print ' @iLimit=' + Str(@iLimit) + '#' + SubString(@sTempArg,@iLimit,1)
while (@iLimit > 0) and not (SubString(@sTempArg,@iLimit,1) in ('+','-','/','*','\','|'))
set @iLimit = @iLimit-1
-- да провериме за водечки "-" за лев аргумент.
if @iLimit > 1
if SubString(@sTempArg,@iLimit,1) = '-'
set @iLimit = @iLimit-1
--!! print ' @iLimit=' + Str(@iLimit) + '#' + SubString(@sTempArg,@iLimit,1)
--!! print ' @iLimitg='+cast(@iLimit as varchar)
set @sTempArg = SubString(@sTempArg,@iLimit+1,@iOperand-@iLimit-1)
--!! print ' излез лев @sTempArg='+@sTempArg
end
else
begin -- десен аргумент
set @iLimit = @iOperand + 1
--!! print ' десен аргумент'
--!! print ' @iLimit=' + Str(@iLimit) + '#' + SubString(@sTempArg,@iLimit,1)
set @iLimit = @iLimit+1
--!! print ' Извештавање...'
while (@iLimit <= Len(@sTempArg)) and not (SubString(@sTempArg,@iLimit,1) in ('+','-','/','*','\','|'))
set @iLimit = @iLimit+1
--!! print ' @iLimit=' + Str(@iLimit) + '#' + SubString(@sTempArg,@iLimit,1)
set @sTempArg = SubString(@sTempArg,@iOperand+1,@iLimit-@iOperand-1)
--!! print ' излез десен @sTempArg='+@sTempArg
end
if @sTempArg = ''
begin
if SubString(@sExpression,@iOperand,1) in ('+','-') -- ова е за -x / +x обработка
set @mResult = 0
else
set @sEr = 'Невалидна употреба на оператори во '+@sExpression
end
else
begin
--!! print ' излез @sTempArg='+@sTempArg
set @mResult = Convert(float,@sTempArg,2)
--!! print ' излез @mResult='+Str(@mResult,35,15)
-- !! проверете за грешка тука !! Обработка на исклучоци !!
-- if code <> 0 then
-- er = @sExpression+'не е број!'
-- else
-- begin
set @iLimit = @iLimit - 1
-- end
end
Главна процедура, која израчунува израз
create procedure [dbo].[dl_PA_ParseAritNew]
@sExpression varchar(8000),
@rResult float output,
@sEr varchar(8000) output -- @sEr = ''<- без грешка, @sEr <> '' <- грешка во изразот
-- Внимание ! ---
-- Функцијата секогаш повикај како ParseArit(0,израз,'+',er) !!!!!
-- Во изразот не смее да има празни места "2+3" = ОК / "2 + 3" <> ОК !!!!
-- Во изразот не смее да има небалансирани загради (погледни тест 2)!
-- (c) А. Мертелј, 1997, 2002
as
declare
@iBrackets int, -- броење на загради ()
@i int, -- броење 1
@j int, -- броење 2
@iLen int, -- должина на @sExpression
@iLeftLimit int, -- лев ограничувач
@iRightLimit int, -- десен ограничувач
@rLeft float, -- вредност на лев аргумент
@rRight float, -- вредност на десен аргумент
@lOperatorsExist bit, -- дали имаше оператор во изразот
@sOrigExpression varchar(8000),
@sTemp varchar(8000) -- временска променлива
set nocount on
set @iLen = Len(@sExpression)
set @sOrigExpression = @sExpression
-- исправи "+x" во "x"
if SubString(@sExpression,1,1) = '+'
set @sExpression = Right(@sExpression,@iLen-1)
-- исправи "--x" во "x"
set @sExpression = Replace(@sExpression,'--','')
--!! print 'во функцијата exp = ' +@sOrigExpression
if @sEr = ''
begin -- без грешка на влез
set @lOperatorsExist = 0
-- обработка на загради ()
set @i = Charindex('(',@sExpression)
if @i > 0 -- @i > 0?
begin -- има (,)
--!! print ' -- има загради'
set @lOperatorsExist = 1
set @iBrackets = 1
set @j = @i + 1
while (@j <= @iLen) and (@iBrackets > 0) -- најди прво совпаѓање
begin
if SubString(@sExpression,@j,1) = ')'
set @iBrackets = @iBrackets-1
if SubString(@sExpression,@j,1) = '('
set @iBrackets = @iBrackets+1
set @j = @j + 1
end
set @sTemp = SubString(@sExpression,@i+1,@j-@i-2)
-- израчунај надворешна пар
exec dl_PA_ParseAritNew @sTemp,@rResult output,@sEr output
--!! print ' ()@rResult='+Str(@rResult,25,10)
set @sTemp = LTrim(Str(@rResult,35,15))
--!! print ' ()@sTemp='+@sTemp
set @sTemp = Replace(@sTemp,',','.') -- промени можен ',' во '.'
--!! print ' ()@sTemp, по замена ='+@sTemp
-- замени надворешна пар со резултат
set @sExpression = SubString(@sExpression,1,@i-1)+@sTemp+SubString(@sExpression,@j,@iLen-@j+1)
--!! print ' ()@sExpression=' + @sExpression
end -- има (,)
else -- @i > 0? не, нема (,)
begin -- провери за *,/
set @i = 1
while not (SubString(@sExpression,@i,1) in ('*','/')) and (@i < @iLen)
set @i = @i + 1
if SubString(@sExpression,@i,1) in ('*','/')
begin -- *,/ најдено
--!! print ' -- има *,/ најдено на позиција ' + Str(@i)
set @lOperatorsExist = 1
exec dl_PA_ParserGetArg @sExpression,1,@i,@iLeftLimit output,@rLeft output,@sEr output
exec dl_PA_ParserGetArg @sExpression,0,@i,@iRightLimit output,@rRight output,@sEr output
--!! print ' */@rLeft='+Str(@rLeft,25,15)
--!! print ' */@rRight='+Str(@rRight,25,15)
--!! print ' */@sEr='+@sEr
if @sEr = ''
begin
if SubString(@sExpression,@i,1) = '*'
set @rResult = @rLeft*@rRight
else
if SubString(@sExpression,@i,1) = '/'
exec dl_DivT @rLeft,@rRight,@rResult output
set @sTemp = LTrim(Str(@rResult,35,15))
--!! print ' */@rResult='+Str(@rResult,25,10)
--!! print ' */@sTemp='+@sTemp
set @sTemp = Replace(@sTemp,',','.') -- промени можен ',' во '.'
--!! print ' */@sTemp, по замена ='+@sTemp
--!! print ' */Десен дел=#'+ SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1) + '#'
-- замени *,/ со резултат
if @iLeftLimit > 0
set @sExpression = SubString(@sExpression,1,@iLeftLimit) + @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
else
set @sExpression = @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
--!! print ' */@sExpression(Финално)=' + @sExpression
end
end -- *,/ најдено
else
begin -- провери за делење, мод
set @i = 1
while not (SubString(@sExpression,@i,1) in ('\','|')) and (@i < @iLen)
set @i = @i + 1
if SubString(@sExpression,@i,1) in ('\','|')
begin -- дел, мод најдено
--!! print ' -- има \,| (дел,мод) најдено на позиција ' + Str(@i)
set @lOperatorsExist = 1
exec dl_PA_ParserGetArg @sExpression,1,@i,@iLeftLimit output,@rLeft output,@sEr output
exec dl_PA_ParserGetArg @sExpression,0,@i,@iRightLimit output,@rRight output,@sEr output
--!! print ' \,|@rLeft='+Str(@rLeft,25,15)
--!! print ' \,|@rRight='+Str(@rRight,25,15)
--!! print ' \,|@sEr='+@sEr
if @sEr = ''
begin
if SubString(@sExpression,@i,1) = '\'
begin
if @rRight <> 0
set @rResult = cast((@rLeft / @rRight + 0.0) as int)
else
set @rResult = 0
end
else
if SubString(@sExpression,@i,1) = '|'
begin
if @rRight <> 0
set @rResult = cast(@rLeft as int) % cast(@rRight as int)
else
set @rResult = 0
end
set @sTemp = LTrim(Str(@rResult,35,15))
set @sTemp = Replace(@sTemp,',','.') -- промени можен ',' во '.'
-- замени дел, мод со резултат
if @iLeftLimit > 0
set @sExpression = SubString(@sExpression,1,@iLeftLimit) + @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
else
set @sExpression = @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
end
end -- дел, мод најдено
else
begin -- провери за збир и разлика
set @i = 1
if SubString(@sExpression,@i,1) = '-'
set @i = @i + 1
while not (SubString(@sExpression,@i,1) in ('+','-')) and (@i < @iLen)
set @i = @i + 1
--!! print ' +,- @i='+cast(@i as varchar)
if SubString(@sExpression,@i,1) in ('+','-')
begin -- +,- најдено
--!! print ' -- има +,- најдено на позиција ' + Str(@i)
set @lOperatorsExist = 1
exec dl_PA_ParserGetArg @sExpression,1,@i,@iLeftLimit output,@rLeft output,@sEr output
exec dl_PA_ParserGetArg @sExpression,0,@i,@iRightLimit output,@rRight output,@sEr output
--!! print ' +,- @rLeft='+Str(@rLeft,25,15)
--!! print ' +,- @rRight='+Str(@rRight,25,15)
--!! print ' +,- @sEr='+@sEr
if SubString(@sExpression,@i,1) = '+'
set @rResult = @rLeft + @rRight
else
if SubString(@sExpression,@i,1) = '-'
set @rResult = @rLeft - @rRight
set @sTemp = LTrim(Str(@rResult,35,15))
--!! print ' +-@rResult='+Str(@rResult,25,10)
--!! print ' +-@sTemp='+@sTemp
set @sTemp = Replace(@sTemp,',','.') -- промени можен ',' во '.'
--!! print ' +-@sTemp, по замена ='+@sTemp
-- замени +,- со резултат
if @iLeftLimit > 0
set @sExpression = SubString(@sExpression,1,@iLeftLimit) + @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
else
set @sExpression = @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
--!! print ' +-@sExpression=' + @sExpression
end -- +,- најдено
end -- провери за збир и разлика
end -- провери за делење, мод
end -- провери за множење, делење
if @sEr = ''
begin -- без грешка до сега
if @lOperatorsExist = 1
begin
--!! print ' излез за рекурзија оригинал. @sExpression='+@sExpression+' @sExpression=' + @sExpression
exec dl_PA_ParseAritNew @sExpression,@rResult output,@sEr output -- парсирај со вредност
end
else
begin
--!! print ' излез за оригинал. @sExpression='+@sExpression+' @sExpression=' + @sExpression
set @rResult = Convert(float,@sExpression,2)
end
end -- без грешка до сега
end -- без грешка на влез
Тестни примери
-- тест случај 1
declare
@sExpression varchar(8000),
@mResult money,
@sEr varchar(8000)
set @sExpression='2*3'
set @sEr = ''
--!! print @sExpression
exec dl_PA_ParseAritNew @sExpression, @mResult output,@sEr output
--!! print '-----'
--!! print Str(@mResult,35,15)
--!! print @sEr
--тест случај 2
create table _TEST_PARSER
(
FORMULA varchar(300),
TEST money,
ER varchar(500),
REZULTAT money
)
declare
@sExpression varchar(8000),
@mTest float,
@mResult float,
@i int,
@iBrackets int,
@sEr varchar(8000)
set nocount on
declare crKurzor cursor local fast_forward for
select FORMULA,TEST
from _TEST_PARSER
open crKurzor
fetch next from crKurzor into @sExpression,@mTest
while @@fetch_status = 0
while @@fetch_status = 0
begin
-- провери за баланс на загради
print '--------------------------------------------------------'
print ' Тестирање: ' + @sExpression
print ' Очекуван резултат = ' + Str(@mTest)
set @i = 1
set @iBrackets = 0
while (@i <= Len(@sExpression)) -- провери цел израз
begin
if SubString(@sExpression,@i,1) = ')'
set @iBrackets = @iBrackets-1
if SubString(@sExpression,@i,1) = '('
set @iBrackets = @iBrackets+1
set @i = @i + 1
end
if @iBrackets <> 0
set @sEr = 'Небалансирани загради во ' + @sExpression
else
begin
set @sEr = ''
exec dl_PA_ParseAritNew @sExpression, @mResult output,@sEr output
end
print ' Израчунат резултат = ' + Str(@mResult)
if (@mResult = @mTest)
print ' ОК'
else
print ' Грешка (@mResult - @mTest) = ' + Str(@mResult - @mTest)
print '--------------------------------------------------------'
update _TEST_PARSER
set REZULTAT = @mResult,
ER = @sEr
where LTrim(RTrim(FORMULA)) = LTrim(RTrim(@sExpression))
fetch next from crKurzor into @sExpression,@mTest
end
close crKurzor
deallocate crKurzor
select LTrim(RTrim(FORMULA)) as 'Formula',TEST,REZULTAT,LTrim(RTrim(ER)) as 'ErrorMsg'
from _TEST_PARSER
where (TEST <> REZULTAT) or (TEST is null)