仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 608|回复: 8
打印 上一主题 下一主题

[学习教程] MSSQL网页编程之变异表的成绩

[复制链接]
分手快乐 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-1-16 22:33:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
如果WHERE子句的查询条件里使用比较操作符LIKE和REGEXP,MySQL只有在搜索模板的第一个字符不是通配符的情况下才能使用索引。比如说,如果查询条件是LIKEabc%‘,MySQL将使用索引;如果查询条件是LIKE%abc’,MySQL将不使用索引。成绩
在论坛中常常碰到变异表的成绩,我保藏了一片有关变异表成绩的文章,如今把他放在这里,但愿能和人人分享!



AvoidingMutatingTables


Ok,soyouvejustrecievedtheerror:
ORA-04091:tableXXXXismutating,trigger/functionmaynotseeit

andyouwanttogetaroundthat.Thisshortarticlewilldescribeanddemonstratethevariousmethodsofgettingaroundthemutatingtableerror.

Ifyouareinterestedinwhyyouaregettingitandinwhatcasesyouwillgetit,pleaseseetheOracleServerApplicationDevelopersGuide(clickheretoreaditrightnow--thislinkistotechnet.oracle.com.Youneedapasswordtoaccessthissitebutyoucangetonerightawayforfree).

Avoidingthemutatingtableerrorisfairlyeasy.WemustdeferprocessingagainstthemutatingorconstrainngtableuntilanAFTERtrigger.Wewillconsidertwocases:


HittingtheORA-4091inanINSERTtriggeroranUPDATEtriggerwhereyouonlyneedaccesstothe:newvalues
HittingtheORA-4091inaDELETEtriggeroranUPDATEtriggerwhereyouneedtoaccessthe:oldvalues
Case1-youonlyneedtoaccessthe:newvalues
Thiscaseisthesimplest.WhatwewilldoiscapturetheROWIDSoftheinsertedorudpatedrows.WecanthenusetheseROWIDSinanAFTERtriggertoqueryuptheaffectedrows.
Italwaystakes3triggerstoworkaroundthemutatingtableerror.Theyare:


Abeforetriggertosetthepackagestatetoaknown,consistentstate
Anafter,rowleveltriggertocaptureeachrowschanges
Anaftertriggertoactuallyprocessthechange.
Asanexample--toshowhowtodothis,wewillattempttoanswerthefollowingquestion:

Ihaveatablecontainingakey/status/effectivedatecombination.Whenstatus
changes,thevaluesarepropagatedbytriggertoalogtablerecordingthe
statushistory.WhennoRIconstraintisinplaceeverythingworksfine.
WhenanRItriggerenforcesaparent-childrelationship,thestatuschange
loggingtriggerfailsbecausetheparenttableismutating.Propagatingthe
valuestothelogtableimplicitlygeneratesalookupbacktotheparenttable
toensuretheRIconstraintissatisfied.

IdonotwanttodroptheRIconstraint.Irealizethatthestatusis
denormalized.Iwantitthatway.Whatisagoodwaytomaintainthelog?

Hereistheimplementation:

SQL>createtableparent
2(theKeyintprimarykey,
3statusvarchar2(1),
4effDatedate
5)
6/
Tablecreated.

SQL>createtablelog_table
2(theKeyintreferencesparent(theKey),
3statusvarchar2(1),
4effDatedate
5)
6/
Tablecreated.

SQL>REMthispackageisusedtomaintainourstate.Wewillsavetherowidsofnewly
SQL>REMinserted/updatedrowsinthispackage.Wedeclare2arrays--onewill
SQL>REMholdournewrowsrowids(newRows).Theotherisusedtoresetthisarray,
SQL>REMitisanemptyarray

SQL>createorreplacepackagestate_pkg
2as
3typeridArrayistableofrowidindexbybinary_integer;
4
4newRowsridArray;
5emptyridArray;
6end;
7/
Packagecreated.

SQL>REMWemustsetthestateoftheabovepackagetosomeknown,consistentstate
SQL>REMbeforewebeingprocessingtherowtriggers.Thistriggerismandatory,
SQL>REMwe*cannot*relyontheAFTERtriggertoresetthepackagestate.This
SQL>REMisbecauseduringamulti-rowinsertorupdate,theROWtriggermayfire
SQL>REMbuttheAFTERtirggerdoesnothavetofire--ifthesecondrowinanupdate
SQL>REMfailsduetosomeconstrainterror--therowtriggerwillhavefired2times
SQL>REMbuttheAFTERtrigger(whichwereliedontoresetthepackage)willneverfire.
SQL>REMThatwouldleave2erroneousrowidsinthenewRowsarrayforthenextinsert/update
SQL>REMtosee.Therefore,beforetheinsert/updatetakesplace,wereset

