SQL операторларында пайдаланушы анықтайтын функцияларды пайдалану

Новости мира

Мен бұл өмірде мүлдем жаңа ештеңе болмайтыны туралы айтудан шаршадым, ал жаңаның көпшілігі ұмытылған ескі. Міне, тағы бір мысал. Осы мақаланың бір авторы Windows жүйесінде FXP2.6-мен ғана жұмыс істей бастаған қарт, бірақ салыстырмалы түрде жас түлкі, ал екіншісі — ең көне кескіштердің бірі. Сондықтан әдістер әртүрлі. Біріншісінде негізінен жаңа FOX әдістері бар, екіншісінде мәңгілік дерекқор ақиқаттары бар. Ескі рецепттер көбінесе жаңадан шыққан қоңыраулар мен ысқырықтарға қарағанда әлдеқайда жақсы шешімдер береді, өйткені сіз теорияны оқып шыққаныңызға және оларды білуге ​​болатын ескі трюктерді пайдалану өте қиын екенін біле аласыз. Содан кейін, қарғыс атсын, сіз әрқашан жаңа, барған сайын күшті әдістерді сипаттайтын агрессивті Microsoft жарнамасымен аяқталасыз. Көбінесе олардың айтқанына сенесің. Бірақ мұнда біз тривиальды тапсырмаларды алып, оларды жаңа асүйге қойып, дәмді пирогты күтеміз. Оның орнына кейде — бір сасық.
Бұл негізінен сыртқы сол/оң жақ біріктіру тармақтары, біріктіру және топтық функцияларды пайдалану арқылы SQL таңдауы туралы болады.
Алдыңғы мақалалардың бірінде, егер бізде бірнеше қосылыстар болса, сұрау және қарау генераторы осы сөйлемдермен қате кодты беретінін айттық.

Мұндай қате кодтың мысалы:

LEFT OUTTER JOIN dbf_s!valuta;
ON int(pd.currency_id) == int(Currency.currency_id) ;
ON int(pd.kv_izg) == int(Currency_a.currency_id) ;
ON pd.shpz_id = Sc_shpz.shpz_id ;
ON pd.nc_id = bc_ac.nc_id ;
ON pd.country_id = country.country_id ;
ON pd.um_id = Sc_ed.um_id ;
СОЛ СЫРТҚА ҚОСЫЛУ dbf_s!valuta Valuta_a ;
СОЛ СЫРТҚА ҚОСЫЛУ dbf_s!Sc_shpz;
СОЛ СЫРТҚЫ ҚОСЫЛУ dbf_s!bc_ac;
LEFT OUTER JOIN dbf_s!Country ;
СОЛ СЫРТҚА ҚОСЫЛУ dbf_s!Sc_ed
Ал сізге керек —
LEFT OUTTER JOIN dbf_s!valuta;
ON int(pd.currency_id) == int(Currency.currency_id) ;
СОЛ СЫРТҚА ҚОСЫЛУ dbf_s!valuta Valuta_a ;
ON int(pd.kv_izg) == int(Currency_a.currency_id) ;
СОЛ СЫРТҚА ҚОСЫЛУ dbf_s!Sc_shpz;
ON pd.shpz_id = Sc_shpz.shpz_id ;
СОЛ СЫРТҚЫ ҚОСЫЛУ dbf_s!bc_ac;
ON pd.nc_id = bc_ac.nc_id ;
LEFT OUTER JOIN dbf_s!Country ;
ON pd.country_id = country.country_id ;
LEFT OUTER JOIN dbf_s!Sc_ed ;
ON pd.um_id = Sc_ed.um_id
Жақсы, бұл проблема емес. «Алдын ала ескертілген адам қарулы».
Мәселе басқаша — генератор бұған қай жерде сөйлемді қосуға мүмкіндік береді, мұнда бұрыннан қолданылған кестелердің кез келгенін пайдалануға болады.
Дәл осы жерде (әсіресе ондағы where сөйлемі біріктірілген кестелерге қатысты болса) нәтиже мүлдем қате болуы мүмкін. Бірақ белгілі бір уақыт ішінде тауарды алу қажет болса, мұндай шартты қалай қоспауға болады? Немесе прейскуранттағы қажетті есептік кезеңге сәйкес келетін тауардың бағасы? Сіз мұны қосылуға итермелей алмайсыз.
Сыртқы біріктірусіз мүмкін емес сияқты көрінуі мүмкін — кез келген каталогқа сілтеме бос болуы мүмкін және тауарлар қатарын жоғалту қажет емес. Сондықтан, сыртқы біріктіру шарттарын қайда көшіру мүмкін емес. Майкрософт қателерді түзететінін күтеміз, сондықтан біздің тұтынушылар бізді күтпейді және табысты компанияларға немесе бағдарламалық өнімдерге тез жоғалады. Сондықтан, ұнайды немесе жоқ, бірақ дұрыс нәтиже беріңіз.
Біріншіден, сұрауды екіге бөлеміз — біреуі сыртқы біріктіру арқылы, екіншісі — қайда. Ол өте жақсы жұмыс істейді және дұрыс индекстермен жеткілікті жылдам. Дегенмен, кейде әртүрлі шарттар үшін тым көп тармақтарды жазу керек болып шығады. SQL саны және олардың күрделілігі өсуде және өсуде. Сонымен қатар, үстелге тағы бір сыртқы қосылымы бар қосымша каталогтарды қосу керек, оның өзі сыртқы біріктіруде ілулі тұр. Нәтижесінде қателік ықтималдығы да жоғары
үлкен.
Бұл жерде ескі, бірақ кем емес тиімді әдістер құтқаруға келеді. Атап айтқанда:
теңшелетін функцияларды пайдалану. Мұндағы идея Select SQL операторынан сыртқы біріктірулерге байланысты барлық кестелерді алып тастау және пайдаланушы анықтайтын функцияларда осы кестелерден қажетті сілтемелерді іздеу болып табылады. Функция егер сілтеме бар болса, оның мәнін алатындай болуы керек, ал егер жоқ болса, қажетті түрдегі «манекенді» қайтарады. Яғни, сыртқы біріктіру жұмысын өзіңіз жасаңыз. Ол үшін қажет: анықтамалық каталогта ізделетін кілттің аты, анықтамалық кестенің аты, каталогтағы өріс, іздеу жүргізілетін тегтің аты.

