Një shembull i tillë nuk është aq i lidhur me SQL-InterActive, por më shumë me mënyrën e programimit T-SQL. Sepse e dimë se sa të çmuar janë shembujt e programeve, ne e përfshimë atë në udhëzime.
Shembulli ilustron mirë rekurzivitetin, procedurat e ruajtura. Procedura kryesore është e destinuar për llogaritjen e shprehjeve matematikore që ne i futim në formën e një vargu karakteresh alfanumerik.
Procedurat janë bërë në mënyrë që nëse heqim --!! para komandave print, shohim rrjedhën e ekzekutimit dhe rekurziveve.
Procedura ndihmëse, e cila kthen argumentet
krijo procedurë [dbo].[dl_PA_ParserGetArg]
@sExpression varchar(8000),
@lLeft bit,
@iOperand int,
@iLimit integer output,
@mResult float output,
@sEr varchar(8000) output
-- parametrat e testit
-- shpall
-- @sExpression varchar(8000),
-- @lLeft bit,
-- @iOperand int,
-- @iLimit integer,
-- @mResult money,
-- @sEr varchar(8000)
--
-- vendos @sExpression='2*3'
-- vendos @lLeft=1
-- vendos @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
si
shpall
@sTempArg varchar(8000)
vendos nocount on
vendos @sTempArg = ' '+@sExpression+' ' --kjo është vetëm për të marrë parasysh kufijtë në cikël (për të mos marrë j[0])
vendos @iOperand = @iOperand + 1
--!! print ' @sTempArg='+@sTempArg+'#'
--!! print ' @iOperand=' + Str(@iOperand) + '#' + SubString(@sTempArg,@iOperand,1)
nëse @lLeft=1
fillo -- argumenti i majtë
vendos @iLimit = @iOperand - 1
--!! print ' argumenti i majtë'
--!! print ' @iLimit=' + Str(@iLimit) + '#' + SubString(@sTempArg,@iLimit,1)
ndërsa (@iLimit > 0) dhe jo (SubString(@sTempArg,@iLimit,1) në ('+','-','/','*','\','|'))
vendos @iLimit = @iLimit-1
-- le të kontrollojmë për "-" të paracaktuar për argumentin e majtë.
nëse @iLimit > 1
nëse SubString(@sTempArg,@iLimit,1) = '-'
vendos @iLimit = @iLimit-1
--!! print ' @iLimit=' + Str(@iLimit) + '#' + SubString(@sTempArg,@iLimit,1)
--!! print ' @iLimitg='+cast(@iLimit as varchar)
vendos @sTempArg = SubString(@sTempArg,@iLimit+1,@iOperand-@iLimit-1)
--!! print ' jashtë majtë @sTempArg='+@sTempArg
përfundoni
përndryshe
fillo -- argumenti i djathtë
vendos @iLimit = @iOperand + 1
--!! print ' argumenti i djathtë'
--!! print ' @iLimit=' + Str(@iLimit) + '#' + SubString(@sTempArg,@iLimit,1)
vendos @iLimit = @iLimit+1
--!! print ' Llogaritja...'
ndërsa (@iLimit <= Len(@sTempArg)) dhe jo (SubString(@sTempArg,@iLimit,1) në ('+','-','/','*','\','|'))
vendos @iLimit = @iLimit+1
--!! print ' @iLimit=' + Str(@iLimit) + '#' + SubString(@sTempArg,@iLimit,1)
vendos @sTempArg = SubString(@sTempArg,@iOperand+1,@iLimit-@iOperand-1)
--!! print ' jashtë djathtë @sTempArg='+@sTempArg
përfundoni
nëse @sTempArg = ''
fillo
nëse SubString(@sExpression,@iOperand,1) në ('+','-') -- kjo është për trajtimin e -x / +x
vendos @mResult = 0
përndryshe
vendos @sEr = 'Përdorim të pavlefshëm të operatorëve në '+@sExpression
përfundoni
përndryshe
fillo
--!! print ' jashtë @sTempArg='+@sTempArg
vendos @mResult = Convert(float,@sTempArg,2)
--!! print ' jashtë @mResult='+Str(@mResult,35,15)
-- !! kontrolloni për gabim këtu !! Trajtimi i përjashtimeve !!
-- nëse kodi <> 0 atëherë
-- er = @sExpression+'nuk është një numër!'
-- përndryshe
-- fillo
vendos @iLimit = @iLimit - 1
-- përfundoni
përfundoni
Procedura kryesore, e cila llogarit shprehjen
krijo procedurë [dbo].[dl_PA_ParseAritNew]
@sExpression varchar(8000),
@rResult float output,
@sEr varchar(8000) output -- @sEr = ''<- pa gabim, @sEr <> '' <- gabim në shprehje
-- Paralajmërim ! ---
-- Funksionin gjithmonë thirr si ParseArit(0,shprehje,'+',er) !!!!!
-- Në shprehje nuk duhet të ketë hapësira "2+3" = OK / "2 + 3" <> OK !!!!
-- Në shprehje nuk duhet të ketë kllapa të paekuilibruara (shih testin 2)!
-- (c) A. Mertelj, 1997, 2002
si
shpall
@iBrackets int, -- numri i kllapave ()
@i int, -- numri 1
@j int, -- numri 2
@iLen int, -- gjatësia e @sExpression
@iLeftLimit int, -- kufiri i argumentit të majtë
@iRightLimit int, -- kufiri i argumentit të djathtë
@rLeft float, -- vlera e argumentit të majtë
@rRight float, -- vlera e argumentit të djathtë
@lOperatorsExist bit, -- a kishte ndonjë operator në shprehje
@sOrigExpression varchar(8000),
@sTemp varchar(8000) -- variabël temporal
vendos nocount on
vendos @iLen = Len(@sExpression)
vendos @sOrigExpression = @sExpression
-- korrigjo "+x" në "x"
nëse SubString(@sExpression,1,1) = '+'
vendos @sExpression = Right(@sExpression,@iLen-1)
-- korrigjo "--x" në "x"
vendos @sExpression = Replace(@sExpression,'--','')
--!! print 'në funksion shprehja = ' +@sOrigExpression
nëse @sEr = ''
fillo -- pa gabim në hyrje
vendos @lOperatorsExist = 0
-- trajto kllapat ()
vendos @i = Charindex('(',@sExpression)
nëse @i > 0 -- @i > 0?
fillo -- ka (,)
--!! print ' -- ka kllapa'
vendos @lOperatorsExist = 1
vendos @iBrackets = 1
vendos @j = @i + 1
ndërsa (@j <= @iLen) dhe (@iBrackets > 0) -- gjej ndeshjen e parë
fillo
nëse SubString(@sExpression,@j,1) = ')'
vendos @iBrackets = @iBrackets-1
nëse SubString(@sExpression,@j,1) = '('
vendos @iBrackets = @iBrackets+1
vendos @j = @j + 1
përfundoni
vendos @sTemp = SubString(@sExpression,@i+1,@j-@i-2)
-- llogarit çiftin e jashtëm
exec dl_PA_ParseAritNew @sTemp,@rResult output,@sEr output
--!! print ' ()@rResult='+Str(@rResult,25,10)
vendos @sTemp = LTrim(Str(@rResult,35,15))
--!! print ' ()@sTemp='+@sTemp
vendos @sTemp = Replace(@sTemp,',','.') -- ndrysho ',' të mundshëm në '.'
--!! print ' ()@sTemp, pas zëvendësimit ='+@sTemp
-- zëvendëso çiftin e jashtëm me rezultatin
vendos @sExpression = SubString(@sExpression,1,@i-1)+@sTemp+SubString(@sExpression,@j,@iLen-@j+1)
--!! print ' ()@sExpression=' + @sExpression
përfundoni -- ka (,)
përndryshe -- @i > 0? jo, nuk ka (,)
fillo -- kontrollo për *,/
vendos @i = 1
ndërsa jo (SubString(@sExpression,@i,1) në ('*','/')) dhe (@i < @iLen)
vendos @i = @i + 1
nëse SubString(@sExpression,@i,1) në ('*','/')
fillo -- *,/ u gjet
--!! print ' -- ka *,/ u gjet në pozitën ' + Str(@i)
vendos @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
nëse @sEr = ''
fillo
nëse SubString(@sExpression,@i,1) = '*'
vendos @rResult = @rLeft*@rRight
përndryshe
nëse SubString(@sExpression,@i,1) = '/'
exec dl_DivT @rLeft,@rRight,@rResult output
vendos @sTemp = LTrim(Str(@rResult,35,15))
--!! print ' */@rResult='+Str(@rResult,25,10)
--!! print ' */@sTemp='+@sTemp
vendos @sTemp = Replace(@sTemp,',','.') -- ndrysho ',' të mundshëm në '.'
--!! print ' */@sTemp, pas zëvendësimit ='+@sTemp
--!! print ' */Pjesa e djathtë=#'+ SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1) + '#'
-- zëvendëso *,/ me rezultatin
nëse @iLeftLimit > 0
vendos @sExpression = SubString(@sExpression,1,@iLeftLimit) + @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
përndryshe
vendos @sExpression = @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
--!! print ' */@sExpression(Final)=' + @sExpression
përfundoni
përfundoni -- *,/ u gjet
përndryshe
fillo -- kontrollo për div, mod
vendos @i = 1
ndërsa jo (SubString(@sExpression,@i,1) në ('\','|')) dhe (@i < @iLen)
vendos @i = @i + 1
nëse SubString(@sExpression,@i,1) në ('\','|')
fillo -- div, mod u gjet
--!! print ' -- ka \,| (div,mod) u gjet në pozitën ' + Str(@i)
vendos @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
nëse @sEr = ''
fillo
nëse SubString(@sExpression,@i,1) = '\'
fillo
nëse @rRight <> 0
vendos @rResult = cast((@rLeft / @rRight + 0.0) si int)
përndryshe
vendos @rResult = 0
përfundoni
përndryshe
nëse SubString(@sExpression,@i,1) = '|'
fillo
nëse @rRight <> 0
vendos @rResult = cast(@rLeft si int) % cast(@rRight si int)
përndryshe
vendos @rResult = 0
përfundoni
vendos @sTemp = LTrim(Str(@rResult,35,15))
vendos @sTemp = Replace(@sTemp,',','.') -- ndrysho ',' të mundshëm në '.'
-- zëvendëso div, mod me rezultatin
nëse @iLeftLimit > 0
vendos @sExpression = SubString(@sExpression,1,@iLeftLimit) + @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
përndryshe
vendos @sExpression = @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
përfundoni
përfundoni -- div, mod u gjet
përndryshe
fillo -- kontrollo për shtesa dhe zbritje
vendos @i = 1
nëse SubString(@sExpression,@i,1) = '-'
vendos @i = @i + 1
ndërsa jo (SubString(@sExpression,@i,1) në ('+','-')) dhe (@i < @iLen)
vendos @i = @i + 1
--!! print ' +,- @i='+cast(@i as varchar)
nëse SubString(@sExpression,@i,1) në ('+','-')
fillo -- +,- u gjet
--!! print ' -- ka +,- u gjet në pozitën ' + Str(@i)
vendos @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
nëse SubString(@sExpression,@i,1) = '+'
vendos @rResult = @rLeft + @rRight
përndryshe
nëse SubString(@sExpression,@i,1) = '-'
vendos @rResult = @rLeft - @rRight
vendos @sTemp = LTrim(Str(@rResult,35,15))
--!! print ' +-@rResult='+Str(@rResult,25,10)
--!! print ' +-@sTemp='+@sTemp
vendos @sTemp = Replace(@sTemp,',','.') -- ndrysho ',' të mundshëm në '.'
--!! print ' +-@sTemp, pas zëvendësimit ='+@sTemp
-- zëvendëso +,- me rezultatin
nëse @iLeftLimit > 0
vendos @sExpression = SubString(@sExpression,1,@iLeftLimit) + @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
përndryshe
vendos @sExpression = @sTemp + SubString(@sExpression,@iRightLimit,Len(@sExpression)-@iRightLimit+1)
--!! print ' +-@sExpression=' + @sExpression
përfundoni -- +,- u gjet
përfundoni -- kontrollo për shtesa dhe zbritje
përfundoni -- kontrollo për shumëzime, ndarje
nëse @sEr = ''
fillo -- pa gabim deri tani
nëse @lOperatorsExist = 1
fillo
--!! print ' jashtë për rekurzion origjinale @sExpression='+@sExpression+' @sExpression=' + @sExpression
exec dl_PA_ParseAritNew @sExpression,@rResult output,@sEr output -- analizoni me vlerë
përfundoni
përndryshe
fillo
--!! print ' jashtë për origjinale @sExpression='+@sExpression+' @sExpression=' + @sExpression
vendos @rResult = Convert(float,@sExpression,2)
përfundoni
përfundoni -- pa gabim deri tani
përfundoni -- pa gabim në hyrje
Shembuj testimi
-- rasti i testit 1
shpall
@sExpression varchar(8000),
@mResult money,
@sEr varchar(8000)
vendos @sExpression='2*3'
vendos @sEr = ''
--!! print @sExpression
exec dl_PA_ParseAritNew @sExpression, @mResult output,@sEr output
--!! print '-----'
--!! print Str(@mResult,35,15)
--!! print @sEr
--rasti i testit 2
krijo tabelë _TEST_PARSER
(
FORMULA varchar(300),
TEST money,
ER varchar(500),
REZULTAT money
)
shpall
@sExpression varchar(8000),
@mTest float,
@mResult float,
@i int,
@iBrackets int,
@sEr varchar(8000)
vendos nocount on
shpall crKurzor cursor lokal fast_forward për
select FORMULA,TEST
from _TEST_PARSER
hap crKurzor
merr nesër nga crKurzor në @sExpression,@mTest
ndërsa @@fetch_status = 0
ndërsa @@fetch_status = 0
fillo
-- kontrollo për ekuilibrin e kllapave
print '--------------------------------------------------------'
print ' Testimi: ' + @sExpression
print ' Rezultati i pritur = ' + Str(@mTest)
vendos @i = 1
vendos @iBrackets = 0
ndërsa (@i <= Len(@sExpression)) -- kontrollo të gjithë shprehjen
fillo
nëse SubString(@sExpression,@i,1) = ')'
vendos @iBrackets = @iBrackets-1
nëse SubString(@sExpression,@i,1) = '('
vendos @iBrackets = @iBrackets+1
vendos @i = @i + 1
përfundoni
nëse @iBrackets <> 0
vendos @sEr = 'Kllapat e paekuilibruara në ' + @sExpression
përndryshe
fillo
vendos @sEr = ''
exec dl_PA_ParseAritNew @sExpression, @mResult output,@sEr output
përfundoni
print ' Rezultati i llogaritur = ' + Str(@mResult)
nëse (@mResult = @mTest)
print ' OK'
përndryshe
print ' Gabim (@mResult - @mTest) = ' + Str(@mResult - @mTest)
print '--------------------------------------------------------'
përditëso _TEST_PARSER
vendos REZULTAT = @mResult,
ER = @sEr
ku LTrim(RTrim(FORMULA)) = LTrim(RTrim(@sExpression))
merr nesër nga crKurzor në @sExpression,@mTest
përfundoni
mbyll crKurzor
deallocate crKurzor
select LTrim(RTrim(FORMULA)) as 'Formula',TEST,REZULTAT,LTrim(RTrim(ER)) as 'ErrorMsg'
from _TEST_PARSER
ku (TEST <> REZULTAT) ose (TEST është null)