SQL>createorreplacetriggerparent_bi
2beforeinsertorupdateonparent
3begin
4state_pkg.newRows:=state_pkg.empty;
5end;
6/
Triggercreated.

SQL>REMThistriggersimplycapturestherowidoftheaffectedrowand
SQL>REMsavesitinthenewRowsarray.

SQL>createorreplacetriggerparent_aifer
2afterinsertorupdateofstatusonparentforeachrow
3begin
4state_pkg.newRows(state_pkg.newRows.count+1):=:new.rowid;
5end;
6/
Triggercreated.

SQL>REMthistriggerprocessesthenewrows.WesimplyloopoverthenewRows
SQL>REMarrayprocessingeachnewlyinserted/modifiedrowinturn.

SQL>createorreplacetriggerparent_ai
2afterinsertorupdateofstatusonparent
3begin
4foriin1..state_pkg.newRows.countloop
5insertintolog_table
6selecttheKey,status,effDate
7fromparentwhererowid=state_pkg.newRows(i);
8endloop;
9end;
10/
Triggercreated.

SQL>REMthisdemonstratesthatwecanprocesssingleandmulti-rowinserts/updates
SQL>REMwithoutfailure(andcandoitcorrectly)

SQL>insertintoparentvalues(1,A,sysdate-5);
1rowcreated.

SQL>insertintoparentvalues(2,B,sysdate-4);
1rowcreated.

SQL>insertintoparentvalues(3,C,sysdate-3);
1rowcreated.

SQL>insertintoparentselecttheKey+6,status,effDate+1fromparent;
3rowscreated.

SQL>select*fromlog_table;

THEKEYSEFFDATE
--------------------
1A04-AUG-99
2B05-AUG-99
3C06-AUG-99
7A05-AUG-99
8B06-AUG-99
9C07-AUG-99

6rowsselected.

SQL>updateparentsetstatus=chr(ascii(status)+1),effDate=sysdate;
6rowsupdated.

SQL>select*fromlog_table;

THEKEYSEFFDATE
--------------------
1A04-AUG-99
2B05-AUG-99
3C06-AUG-99
7A05-AUG-99
8B06-AUG-99
9C07-AUG-99
1B09-AUG-99
2C09-AUG-99
3D09-AUG-99
7B09-AUG-99
8C09-AUG-99
9D09-AUG-99

12rowsselected.


Case2-youneedtoaccessthe:oldvalues
Thisoneisalittlemoreinvolvedbuttheconceptisthesame.WellsavetheactualOLDvaluesinanarray(asopposedtojusttherowidsofthenewrows).Usingtablesofrecordsthisisfairlystraightforward.Letssaywewantedtoimplementaflagdeleteofdata--thatis,insteadofactuallydeletingtherecord,youwouldliketosetadatefieldtoSYSDATEandkeeptherecordinthetable(buthideitfromqueries).Weneedtoundothedelete.
InOracle8.0andup,wecoulduse"INSTEADOF"triggersonaviewtodothis,butin7.3theimplementationwouldlooklikethis:


SQL>REMthisisthetablewewillbeflagdeletingfrom.
SQL>REMNoonewilleveraccessthistabledirectly,rather,
SQL>REMtheywillperformallinsert/update/delete/selectsagainst
SQL>REMaviewonthistable..

SQL>createtabledelete_demo(aint,
2bdate,
3cvarchar2(10),
4hidden_datedatedefaultto_date(01-01-0001,DD-MM-YYYY),
5primarykey(a,hidden_date))
6/
Tablecreated.

SQL>REMthisisourview.AllDMLwilltakeplaceontheview,thetable
SQL>REMwillnotbetouched.

SQL>createorreplaceviewdelete_demo_viewas
2selecta,b,cfromdelete_demowherehidden_date=to_date(01-01-0001,DD-MM-YYYY)
3/
Viewcreated.

SQL>grantallondelete_demo_viewtopublic
2/
Grantsucceeded.

SQL>REMhereisthestatepackageagain.Thistimethearrayisof
SQL>REMTABLE%ROWTYPE--notjustarowid

SQL>createorreplacepackagedelete_demo_pkg
2as
3typearrayistableofdelete_demo%rowtypeindexbybinary_integer;
4
4oldvalsarray;
5emptyarray;
6end;
7/
Packagecreated.