Кейбір трюктар.
Каталогтан бір кілт үшін бірнеше түрлі өрістер табылуы керек делік. Іздеу жұмысын екінші рет жүктегім келмейді. Егер каталогта қажетті жазба табылса, басқа өрісті қайта іздеудің қажеті жоқ.
Екінші.
SQL таңдауының бір жағымсыз қасиеті бар: алынған өрістің ұзындығы инициализация уақытында бағаланады. Сондықтан, егер бірінші жазбаға көмек болмаса, бірақ келесіге көмек болса, бос жазба үшін қажетті ұзындықтағы өрісті қайтару керек. Әйтпесе, каталогтағы жазбалар бір әріппен қысқартылады.
Міне, осындай функцияның мысалы
Lпараметрлері pr_id,mydat
Жергілікті реткр

Егер тапсырыс (‘val_course’)!=’datcur’
val_course ішіндегі datcur үшін ретті орнатыңыз
Эндиф
retcr=0
Егер бос (mydat)
дәл өшіру
Егер seek(str(pr_id,3),’val_course’)
retcr=курс
Эндиф
Басқа
Егер орнатылса(‘ЖАҚЫНДА’)=’ӨШІРУЛІ’
Жақын жерге қойыңыз
Эндиф
=seek(str(pr_id,3)+dtos(mydat),’val_course’)
Егер pr_id=val_course.valuta_id болса
retcr=val_course.course
Эндиф
Жақын жерге қойыңыз
Эндиф
retcr қайтару:

Getref функциясы
Lпараметрлері fld,pr_id,tb,tg

Жергілікті fl,tpt,rt,rtt,lnn,fl,fll

fl=tb+’.’+alltrim(fld)
fll=tb+’.’+тг
*** Егер кілт сәйкес келсе, сіз іздей алмайсыз, әйтпесе — біз іздейміз
Егер бос болмаса(pr_id) және ;
(eval(fll)=pr_id немесе search(pr_id,tb,tg))
rtt=бағалау(fl)
rtt қайтару
Басқа
rt=бағалау(fl)
tpt=түрі(‘rt’)
Іспен айналысу
Іс tpt=’N’
rtt=0
Іс tpt=’C’
Lnn=len(бағалау(fl))
rtt=pad(»,lnn)
Іс tpt=’D’
rtt=ctod(‘..’)
Іс tpt=’L’
rtt=.f.
Соңғы регистр
rtt қайтару
Эндиф

Lпараметрлері pr_id,mydat

Жергілікті реткр