SQL>REMtheresettrigger...

SQL>createorreplacetriggerdelete_demo_bd
2beforedeleteondelete_demo
3begin
4delete_demo_pkg.oldvals:=delete_demo_pkg.empty;
5end;
6/
Triggercreated.

SQL>REMHere,insteadofcapturingtherowid,wemustcapturethebeforeimage
SQL>REMoftherow.
SQL>REMWecannotreallyundothedeletehere,wearejustcapturingthedeleted
SQL>REMdata

SQL>createorreplacetriggerdelete_demo_bdfer
2beforedeleteondelete_demo
3foreachrow
4declare
5inumberdefaultdelete_demo_pkg.oldvals.count+1;
6begin
7delete_demo_pkg.oldvals(i).a:=:old.a;
8delete_demo_pkg.oldvals(i).b:=:old.b;
9delete_demo_pkg.oldvals(i).c:=:old.c;
10end;
11/
Triggercreated.

SQL>REMNow,wecanputthedeleteddatabackintothetable.WeputSYSDATE
SQL>REMinasthehidden_datefield--thatshowsuswhentherecordwasdeleted.

SQL>createorreplacetriggerdelete_demo_ad
2afterdeleteondelete_demo
3begin
4foriin1..delete_demo_pkg.oldvals.countloop
5insertintodelete_demo(a,b,c,hidden_date)
6values
7(delete_demo_pkg.oldvals(i).a,delete_demo_pkg.oldvals(i).b,
8delete_demo_pkg.oldvals(i).c,sysdate);
9endloop;
10end;
11/
Triggercreated.

SQL>REMNow,toshowitatwork...
SQL>insertintodelete_demo_viewvalues(1,sysdate,Hello);
1rowcreated.

SQL>insertintodelete_demo_viewvalues(2,sysdate,Goodbye);
1rowcreated.

SQL>select*fromdelete_demo_view;

ABC
-----------------------------
109-AUG-99Hello
209-AUG-99Goodbye

SQL>deletefromdelete_demo_view;
2rowsdeleted.

SQL>select*fromdelete_demo_view;
norowsselected

SQL>select*fromdelete_demo;

ABCHIDDEN_DA
--------------------------------------
109-AUG-99Hello09-AUG-99
209-AUG-99Goodbye09-AUG-99




BDB源自BerkeleyDB,事务型数据库的另一种选择,支持COMMIT和ROLLBACK等其他事务特性
飘灵儿 该用户已被删除
沙发
发表于 2015-1-19 16:28:14 | 只看该作者
从底层原理到表层引用,书籍多的很。个人认为没有什么那本书好?这样的说法。主要看和个人的学习方法是否适合。
蒙在股里 该用户已被删除
板凳
发表于 2015-1-25 10:53:19 | 只看该作者
两个月啃那本sqlserver2005技术内部-存储引擎,花了几个月啃四本书
再现理想 该用户已被删除
地板
发表于 2015-2-2 21:46:52 | 只看该作者
两个月啃那本sqlserver2005技术内部-存储引擎,花了几个月啃四本书
若天明 该用户已被删除
5#
发表于 2015-2-8 07:31:30 | 只看该作者
SQLServer的异构移植功能个人感觉最好了。(如果对比过SQLServer的链接服务器和Oracle的透明网关的朋友会发现SQLServer的sp_addlinkedserver(openquery)异构数据库系列比Oracle真是强太多了。)
灵魂腐蚀 该用户已被删除
6#
发表于 2015-2-25 00:17:30 | 只看该作者
需要注意的一点,也是我使用过程中发现的一个问题。在建立function->schema->table后,如果在现有的分区表上建立没有显式声明的聚集索引时,分区表会自动变为非分区表。这一点很让我纳闷。
admin 该用户已被删除
7#
发表于 2015-3-7 14:41:01 | 只看该作者
对递归类的树遍历很有帮助。个人感觉这个真是太棒了!阅读清晰,非常有时代感。
小魔女 该用户已被删除
8#
发表于 2015-3-15 07:40:50 | 只看该作者
我是新手,正在学习数据库和操作系统,深感理论的泛广,唯有一步一步来,但是又感觉时间不够,收集了很多资料却总是没能认真的看完,希望有一个讨论板块,大家共同解决,共同分享,共同努力
9#
发表于 2015-3-21 22:08:44 | 只看该作者
现在是在考虑:如果写到服务器端,我一下搞他个10个存储过程导过去,那久之服务器不就成垃圾箱了吗?即便优化了我的中间层.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-12-23 17:34

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表