Егер тапсырыс (‘val_course’)!=’datcur’
val_course ішіндегі datcur үшін ретті орнатыңыз
Эндиф
retcr=0
Егер бос (mydat)
дәл өшіру
Егер seek(str(pr_id,3),’val_course’)
retcr=курс
Эндиф
Басқа
Егер орнатылса(‘ЖАҚЫНДА’)=’ӨШІРУЛІ’
Жақын жерге қойыңыз
Эндиф
=seek(str(pr_id,3)+dtos(mydat),’val_course’)
Егер pr_id=val_course.valuta_id болса
retcr=val_course.course
Эндиф
Жақын жерге қойыңыз
Эндиф
retcr қайтару

Қолдану мысалы. Бізде келесідей SQL сұрауы болды делік:

doc LEFT OUTER JOIN мәнінен doc.num,val таңдаңыз;
ON doc.currency_id= Currency.currency_id

Енді жазамыз

Doc ішінен val ретінде doc.num getref(‘val’,’doc.valuta_id’,’valuta’,’valuta_id) таңдаңыз

Бұл жерде, әрине, бастапқы мысалға қарағанда қиынырақ болып шықты, бірақ сіз каталогтардан және каталогтардан бірнеше өрістерді қосуға болады және сол sql-де where сөйлемін пайдаланудан қорықпайсыз.

Екінші мысал қиынырақ.
Валюталар кестесі және валюта кілттері, күні мен бағамы бар айырбас бағамдарының кестесі бар. Оның үстіне валюта бағамдарының кестесінде бағамдарды уақыт тәртібі бойынша емес, ерікті түрде жазуға болады. Айырбастау бағамы кестесіндегі кейбір валюталар мүлдем болмауы мүмкін. Дегенмен, барлық валюталарды соңғы бағамымен көрсету қажет.

Бірінші шешім (дұрыс емес):

valuta.valuta_id=vcour.valuta_id бірлігі val,max(dat),cour from valuta, vcour таңдаңыз;
Val, ctod(‘..’), 0 коur ретінде valuta_id жоқ жерде таңдаңыз (vcour ішінен valuta_id таңдаңыз)
Мәселе мынада, жазбалардың бүкіл ауқымында жұмыс істейтін максималды функция дұрыс күнді береді, бірақ жылдамдық соңғы жазбадан. Егер мөлшерлеме хронологиялық тәртіпте енгізілмесе, мөлшерлеме соңғы күннен емес, таңдаудағы күннің өзі соңғы болса да, соңғы жазбадан алынады.
Microsoft стиліндегі шешім дұрыс, бірақ оңтайлы емес.

max(dat) dt,valuta_id ретінде таңдаңыз;
vcour тобын valuta_id арқылы курсорға qr
ішінен ерекше val,cour,dat таңдаңыз;
valuta, vcour, qr;
мұнда currency.currency_id=vcour.currency_id ;
және qr.dt=vcour.dat және ;
qr.currency_id=currency.currency_id ;
одақ ;
Айқын val,1 ретінде cour, ctod(‘..’) valuta-дан dat ретінде таңдаңыз, мұнда ;
valuta.valuta_id жоқ (vcour ішінен бөлек valuta_id таңдаңыз);
курсорға vcou

Атасының келісімі бойынша шешім. Ең жылдам.

Өрнегі бар айырбас бағамы кестесінде даткур құрама индексін құрайық
STR(валюта_идентификаторы,3)+DTOS(деректер)
Getvcr функциясын жасайық
Lпараметрлері pr_id,mydat

Жергілікті реткр

Егер тапсырыс(‘vcour’)!=’datcur’
Vcour ішіндегі dacur үшін ретті орнатыңыз
Эндиф
retcr=0
Егер бос (mydat)
дәл өшіру
Егер seek(str(pr_id,3),’vcour’)
retcr=vcour.cour
Эндиф
Басқа
Егер орнатылған болса(‘ЖАҚЫНДА)=’ӨШІРУЛІ’
Жақын жерге қойыңыз
Эндиф
=seek(str(pr_id,3)+dtos(mydat),’vcour’)
Егер pr_id=vcour.valuta_id болса
retcr=vcour.cour
Эндиф
Жақын жерге қойыңыз
Эндиф
retcr қайтару

Енді Select val,getvcr(valuta.valuta_id) сөзін valuta-дан cour ретінде жазу жеткілікті — және болды.
Белгілі бір күнге курс қажет болса, оны екінші параметрде көрсетіңіз.
Сөйтіп, екі өгізге қатысты анекдот есіме түсті. Жас бала тезірек сиырларға жүгіруге тырысты. Бізге сондай-ақ ескі өгіздің принципі ұнайды — баяу жүрейік, бірақ біз қалағанның барлығына ие боламыз және тіпті жас біреуді басып озармыз.