|
|
用户名:zuoyl2000 笔名:思絮 地区: 北京-北京 行业:其他 |
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
爱情,可以burn,可以exist,但是,他们不能共存。有些男人是可以陪你化蝶的,他懂得给你大束的鲜花,懂得在anniversary时放焰火,可是,朝生暮死…我不能,但是,我可以做一只海龟,呆呆的,笨笨的,一直陪着你老去…… 我住长江头,君住长江尾;日日思君不见君,共饮长江水。
爱你的心,千载不变!
(作者置顶)
当爱已成往事
(作者置顶)
我开始提笔写我们的这段爱情故事。但此刻我还是无从下笔。我感觉无法表达,无法诉说这段情,这份爱。即使我等了整整一落千丈年来平静我的心情。
虽然和你分别后的一年来几乎每一天你的浅笑,你的言语,都从不曾离开过我,但我不得不承认,开始越来越淡越来越模糊。我开始怀疑自已是不是快要将你忘记?然而,我知道:刻骨铭心的东西又怎么会那么容易的逝去(永远不会)?
曾经我告诉自己,无论我们的结局如何,我都会把它写成一篇文字。结局来得很快。但我也不曾想到,写这篇文字竟然整整等了一年。
我想:晚一些写,也许可以正确的面对这个结局,可以客观的评定我们之间谁是谁非。可是,直到今晚,只要是很认真的回想我们那不长久但很纯真的爱时,我的心就依然颤痛不已。
写到这,我惨然一笑,为那一句--风中的承诺!
一年来,我都看到一双眼睛,那晚在昏黄路灯下的眼睛。就是那双眼睛让我平静如水的心开始狂乱不已。直到今天我也不知道:那晚,我是怎么从你偷去我心的眼光里匆匆逃走的。我怎么会不懂得了你的眼睛。
你拉开我拉你的手,带着那颗我乱跳不已的心,我
在读懂你眼里写得是什么的时候,却不知所措。我知道:爱,就在那一刻从我身边擦身而过。一年来,我试着承受那道眼神,但每次我都身心疲惫。
如果,那一刻...
长长而寂寞的夜里,我看到我披着那件二千年的长袍伫立风中;我曾经为此长啸,为此狂歌;但竟是它禁锢着我,是它阻止着我--那一刻本可以相 抱相拥!
是苦涩吗?我问自已,我们无言的结局。
在那以前,我以为那就是爱了,可以穷尽我一生的爱。我们默契的眼神,我们一起跳动的心,我知道你看出我的眼里满是温存。而我从你的信里知道:你却仍然希望听到那句-我23年从不曾说出口的话。是我的信念不够坚定吗?还是那句话才是:真爱!?
直到如今,我仍不知道你为何离去?在我那么需要你的时候!你什么理由也没说,只是在那以后每一封信里暗示说:你已太累。
分手无需理由,爱本没有对错;这点我懂.
这一年多来,我仍旧无法舍弃那一丝牵挂,因为它已溶进了我的血里我的生命里。但我似乎懂得了很多:什么才可以留住那依水的红颜,什么才能绊住那天边的游子。
但我已知爱已成为往事。
论女大学生当妓女
kiss的十大功劳
I LOVE YOU真正的含义
I-Inject ---- 投入
L-Loyal ---- 忠诚
O-Observant ---- 用心
V-Valiant ---- 勇敢
E-Enjoyment ---- 喜悦
Y-Yes ---- 愿意
O-Obligation ---- 责任
U-Unison ---- 和谐
所以爱,就是投入、忠诚、用心、勇敢、喜悦、愿意、责任,还有和谐
『感悟』爱一个人
女人聪明那是因为不够爱你
有一位女友,是朋友圈里公认的情感专家。朋友们所有的情感问题:热恋,失恋,暗恋,三角恋,到了她那儿,只需稍加点拨,便统统迎刃而解。于是便想,这样精明伶俐的女子,倘若爱了,必定是优雅从容风情无限。如果说爱情是场战争,那么她自然便是两军对垒时指挥三军的大帅,或进或退,或松或紧,挥洒自如,游刃有余。可事实上,到后来她自己真正投入地爱了时,却全然换了另一副模样。
她一天十几遍地缠着他问:“你爱我吗?有多爱呢?”得到他肯定的答复,便笑逐颜开,欢欢喜喜地去为他洗手做羹汤;倘若他有丝毫的怠慢和厌倦,她便自怨自艾,是不是我今天的衣服不够漂亮?是不是我比不上他办公室新来的MM有风情? 可是之前,她曾经几番教导朋友们:无论多爱他,也不要失去自己,你要有足够的自信,才会吸引他。 朋友们常常找不到她,因为她的手机换了新的号码,她深情地对那个男人说:“这是只为一个人开的号码,是我们的爱情通道。”她会毫不犹豫地推掉朋友的聚会,匆匆忙忙地回家洗他的臭袜子;她喜气洋洋地对同事说:“我今天在专卖店看到一款新上市的休闲服,正配他的气质肤色……” 可是之前,她曾经告诫姐妹们:爱情之外,还有更广阔的天空,你越在乎他,他越不把你放在心上…… 这个爱情沦陷中的女子,先前的精明机智已经无影无踪,像所有的凡俗的女人一样,爱了,便傻了。爱了,所有的刀枪剑戟便统统收仓入库,一切的技巧手段都忘得一干二净,只剩下一个心思:爱他。那么笨、那么傻、那么痴地爱他。 有什么办法呢?爱了,就傻了。《胭脂扣》里的如花,多么聪慧的一个女子,可是为了她爱而不得的十二少,情愿陪他一起去死。这份痴傻,真是到了极至。 判断一个女人爱不爱你,最简单的标准就是:她在你面前是不是傻得一塌糊涂。如果她进退有度从容不迫,连什么时候打电话、隔多久见一次面都掌握得分毫不差,那就说明她还不够爱你。相反,她一天问你十几遍到底爱不爱她;她刚刚还在生气,发誓再也不理你,可是转脸又忍不住打电话给你;她一直喜欢吃甜的,可是和你在一起,她做的菜里全都放了红红的辣椒,因为你喜欢;外出的时候突然下起了雨,她不避,却慌忙迎着雨去给你送伞,结果自己淋得像落汤鸡……若是你身边正好有这样的傻女子,请你一定珍惜她。
男欢女爱 你们到了哪一步
从相识到相知再到相恋相守,是男女之间的了解逐步深入、默契日益增加和感情愈渐浓厚的过程。但情感的深浅又不完全同相处的时间长短成正比关系。不如来看看晓晓经过多年的理论和实践结合,列出的如下另类恋爱进阶表,自我检测爱情进行到哪一步了。
第一步:看电影。男女双方初初结识,最适合去影院看电影,只要跟着故事发展交换看法,不怕没有话题。可别以为看电影只要买两张票很简单,其实从中可以揣摩出不少对方不经意间流露的自我。如果他擅自选择你根本不喜欢的科幻题材影片,甚至恐怖片,那么你等影片结束就可以跟对方说拜拜。而对方事先为你准备了什么样的零食饮料、是不是电影看到一半手机兀自响起来、有没有趁着黑暗悄悄拉你的手,都是值得考察的。 看电影这关pass后,就该吃饭了。这里指的可不是一般冠冕堂皇地吃王品、采蝶轩或MontheBund。相交不深的时候,选择环境好的餐饮场所是最保险的,只要有一方钱包够鼓。停留在这一阶段的男女,还只是在对感情相互试探。其实,两人感情逐渐熟络起来的标志之一就是开始不吃情调吃实惠。吃饭就单纯地以填饱肚子为目的, 肯德基、大食代、新亚大包都可以考虑,甚至必要的时候路边摊也能吃出温馨甜蜜。当然,要是他吃完后直接用指甲抠牙缝,再伸出舌头舔一下油腻腻的嘴巴,你可以考虑马上把感情退回上一个阶段。 逛街是女孩最常用的考验武器,能对他体力+脑力来一个综合测试。如果两人看似默契,在大商场里一个试穿得不亦乐乎,一个买单得不觉辛苦,未必是亲密的一对。倒是一搭一档,一个唱红脸一个唱白脸,和营业员讨价还价得手后,背地里一起偷笑的才是真正的爱人同志。感情更深厚的两个人还会相约去陕西路、长乐路的小店淘宝,享受更多讲价带来的乐趣和实惠。不过曾看到过让我瞠目结舌的一幕,很难判断两者的关系程度。那是一对男女从某品牌内衣的试衣间一同走出来,营业员热情地问,试穿效果怎么样,那相貌平平的男人一语惊人:好是蛮好,就是太贵了。然后把小巧的内衣还给营业员,携女友扬长而去。 感情日渐加深,两人的浪漫越来越从平凡生活中细细溢出,而不仅仅是甜言蜜语和玫瑰钻石。她愿意双休日素面朝天去他的小屋打扫下厨看碟,他自告奋勇陪她去很远的地方烫发补牙。敢于在对方面前暴露自己太过真实的面目需要一定的勇气和对感情的笃信,尤其是病恹恹的样子既有可能博得他怜香惜玉的恻隐之心,激发他大表爱心让两人感情飞跃前进,也要做好暴露的时机不成熟可能吓到对方的准备。 爱意在细节中涌动,关切和体恤蕴含在言语、眼神和行动中。但如果感情平淡如水,一方不再舍得花钱花心思去为另一方制造小惊喜,那么这段关系是否值得再进一步也需要打一个问号。看到这里,或许你仍然为自己在对方心里到底占有多少比重而疑惑,又或许为和对方到底是否到了谈婚论嫁的地步而迷茫,最简单的方法就是,想一想让你们彼此心动和感动的事情发生在几天前、几周前还是几个月前吧。
女孩子满脑子都是色情
会错意(一)
下午coffee time,总经理走近四个女同事旁,“美丽小姐儿们,要不要猜谜啊?嘻嘻……好啦注意听,猜人身上的东西: 上面有毛,下面也有毛,晚上就来个毛对毛。”“唉呀呀,总经理好色,人家不来了啦!” “喂喂,别想歪了,答案是‘眼睛’”
会错意(二)
打卡时,总经理对女同事们说:“美丽的小姐们!要不要来个脑筋急转弯?” 众脂粉们心想,又来了。听好喔:“什么东西最硬?女孩子最喜欢,特别是结了婚的女人,更是爱死了。脑筋急转弯!开始!” 众脂粉们又开始脸红了,低头都想走开。 “喂喂!还没说出答案啊?” “不来了啦,总经理你最色了啦!” “喂喂!又想到哪去了?答案是【钻石】啦!”
会错意(三)
“总经理!今天不玩猜谜啦?” “这个很难猜,你们一定猜不出来。” “哼?谁说的?”众小姐们不服输地娇嗔着。 好!那仔细听好。猜人类的一种东西: “一种玩意儿,可长可短,西方人比较长,东方人比较短。” 众小姐又开始脸红了,开始故作娇羞状。 “唉呀!讨厌啦!再给一些提示嘛?” “好好,提示:结婚后,妻子就可用丈夫的这个东西。” “唉呀呀,为什么结婚前就不能用?”一位稍八婆的mm挑逗问道。 “如果硬要用,会让人耻笑:成何体统?” “唉呀!讨厌啦!再给一些提示嘛”众小姐又在故作矜持。 “好好,提示:出家人都不会用它。” “那…那……尼姑会想到用它吗?”那mm再问。 “尼姑也不用,她们用更长更长的东东。” “哇!哇?”众小姐发出无比羡慕渴望的娇呼声。 “怎样?猜不出来吧?很难猜,你们就不信。” “它是不是有时大?有时小?”还是那个mm在问。 “嗯??没错!当看他比较大,你就说他是:【大】那个; 如果 看他比较小,你就说他是:【小】那个,像最近打职棒的就用大小来分。” “唉呀呀!好下流,用【这个】来分?”众小姐低声议论纷纷。 众小姐早已认定答案就是“那个”,只是羞得说不出口。 忽见窗外,董事长座车驶进大门了,众小姐赶紧要回位子了。 “喂喂! 们还没猜出来啊?” “唉呀!不来了啦!总经理好色!” “喂喂!想到哪去了!答案是姓名的【姓】啊。”
会错意(四)
总经理又在玩猜谜的玩意儿。
“各位美丽的小姐儿们,猜个谜语吧?猜人身上的一种东西:
舔也硬,不舔也硬,要舒服睡觉,先搓搓它”
众小姐又开始脸红了……
“唉呀!不来了啦!总经理好色!”
“喂喂!想到哪儿去了!答案是【牙齿】啦。”
会错意(五)
“各位美丽的小姐儿们,猜个谜语吧?仔细听好猜一句成语喔!总不会再想歪了吧:
心里很想要,好想要,好兴奋,又想得要命,结果洞口就慢慢开始流出水来了。”
“唉呀!妈呀!这么不要脸的总经理。”小姐们心里如此骂着!
“怎样?猜不到了吧!嘿嘿嘿!”
“那个…那个是不是会张很开?”38婆故作羞赧地问道。
“没错!而且都一直大大张开着。而且水流得更多。”
“讨厌啦!讨厌啦!不来了啦!总经理好色。”
“喂喂!猜不来就别乱讲,答案是【垂涎三尺】啦。”
会错意(七)
“嗨!美丽的小姐儿们!” “总经理好!今天还要猜谜吗?” “不啦!每次都说我好色,不要了啦!”总经理满脸无辜样子。 “好嘛好嘛!我们不说就是了嘛。” “那么,今儿来猜一种【人的动作】。” “仔细听好:【下班以后最想做的事,一根硬梆梆的长条东西,直直地插进洞里,快的话,两下就好了。不然就抽出来,再插进去。不达目的绝不终止。 猜猜看是什么?“ “唉呀!夭寿啊!还说不色?这次这么粗鲁下流”众小姐都作如是想。 小姐们的脸一个比一个还红,真是假装羞死了。 “小孩子可不可以做?”38婆又问了。 “最好不要,出事大人要负责的。” “白天晚上都可以吗?”还是38婆在问。 嗯!通常都在晚上,白天也可以。不过白天看得较清楚,晚上乌漆妈黑的,好一边摸着,一边再插进去。 “哇!还说不色!”小姐们一边脸红,一边闷声嗤笑。 “还猜不出来?好吧!再给提示:最好不要发生那种让别人胡乱插进去的事,否则要出事的!” “讨厌!不来了啦!总经理好色。” “喂喂!猜不来就不要乱栽赃抹黄!答案是【用钥匙开门】啦!”
女人 就要做个身经百战的处女
可喜的是,现在她们担心的倒不是男人会不会在事后变心。逐渐成长壮大的女性自主力量以及对爱情的务实态度,使得女性有了一种新的自我定位:变心就变心吧!搞不好,自己还先变心呢!
她们担心的也不是日后无法带着生理上的处女状态进入婚姻。 在这个接触频繁的年头,谁还觉得处女不处女有什么了不起呢?就算对方介意,也有许多“补救”或“掩盖”的方法呀! 她们现在担心的倒是做爱之后的心理状态:如果给了他,自己会不会有失落感,会不会因此而变得没有安全感? 这种问题是不用拿去问那些道德凛然的保守人士的。于是她们转而追问那些看来了解女人、体贴女人的进步女性:倒底要不要“给”他呢? 脸上带着刚毅神色的进步女性提出一套空泛的身体自主权说法:“身体是属于自己的。如果你觉得想要,那就放心去做;如果你心里并不很愿意,那当然也不必委屈自己。不过,要是你是因为想留住男友的人而去做,那就太傻了。男人如果因为你拒绝给他而离开你,这显示他想到的只有自己的欲望,而没有顾及你的心情,那反倒是早去早好!所以,如果你觉得并不是很想(有许多顾虑,或者还觉得有恐惧感),那就绝对不要屈就。尊重你自己的感觉,总有一天你会找到一个让你全心全意不恐惧的人。”这种空泛的建议听来好像很有道理,但是事实上还是结束在高层次的“待价而沽”的等候心态上。而且对于毫无经验的女性而言,空泛的身体自主终究还只是一些空泛的话而已;说穿了,只是用空泛的身体自主来继续维持处女状态而已,对积极锻练女人探索自己的身体、掌控自己的感觉,根本并没有提出什么具体的操练方法来。 要落实身体自主,一定要有相应的具体实践来改变女性的情欲现况,才能跳出困境。 所以,务实的身体自主权说: 首先,你需要好好地培养调教自己掌控身体情欲的能力。比方说,平日心头升起欲望或想象的激情场景时,千万不要自责或罪恶感深重,而为了克服这种原本被训练出来的反应方式,你甚至需要特别耐心地看看A片、A书、A光碟、午夜秀、锁码台,运用你一向颇为有主见的、非常挑剔的血拼购物眼光,精挑细选爱看的、喜欢的来看,以充分的想象力来充实自己情欲的胃口。 所以,你还要问倒底要不要给他? 老在这个问题上打转的人真正关切的是:“第一次”要给谁? 我说,女人的第一次到第一百次,都应当是属于自己的。身经百战的处女,面对男人的时候才不会白痴的任人摆布,才不会丧失自主权。 你还是追问:会不会有失落感? 经过这一番磨练,也许你原来担心的失落感根本就不会存在了——因为,你已经变了一个人了,你已经变成一个又自信又有知识又有自主能力,根本就不会因为性行为而辗转自责的女人了。
女人的十大乐事与十大憾事
每个人在自己的记忆中,都有一些令自己很快乐的事情,还有一些事情,无论时间过多久,那一点点遗憾都让你无法释情。我们总结出了女人认为最快乐的十种事情与最遗憾的十种事情。
十大快乐 一、相爱。要男生爱女生多出一点点,才算相爱。因为男生应该爱护女生,如果他付出的爱,跟女生付出的相同,那就不够爱她。 二、婚姻美满。美满幸福的爱情生活,相信没有哪个女人不向往的,做一个幸福的小女人相信是女人最大的梦想吧。 三、在对方想跟你分手之前,你抢先向他提出分手。首先是自己保住了面子,最重要的是,在你的回忆里,底价从来没有被抛弃。
大学各系女生的初夜表白 (少儿不宜)
中文系:郎君,在熄灯前你看《xx指南》没?我怕痛的。。。
数学系:我希望看到令我满意的弹性系数
化学系:两种有机物的结合很奇妙,但气味也太难闻了吧?!
物理系:虽然总功率是零,但是我的流量远远大于你的流量!
外语系:oh,yes~~~yes~~~yes~~~oh。。
历史系:我经常思考,古人是怎么避孕的?
体育系:我会在上面做劈腿等分解动作,等你领悟了,就开始做全套动作
经济系:在上床之前,请把这个月的工资交出来。如果现在不对你进行经济制裁的话,难免你会在外面乱交公粮
地理系:你的地质勘探器能不能插深点呀?
气象系:洞内湿气重,要穿雨衣的哟
计算机系:你的内存条是edo的呀?!怎么这么小??
法律系:亲耐的,偶已满14周岁,接触不构成犯罪
工程系:悬臂梁的轴压不小啊,还有点偏心距。。。。
水利系: 当洋流到达的时候就会出现高潮。
电气系:慢点进,放一条腿在地板上,你的电压挺高的,安全第一,做好接地。
音乐系:啊``啊``啊——啊``啊``啊,亲爱的,咱再换个2/4拍的吧。
建筑系:国家规范记得吗,地方的呢?进入深度、幅度、次数,退红线一定要满足规范标准啊!!!
医学系的:找到我说的那个地方了没有?。。。对,就是那里,往下的地方叫做————————————
材料系:你这个是不是真的哦??
自控的:要注意适当的幅值域度和相角域度,同时频率不要超过系统截止频率。
美术系:周围的颜色必须是黑色,,,这样才能显示出性感来。
机械的:在此状态下,保持过盈配合是最佳选择
园林设计系的:根要扎的深,水要淋的多……记得不?
考古系:怎么钻了这么久这么深还不见骨头哦??
汽车系:你的轮胎是几号的??不错啊
新闻系:各位观众,一个伟大的时刻马上就要到来了,3```2```1,射了,射了,彻底释放出来了。
哲学系:女人第一次流x,并不代表她就是cn,女人第一次不流x,也并不代表她就不是cn。
电机系的:偶这个电机是1kw的,跟你的那个自耦变压器接上吧。
表演戏:怎么你的脚本和我的脚本不一样哩,卡~~~~~~~~~重来~
工业设计系:要学会创新思维,不要光想着用jj,换个角度考虑,我们可以用脚趾头来,这样才有新意……
通信工程:我的3g兼容你的2g,
环保系:尽量不要射,避免造成环境污染。
飞机设计系:我希望你保持巡航速度,延长巡航时间,不到关键时刻不要开加力啊!
电子工程:你是我的三极管,我是你的双向插头
系统工程系:要注意保持此系统的整体性,协调性,综合性,当然最重要的是用户的满意度。
市场营销:中国加入wto,一切遇国际接轨,你:长度,直径,硬度都不够.
数学系:我的插入深度和你的满意程度成2的平方比,也就是说你每伸进1cm我都将得到4%的满意度,一般我的范围在区间(10cm,20cm)内,那你的满意度 也就会在10*4=40和20*4=80之间,也就是在区间(40%,80%),注意,这个集合是开区间,不是闭区间,所以我还要再做大量的练习。
服装设计系:你的这件衣服设计的真是难脱呀,急死我了
艺术设计系:亲爱的,为什么我才进去3个像素,就有这种c10m80y100的液体流出来呢?
国际贸易系: 充分发挥各自比较优势利益,努力进出口,在平等互利,互取所需,互取满足的情况下大幅度提高人民x生活质量和满意度。充分发挥各自比较优势利益,努力进出口,在平等互利,互取所需,互相满足的情况下大幅度提高人民x生活质量和满意度
女人写给男人的十句悄悄话
不要老说别人的老婆如何如何好,别数落她不漂亮,她能嫁给你那是你的福气,你还这么说,真是很不应该。对大多数女人来说,听到自己最爱的人说她的一句好那是比所有人说她的好加起来还受用。何况,爱她还忍心伤害她吗?
二:不可以三天两头的冷落她。 女人都是敏感多疑的,她会把很多事情往消极的方向想。其实出门前的一个蜻蜓点水的吻、回家推开门时的一个拥抱都会让你的女人以后想起来感动万分,这些对于男人一点都不难做到,不是吗?记得在你难过时告诉她让两人一起分担,在她难过时要牵着她的手把手心的温度传给她。 三:不要摆脸色给你的女人看,一个对女人使脾气的男人是很可恶的。 你在生意场光鲜整洁,她在家中忙里忙外的,繁忙的家务已经让她有了一肚子火了,你应该要知道就是因为她在你背后所做的这一切才能让你无后顾之忧。试想一男人下班后回家说:老婆,你忙了一天,辛苦了!女人笑笑说:没什么的,你才辛苦呢!那是多么和谐的一幅画。 四:男人走到一起是比工作比职位,女人走到一起是比男人比孩子。 所以在她的女友面前一定得表现出你对她的宠爱和疼惜,让她觉得自己是一个公主,拥有了会让所有女人嫉妒的那份完整的爱。如果她是一个明理的女人,她肯定也会在你的哥们面前给足你面子,让你在朋友面前做个顶天立地的大男人。 五:和男人喜欢看美女一样,女人也喜欢看帅哥。 你可以吃醋可以生气,可是一个真爱你的女人其实看到帅哥的时候的心境比男人看到美女时的心境更加单纯,她只是看到一些美好的东西有些感叹而已,就像是看到一幅美的图画一样,不像男人那样会有更多的幻想。 六:老婆是娶来疼的,有修养的男人是绝对不会打老婆的。 如果真爱她那就一定要尊重她,不能随便动手。如果你已经不爱她了,那么你就摸摸自己的良心:我还能让她幸福吗?如果答案是否定的,那就放她走吧,让她找个真正能对她好的人。让自己别再错下去也让她自由吧! 七:女人喜欢男人的大男子主义,这样让她们觉得很安全。 可女人更抵挡不了男人的温柔,如果说女人的温柔是对付男人的利器,那么男人不经意的温柔对于女人绝对是可以说是核武器。但是女人也有自己天性那就是天生的母性情结,她偶尔会把你当做自己的孩子一样处处宠爱着,但你要记住不要得寸进迟。 八:家庭永远是第一。 男人固然要对工作负责,却也要有职业道德,要从工作中得到乐趣,但不要做工作的奴隶,我们工作是为了更快乐地和家人在一起,享受生活很重要,记得不定时地和你们妻子和你的孩子一起享天伦之乐。 九:爱人的父母就是自己的父母,将心比心,爱屋及乌。 老吾老以及人之老,只要内心深处真正感到这就是我自己的父母,心理上对老人依恋亲密,老人会感受到这份真心的。何况,人老了很象孩子,只要象哄孩子般哄老人开心就好了。我们自己也有老的一天,要做好下辈的镜子,让他们知道怎么去尊敬老人。 十:两个人相处切记要坦诚、信任、宽容、理解。 不可事事隐瞒但也可在逼不得已时说些善意的谎言,个中尺度自己把握。多多站在对方的立场上去看一件事,想想她的处境,体会一下她的为难之处。记得:你是她最爱的人,你要理解她,支持她,在她犯错误时要宽容以对。
PL/SQL学习--命名程序单元
命名的PL/SQL块就象数据库的表,序列等被存储在数据库服务器上,在需要的时候可以直接调用;文明一点叫做存储程序单元,可以被许多应用程序共享或者使用;
注意:程序单元的好处不止是当你写一个它的时候,下次来调用的时候不需要重新写然后编译,更为牛的好处其实在于,当许多应用程序都使用了某个程序单元,而这个程序单元的对外逻辑想要追求一点变化的时候,我们只需要修改被大家使用的程序单元就行了;
命名程序单元的类型:
1, 存储过程和函数:存储在Oracle9i数据库中;
创建过程:
create or replace procedure ship_cost_sp(p_qty in number,p_ship out number)
is
begin
if p_qty>10 then p_ship:=11.00;
elsif p_qty>5 then p_ship:=8.00;
else p_ship:=5.00;
end if;
end;
调用过程:
Variable g_ship_cost number;
Execute ship_cost_sp(7,:g_ship_cost);
Print g_ship_cost;
命名关联调用:execute ship_cost_sp(p_ship=>:g_ship,p_qty=>7);
注意:in 模式的参数是不可以在过程中被再次赋值的,但是out模式的可以;
同时out模式的参数却在调用过程中是空的;
所以我们可以使用in out 这样的结合模式来实现在过程中使用一个单独的参数来传入和传出值的效果;
可以在一个过程中调用另一个过程,但是注意在这种调用方式中:被调用过程的参数不能出现调用过程没有定义的变量,无论是in还是out变量,要么调用过程自己定义了,要么调用过程形式参数定义了;比如,直接在被调用过程的参数中使用主机变量就是严重的错误做法;而在用Execute 执行一个过程的时候用主机变量作为被调过程的参数我们发现是可行的,这也是和上面说的原则高度一致的:execute 是由sql-plus来调用的,这时候主机
变量是作为调用者的变量传给被调用者的;
其实我们发现这和普通程序语言是一样的:如果你在一个函数中调用另一个函数,而你给这个函数的参数又是来源于调用当前函数的上层函数,当前函数没定义,那会发生什么情况,不就是不认识吗!除非那是个全局变量;但事实行,这三层之间只是层次调用关系,并没有范围包括关系,所以最上层定义的变量并不是全局变量;
所以我们发现,SQL-Plus定义的主机变量并不是全局变量;而且SQL-Plus与其他过程或者函数的关系也不是范围包括关系,而只是说:SQL-Plus是其他函数或过程的调用者;
毕竟没有在函数中定义函数这么荒唐的事情和做事原则;所以真正的范围包括关系不会发生在函数与函数或者说过程与过程之间,而是会是在类与函数,函数与程序块之间的;
子程序:***************就是在一个程序单元中定义另一个程序单元;
只有在其中声明子程序的单元才能使用该子程序;
子程序是在过程块中的declare部分创建的;
例如:create or replace procedure demo1_sp………
is
Procedure demo2_sp
….
End demo2_sp
Begin
….
Demo2_sp….
End;
在异常处理上,异常的传播和责任传播是和匿名的PL/SQL块一致的:逐级上传
在事务控制上,一个过程的事务不仅包括那个过程内部的DML操作,还包括在那个过程中调用的过程的任何DML操作;
所以一直有这样的原则存在:被调用者的一个回退操作可能把调用者的操作也给回退了,除非被调用者是个自主事务:is pragma autonomous_transaction;
这样的话,被调用的过程的提交或者回退只是针对自己的而不影响调用它的过程;
内置的引发错误提示的函数:raise_application_error(错误号,提示消息);
函数和过程是非常相似的;不过函数是而且必须是表达式的一部分,它不能做为一个完整的语句使用;所以函数除了在PL/SQL中使用之外还可以在SQL语句中使用,而过程只能在PL/SQL中使用;所以你已经在SQL查询中多次使用了Oracle9i内置的函数了;但是有一个例外就是当函数中使用了out模式的参数后,就不可以在SQL中使用函数了;所以从函数中返回一个值并使用return语句返回这个值而不使用out模式的参被认为是很好的做法;
Return语句的后面不一定要跟一个变量,而只是要求是个符合函数定义的return类型的值或者表达式就行,这和c,java保持高度一致;
过程中可以使用单独的return语句来返回到过程调用之后的下一个语句;
注意:实参的精度大小不能小于形参将要返回的数值的精度大小;但是不幸的是我们在声明形参的时候不可以指定精度,这就给我们调用者在声明out实参时一个巨大的考验:你首先得考察好被调用的函数的out形参将要返回的最大精度是多少,然后声明这样一个精度的实参给函数;同时我们也看到了这样做的好处:我们不需要指定int形参的精度,所以我们在调用的时候声明的实参精度就无所限制了,这时候是形参跟着实参跑;
Java,c++中按照变量是普通还是特殊类型来天生式得决定了参数的传递是值传递还是引用传递,但是oracle中无论对于什么类型的参数传递都可以自己决定,默认都是值传递,意味着copy了一份值给函数,如果把参数设置为nocopy则成为引用传递,意味着没有copy新的值;p_out in out nocopy number;
最后,函数是有很多的限制的;
2, 应用程序过程和函数,存储在Oracle9i应用程序中或者客户端上的程序库中;
3, 软件包,存储在服务器端;
4, 数据库触发器,在与其相关的一个表上发生DML操作时被自动执行,存储在Oracle9i数据库中;
5, 应用程序触发器,在发生特定的应用程序事件(如单击按钮)时自动执行的一项任务,存储在Oracle9i应用程序中;
PL/SQL学习--PL/SQL处理
Distinct 在Oracle中仍然是被支持的;
在PL/SQL中是支持条件运算符的,所以在if中你完全可以使用or,and;
我们认为case语句的功能完全可以用if来代替,
但是我们认为case语句使得代码更紧凑了;
注意:
Case ……
When ….then….
When ….then….
….
Else …..
End case;
中,如果省略else的话,在case不上任何一个条件的时候将会引发Oracle异常;
搜索的case语句结构是
Case
When 条件表达式 then….
…
Else ….
End case;
这种结构不检查州变量与哪个when 后面的值相等,事实上根本没有州变量,它只是检查
下面的when 后面的条件哪个是ture就执行哪个;
Case表达式将判断条件并在赋值语句中返回一个值;
例如:lv_tax_num:=case rec_order.shopper
when 23 then 23
when 21 then 21
else 56
end;
异常处理的使用
异常分为三种:预定义的Oracle错误;非预定义的Oracle错误,用户定义的Oracle错误;
看明白之后,你应该理解到Oracle的异常就分为两种:第一种是在事件发生的时候系统一定会抛出的异常;另一种是用户为了某些目的,在一个系统虽然认为是正常事件的条件下,
手动引发一个自己新定义的异常;
1,预定义的Oracle错误:
//注意这里说的异常是在PL/SQL块中引发的,而不是由简单的 SQL语句引发的;
为什么在SQL语句select中选不到行或者选了很多行不必事实也不必引发异常,而在
PL/SQL块中一旦发生其一就要引发异常呢?因为PL/SQL块中的select的结果要放进
一个变量里into ;;;
异常处理执行完毕后,程序不会返回到块的可执行部分中的下一个语句;
2,非预定义的Oracle错误:
其实预定义的Oracle异常与非预定义的Oracle异常都是Oracle异常,它们都有一个
Oracle异常号;只是不同的是:预定义的Oracle异常是有名字的,意思是你在
Exception块中可以直接when 预定义的oracle异常名字 then ……; 而对于非预定义
的Oracle异常,它在Oracle内部是存在的,同样也对应着一个异常号,也就是说它
也代表当某件事情发生后的后果,但是与预定义的Oracle异常不同的是,它没有名字,
意思是你不可能在excetpion 块中when 名字 then …;所以我们可以先声明一个异常
名字,然后把这个名字和一个异常号联系起来,当被联系的异常号对应的事情发生的
时候系统就以我们定义的名字来抛出异常,这样我们就可以when 自己定义的异常名
字 then ……;
定义异常和关联异常的代码:
ex_basket_fk exception;
pragma exception_init(ex_basket_fk,-22);
所以,我们推测,select引发的两个异常是这样来定义和关联的:
数据没有找到: no_data_found exception;
Pragma exception_init(no_data_found,-1403);
注意:上面都是定义Oracle本身的异常;
3,用户定义的异常:
如果用户更新失败,update本身并不引发Oracle中的任何错误,但是我们确实希望来
引发一个错误来警告用户或者终止程序的话;
或者检查库存货物不够的时候,也可以手动引发异常;
用户这时候也需要定义异常,不过这里定义的异常名字不再是要关联到系统的异常号;
而是用raise来在必要的时候引发它;
4,when others, sqlcode,sqlerrm
如果发生了我们没有想到的错误时该怎么办??
这个困境是经常发生的,你明明知道有一个句子有可能引发异常,但不幸的是这个异
常一方面没名字,另一方面你也不知道它对应的异常号是几;别着急,下面就是来解
决这个问题的;
我们之所以辛苦进行异常的捕获,目的就是一个:不让那些难以理解的错误提示传播
到应用程序中从而被用户看见;when others 正是以一种包容的心态来进行这样的
捕获的;
When others确实好用,但是我们总是希望通过when others在软件还没发布前能够找
出异常的号码和实际动作;这时候可以使用两个函数:sqlcode,sqlerrm
A,sqlcode返回Oracle错误号;sqlerrm返回oracle错误消息;
在嵌套的块中,如果被嵌块中发生的异常没有处理,则会转到嵌套块的异常处理部分而不是被嵌块后面的一句接着执行;
在declare部分发生的异常属于当前块的调用块处理而不是当前块的exception处理;
也就是说,每一个异常处理部分exception处理的目标是它所在的块的begin部分和它调用
的块中发出的异常;
PL/SQL学习--在PL-SQL块中处理数据2
使用游标
游标是Oracle服务器中的内存的一个区域;
上面已经做了猜测,记录表并不是可以拿SQL查询来整体赋值的,所以真正适合处理多行数据的是游标;
在PL/SQL块中发出的所有DML和select语句,都将自动声明了隐式游标;
1, 隐式游标:游标属性允许检查SQL 语句的结果;
SQL%rowcount : 受SQL语句影响的行数;
SQL%found / SQL%notfound 是否影响了至少一行的数据;
SQL%提示系统查看隐式SQL游标区域;
//注意:隐式游标的属性信息总是反映了处理的最新SQL语句的信息;
2, 显式游标:显式游标是通过使用包含select语句来声明的游标;
其实只有显式游标才可以真正处理多行数据;隐式游标只是提供了一些游标属性信息而已;
//隐式游标的属性同样适用于显示游标,只不过所有的隐式游标都使用名字SQL,而显式游标有自己的名字;
使用显式游标的步骤:
1, declare
2, open
3, fetch
4, close
例子:使用游标来检索所有商品,并对设备和咖啡使用不同的税率来计算订单的总税额;
所以,我们发现,本来计算总税额的工作应该放在应用程序中,而SQL只能负责把数据检索出来传给应用程序;但是有了PL/SQL,应用程序只需要一个总税额的数据就行了,这大大减少了网络流量;
declare
cursor cur_basket is
select bi.idbasket,p.type,bi.price,bi.quantity
from bb_basketitem bi inner join bb_product p
using(idproduct)
where bi.idbasket=:g_basket;
type type_basket is record
(
basket bb_basketitem.idbasket%type,
type bb_product.type%type,
price bb_basketitem.price%type,
qty bb_basketitem.quantity%type
);
rec_basket type_basket;
lv_rate_num number(2,2);
lv_tax_num number(4,2):=0;
begin
open cur_basket;
loop
fetch cur_basket into rec_basket;
exit when cur_basket%notfound;
if rec_basket.type='E' then lv_rate_num:=.05; end if;
if rec_basket.type='C' then lv_rate_num:=.03; end if;
lv_tax_num:=lv_tax_num+((rec_basket.price*rec_basket.qty)*lv_rate_num);
end loop;
close cur_basket;
dbms_output.put_line(lv_tax_num);
end;
隐式游标的rowcount总是返回游标中的总行数;
而显式游标的rowcount则反映提取了多少行,并不代表游标中的具体行;
到此为止,我们所说的游标就是游标,不是变量;所谓变量,就是可以用:=来赋值的;
而我们看到了,游标不可以;
cursor for 循环:看了半天,原来就是用for循环来处理游标嘛!
For循环自动创建一个记录变量,打开游标,一次循环处理一行,处理完所有的行后关闭游标;
例子:通过游标更新价格
declare
cursor cur_prod is select type,price
from bb_product where active=1
for update nowait;指示服务器记录与游标中的每一行相关联的物理数据库行;
lv_sale bb_product.saleprice%type;
begin
for rec_prod in cur_prod loop
if rec_prod.type='C' then lv_sale:=rec_prod.price*.9;
end if;
if rec_prod.type='E' then lv_sale:=rec_prod.price*.95;
end if;
update bb_product
set saleprice=lv_sale
where current of cur_prod; 指示系统应该在与当前游标的行对应的物理数据库行上执行这一更新操作;
end loop;
commit;
end;
nowait选项表示在其他会话锁定了游标正在处理的行时,不等待,直接引发Oracle错误;
for update将导致锁定与游标行相关的所有表行;意思是如果这个游标涉及到多个表的连接,则for update将锁定所有的牵涉到的表的相应行;
for update of 就是一个很好的选择,可以for update of s.promo表示update操作只是针对
promo列的,所以只会锁定当前这个连接起来的行的promo列的表中的相应的行;
带参数的游标:
Declare
Cursor cur_order(p_basket number) is
……..
Bein
Open cur_order(:g_bask_1);
Open cur_order(:g_bask_2);
End;
带参数的游标允许每次被打开的时候,检索到一组不同的行;
所以我们发现,在游标的声明的时候,游标里面包含什么行并没有被确定,是在open一个游标的时候才正式确定或者说获取一些行放进游标的;
3, 游标变量:隐式游标和显式游标都与特定的查询想关联,是静态的;
虽然显式游标为一个存储特定结果集的工作区域指定了一个名称,但是这个名称并不是指针,因为它只能是一个特定结果集的名称,不可指向其他的结果集;
游标变量正是一个指向可以处理查询的工作区域的指针;
注意:for cv_xxx in cv_prod loop 中的cv_prod不可以是游标变量;只能是显式游标;
所以我们在下面的例子里只能使用while或者loop循环而不是for 循环,因为我们使用了游标变量cv_prod而不是显式游标cv_prod;
declare
type type_curvar is ref cursor;
cv_prod type_curvar;
cv_basket bb_basket%rowtype;
cv_shopper bb_shopper%rowtype;
--cursor cur_prod is select * from bb_basket;
begin
if :g_choice=1 then
open cv_prod for select * from bb_basket;
loop
fetch cv_prod into cv_basket;
exit when cv_prod%notfound;
dbms_output.put_line(cv_basket.idbasket||
' '||cv_basket.dtcreated);
end loop;
end if;
if :g_choice=2 then
open cv_prod for select * from bb_shopper;
loop
fetch cv_prod into cv_shopper;
dbms_output.put_line(cv_shopper.idshopper||
' '||cv_shopper.firstname);
end loop;
end if;
end;
Type demo is table of 后面如果是普通类则demo 就是一个PL/SQL表,如果是记录类型,
则demo就是一个记录表;所以说多行的普通类型得到了PL/SQL表,多行的记录得到了记录表;
无论如何,在declare部分是不可以对以前其他块中声明的变量进行赋值的;
PL/SQL学习--在PL-SQL块中处理数据
匿名PL/SQL块也是PL/SQL语言,但是不能重用;
变量是存储值的命名内存区域;
使用标量变量
标量变量是只包含一个单独的值的变量;
Char,varchar最大长度是32767,真是长;我想我们注意到了,Oracle所说的字符长度并不是存储长度,而是指行为长度;如果一个字符用16bit表示,则最长的char变量将占用
32767*2个字节节的磁盘大小;
1,not null与constant的使用:
demo1 varchar(2) not null:=’US’;
demo2 constant number(2,2):=.04;
注意,demo1,demo2都要求在声明的时候初始化,但是demo2在begin块中不能再被修
改了;
//SQL*Plus的一个非常ugly的地方就是显示的语法错误和运行期错误没有区别;
2,使用主机变量或绑定变量:
也称为全局变量。
PL/SQL 块使用主机变量将一个应用程序环境中的值移动到PL/SQL块中进行处理;
创建一个主机变量:variable g_shopper number; 注意,创建的这个主机变量是SQL*Plus的而不是PL/SQL块的,所以在当前SQL*Plus窗口中一直可以使用这个变量,所以主机变量又成为会话变量;
可以这样给主机变量赋值:
begin
:g_shopper:=25;
end;
可见,使用主机变量时需要使用一个冒号在前面;
3,使用锚定数据类型:%type属性告诉系统查看数据库列中的数据类型并将这种类型用于所声明的变量;注意,%type是数据库列的属性,所以应该这样来引用:
Lv_basket_num bb_basket.idBasket%type ;
这样做有两个好处:第一,当然是免去了程序员去查看数据库列的类型再定义变量的工作了;第二,当数据库列的类型定义变化的时候,程序员不必再修改PL/SQL块中对列的定义;
使用复合数据类型
复合数据类型是一种数据类型,它可以将不同数据类型的多个值作为一个单元来存储和处理;
集合是一个变量,它可以将同一种数据类型的多个值作为一个单元来存储和处理;
1,记录 使用记录数据类型声明的变量可以存储由许多列值组成的一行数据;
//使用复合变量之前必须创建自己的数据类型;
在类型定义中指出将在记录中包含的字段以及其相关的数据类型;
declare
type type_basket is record
(
basket bb_basket.idbasket%type,
created bb_basket.dtcreated%type,
qty bb_basket.quantity%type,
sub bb_basket.subtotal%type
); --¶¨ÒåÁËÒ»¸ö¼Ç¼ÀàÐÍ
rec_basket type_basket; --ÉùÃ÷ÁËÒ»¸ö¼Ç¼ÀàÐ͵ıäÁ¿
lv_days_num number(3);
lv_shopper_num number(3):=25;
begin
select idbasket,dtcreated,quantity,subtotal into rec_basket
from bb_basket where idshopper=lv_shopper_num and orderplaced=1;
lv_days_num:=sysdate-rec_basket.created;
end;
注意:要确保在select语句中的列顺序与在记录变量中的字段顺序一致;
记录变量对其字段的引用方法:record_variable_name.field_name;
Dbms_output.put_line()不可以直接输出记录类型的变量;
%rowtype
使用type定义的记录类型中有一个特殊的类型就是这个记录的字段包含了表的所有列,此时更简单的方法就是使用%rowtype,系统将根据表结构信息来为我们创建记录数据类型;
%rowtype得到的记录类型的字段名和表的列名是一致的;
2,记录表 记录表类型与记录类型相同,但是可以处理多个记录或多行数据;
记录表类型有效地解决了记录只能存储一个一行数据的缺点;
declare
type type_basketitems is table of bb_basketitem%rowtype
index by binary_integer;
tbl_basketitems type_basketitems;
begin
tbl_basketitems(:g_row).idproduct:=:g_prod;
tbl_basketitems(:g_row).price:=:g_price;
tbl_basketitems(:g_row).quantity:=:g_qty;
tbl_basketitems(:g_row).option1:=:g_opt1;
tbl_basketitems(:g_row).option2:=:g_opt2;
dbms_output.put_line(:g_row);
:g_row:=:g_row+1;
dbms_output.put_line(:g_row);
dbms_output.put_line(:g_prod);
end;
发现:记录表就是多行的记录,所以记录表的一行中将出现什么字段取决于is table of 后面的记录的类型,因为我们发现is table of后面就是一个记录类型;
例如:先定义一个记录类型,然后用定义一个每行都是该记录类型的记录表类型;
type type_basket is record
(
basket bb_basket.idbasket%type,
created bb_basket.dtcreated%type,
qty bb_basket.quantity%type,
sub bb_basket.subtotal%type
);
type type_basketitems is table of type_basket
index by binary_integer;
使用流程控制语句
1,if
If condition then statement end if;
2,循环:
Loop
Statement
Exit when condition;
End loop;
For counter in lower_bound .. upper_bound loop
Statement
End loop;
//这里可以对计数器counter使用任何名称,但通常使用 I;
使用集合
集合是一个已排序的元素组,它允许相同数据类型的多个值作为一个单独的单元来处理;
集合类似数组;一个集合可以包含很多行数据,但是只包含一个单独的字段;
1, 按索引组织的表:
也叫做PL/SQL表,是一种可以处理多行数据但是只能处理一个字段的变量;
注意,是变量,而不是实际存在的表;
PL/SQL表的使用步骤和记录是一样的:先声明一个这样的类型,然后再声明这个类型的变量;
PL/SQL表的属性是可以和表变量一起使用的函数:
count表中的行;first,last,next,prior属性可以用于在表数据中移动;
Exists将检查是否为指定的索引号输入了一值;
我们发现PL/SQL表非常类似于记录表,只不过记录表的is table of后面是一个记录类型,而PL/SQL表的is table of 后面是一个简单类型;
所以我们发现:以记录表这样的多行多列的表为样板,产生了单行多列的记录和多行单列的PL/SQL表;
//发现,多行的表—记录表的并不是从表中直接检索出多行直接赋给记录表变量的;
PL/SQL表也同样;所以,发现对多行的操作好像只能是一行一行的赋值,而比如列那样只要对应好多个列一起就办了;
声明一个PL/SQL表如下:
declare
type type_roast is table of number
index by binary_integer;
tbl_roast type_roast;
lv_tot_num number:=0;
lv_avg_num number;
对一个记录表变量赋值的时候需要指定行和列:jilubiao(row).ziduanming:=????
而对PL/SQL表赋值的时候只需要指定行:plsqlbiao(row):=????
2,varray
3,嵌套表
PL/SQL学习--前言
2PL/SQL介绍
非常值得庆幸的是:PL/SQL的使用将会与Oracle 9i数据库交互以及支持商业环境中的应用程序,也就是说学这个就是走向Oracle开发方向而不是管理方向;
PL/SQL引擎被设计成为数据库服务器的一部分,所以几乎可以从任何应用程序开发语言中使用或调用这些代码模块;
在一个应用程序中处理SQL语句比在用户的计算机上处理SQL语句更有效;
很多开发工具也内置了PL/SQL引擎;
PL/SQL的最大的优点:提高了性能:
1, PL/SQL允许一次传输的方式将语句发给Oracle,减少了网络通信量,不然的话,我
们都知道每一个SQL语句都必须单独传输;
2, PL/SQL代码模块或存储的程序单元都是以可执行的形式存储的,这使得过程调用
变得非常有效;
3, 可执行代码自动在内存中缓存,并在用户间共享;
4, PL/SQL引擎嵌入在Oracle开发工具中,所以可以在客户机上处理PL/SQL代码,
这减少了网络流量;
应用程序模型
应用程序模型是一种通用的框架或设计,它用来说明应用程序的各个组件是如何结合在一起的;
一个应用程序主要包含三个组件:
1, 用户界面或屏幕;
2, 屏幕背后的程序逻辑;PL/SQL就扮演这个角色;
3, 数据库;
三层模型比二层模型支持的用户多;
建立数据库
一个非常有用并且苦恼了你很长时间的问题,你一直想把每次在SQL-Plus里做的练习以及Oracle的响应数据都存储起来做为笔记,用了一个非常ugly的命令save “…”这样只是保存了当前执行的一个代码而已,用起来非常不舒服;但是现在有好的选择了,就是使用
假脱机 :文件à假脱机à假脱机文件;这样设定一个文件来记录从当前的SQL-Plus窗口
建立了假脱机文件起到当前窗口关闭这段时间内所有的屏幕显示;
Oracle初学者笔记终结篇
集合
PL/SQL表
在PL/SQL块中临时使用,象数组一样的对象,但不会用来定义表中的字段;
包含一列和一个主键;不能对列和主键进行命名;
列可以是任何标量数据类型;
主键必须是binary_integer类型;
大小没有限制;
定义PL/SQL表的步骤:
1, 定义表的类型;type typename is table of col_def index by binary_integer;
2, 声明该类型的一个PL/SQL表;tablename typename;
引用PL/SQL表:
使用主键值引用PL/SQL表中的行;
Tablename(key_value)
给PL/SQL表的某行赋值:
Tablename(key_value):=expression;
一个例子:
declare
type student_type is table of varchar(10) index by binary_integer;
stu1 student_type;
begin
stu1(1):='Tom';
stu1(2):='fuck';
for i in 3..10 loop
stu1(i):='com.'||i;
end loop;
for i in 1..10 loop
dbms_output.put_line('The '||i||' is : '||stu1(i));
end loop;
end;
/
PL/SQL表自带了集合函数.delete(i)可以按索引删除第I个元素;
可以不按顺序赋值;
可变数组的宽度是一定的,PL/SQL是无限的,可称为快表;
记录
为什么使用记录?我们知道%rowtype类型可以使我们获得一个行级变量存放整个行;但是为了获得更大的灵活性,我们希望能够定义一个包括了某几个我们需要的字段的变量而不是整个行的所有字段都被包括的变量;这时候我们用记录;
定义类型:type typename is recode(列定义…..);
声明一个该类型的记录变量:recordtype typename;
引用字段:recordname.columnname
赋值:
例子:
declare
type stuRecordType is record
(
id student.stuid%type,
name student.stuname%type,
se student.se%type
);
stuRec stuRecordType;
begin
select stuid,stuname,se into stuRec from student
where stuid='101';
dbms_output.put_line(sturec.id||' '||sturec.name||' '||sturec.se);
exception
when no_data_found then
dbms_output.put_line('no data');
end;
/
一个记录内部可以嵌套其他的记录;
批量绑定:
对PL/SQL变量的赋值;
一次绑定一个集合
提高DML的性能;
Forall关键字用于要在发送到SQL引擎之前对输入集合进行批量绑定;
成员函数和过程
抽象数据类型中定义成员函数和过程;类似Java类中的方法;
构造函数你已经使用过了,它无须显式定义,与对象类型同名;
定义带有函数和过程的对象类型时声明和主体的定义仍然是分开的;
例子:
声明:
create or replace type person_type as object
(
id int,
name varchar(20),
member function getid return int,
member procedure setid(pid int),
member function getname return varchar,
member procedure setname(pname varchar)
) not final;
主体定义:/
create or replace type body person_type as
member function getid return int is
begin
return id;
end getid;
member procedure setid(pid int) as
begin
id:=pid;
end setid;
member function getname return varchar is
begin
return name;
end getname;
member procedure setname(pname varchar) is
begin
name:=pname;
end setname;
end;
/
使用:
1 declare
2 p person_type;
3 begin
4 p:=person_type(1001,'com');
5 dbms_output.put_line('id: '||p.getid);
6 dbms_output.put_line('name: '||p.name);
7 p.setid(1002);
8 p.setname('mike');
9 dbms_output.put_line('id: '||p.getid);
10 dbms_output.put_line('name: '||p.name);
11* end;
id: 1001
name: com
id: 1002
name: mike
其实当我们有了p这个变量后就可以直接访问id: p.id;
我们需要清醒的是这里的类型不是一个表,而是将来可以成为一个表中一个行的类型控制描述;用构造函数构造的只是一个表的一行而不是一个表;当然我们可以用这个类型来定义一个对象表,这样的话,我没什么说的了,因为我已经不明白了;
create table persontable of person_type;
因为对对象表来说我们有两种插入的方法:
insert into persontable values(2001,'fuck');
或构造一个对象插进去:
insert into persontable values(person_type(2002,'me'))
Oracle初学者笔记(十五)2
Oracle的内置程序包
扩展数据库的功能;
为PL/SQL提供对SQL功能的访问;
一般具有sys权限的高级管理人员使用;
一个典型的程序包就是dbms_output,你老是用它的过程put_line();
Dbms_standard 提供语言工具;
Dbms_lob操作Oracle LOB;就是针对大型数据的操作设计的;
Dbms_lock用户定义的锁;
Dbms_job 允许对PL/SQL过程进行调度;
Dbms_alert 支持数据库事件的异步通知;
1,dbms_output的一些过程:
a):enable
b):disable
c):put只是把数据放到缓存(SQL-Plus的缓存,实际就是整个窗口)中,无输出功能;
d):put_line可以使得以前放在缓存中所有数据输出;并且换到下一行;
e):new_line
f):get_line
g):get_lines
2,dmbs_lob ,这个包只能是由系统管理员来操作;
Clob以字符数据存储可达2G;
Blob以二进制数据存储可达4G;
Nclob以unicode字符存储;
一个文件下载列表的例子:
创建下载目录表:
create table downfilelist
(
id varchar(20) not null primary key,
name varchar(40) not null,
filelocation bfile,
description clob
)
/
创建目录:
create or replace directory filedir as 'f:\oracle'
/只是向Oralce注册了目录,实际上并不会真的建立目录在磁盘上;Oracle无权管理和锁定操作系统的文件系统;
向目录表中插入数据:
insert into downfilelist
values('10001','oracle plsal编程指南',bfilename(upper('filedir'),'demo.mp3'),'this is a mp3 music')
insert into downfilelist
values('10002','java 大权', bfilename(upper('filedir'),'x.jpg'),'good super girl')
/在filedir的目录f:\oracle下实际存储着demo.mp3 ,x.jpg;
注意,如果你试图查询,效果是 :
sys>select * from downfilelist;
SP2-0678: 列或属性类型无法通过 SQL*Plus 显示
因为第三列是无法显示的,是一个二进制的;
下面使用dbms_lob的一些过程来进行操作:
1,read过程
declare
tempdesc clob;
ireadcount int;
istart int;
soutputdesc varchar(100);
begin
ireadcount:=5;
istart:=1;
select description into tempdesc from downfilelist where id='10001';
dbms_lob.read(tempdesc,ireadcount,istart,soutputdesc); 把clob类型的tempdesc中的数据读到字符类型的soutputdesc里;
dbms_output.put_line('Top 5 character is: '||soutputdesc);
end;
/注意,对unicode来说,汉字和字母所占的位数是一样的;
2,getlength函数
select description into tempclob from downfilelist where id=‘10001’;
ilen:=dbms_lob.GetLength(tempclob);
append,copy……..
发现这样的现象:select x into y的时候,y并不是独立于x的拷贝,因为当修改y的时候x也被修改了;
3, fileexists函数
select id ,dbms_lob.fileexists(filelocation) from downfilelist;
如果在bfile类型字段filelocation指定的系统下的目录中存在filelocation指定的系统文件,则返回int 1,否则返回0;
这说明Oracle还是可以检测到系统的文件情况的,如同java.io包里的类一样;
对bfile类型数据的操作函数有fileisopen,fileopen,fileclose等等;
Oracle初学者笔记(十五)
------触发器------
是PL/SQL块或存储过程;
是在对关联表执行DML操作时触发的;
是隐式执行的;
还可能具有声明部分和异常处理部分;
DML触发器有三类:
1, insert触发器;
2, update触发器;
3, delete触发器;
触发器的组成部分:
触发器的声明,指定触发器定时,事件,表名以类型
触发器的执行,PL/SQL块或对过程的调用
触发器的限制条件,通过where子句实现
类型:
应用程序触发器,前台开发工具提供的;
数据库触发器,定义在数据库内部由某种条件引发;分为:
DML触发器;
数据库级触发器;
替代触发器;
DML触发器组件:
1,触发器定时
2,触发器事件
3,表名
4, 触发器类型
5, When子句
6, 触发器主体
可创建触发器的对象:数据库表,数据库视图,用户模式,数据库实例
创建DML触发器:
Create [or replace] trigger [模式.]触发器名
Before| after insert|delete|(update of 列名)
On 表名
[for each row]
When 条件
PL/SQL块
For each row的意义是:在一次操作表的语句中,每操作成功一行就会触发一次;不写的话,表示是表级触发器,则无论操作多少行,都只触发一次;
When条件的出现说明了,在DML操作的时候也许一定会触发触发器,但是触发器不一定会做实际的工作,比如when 后的条件不为真的时候,触发器只是简单地跳过了PL/SQL块;
Insert触发器的创建:
create or replace trigger tg_insert
before insert on student
begin
dbms_output.put_line('insert trigger is chufa le .....');
end;
/
执行的效果:
SQL> insert into student
2 values(202,'dongqian','f');
insert trigger is chufa le .....
update表级触发器的例子:
create or replace trigger tg_updatestudent
after update on student
begin
dbms_output.put_line('update trigger is chufale .....');
end;
/
运行效果:
SQL> update student set se='f';
update trigger is chufale .....
已更新8行;
可见,表级触发器在更新了多行的情况下,只触发了一次;
如果在after update on student后加上
For each row的话就成为行级触发器,运行效果:
SQL> update student set se='m';
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
update trigger is chufale .....
已更新8行;
:new 与: old:必须是针对行级触发器的,也就是说要使用这两个变量的触发器一定有for each row
这两个变量是系统自动提供的数组变量,:new用来记录新插入的值,old用来记录被删除的值;
使用insert的时候只有:new里有值;
使用delete的时候只有:old里有值;
使用update的时候:new和:old里都有值;
可以这样使用: dbms_output.put_line('insert trigger is chufa
dbms_output.put_line('new id is : '||:new.stui
dbms_output.put_line('new name is : '||:new.st
dbms_output.put_line('new se is : '||:new.se);
可以这样从数据字典中查看一个表上有哪几个触发器:
SQL> select trigger_name from user_triggers
2 where table_name=upper('student');
TRIGGER_NAME
------------------------------
TG_INSERT
TG_UPDATESTUDENT
带有:old变量的行级delete触发器:
create or replace trigger tg_deletestudent
before delete on student
for each row
begin
dbms_output.put_line('old is: '||:old.stuid);
dbms_output.put_line('old name: '||:old.stuname);
end;
/
运行效果:
SQL> delete from student;
old is: 202
old name: dongqian
old is: 101
old name: liudehua
old is: 102
old name: lingqingxia
old is: 103
old name: lichanggong
old is: 104
old name: zhenxiuwen
old is: 1001
old name: lilianjie
old is: 1009
old name: tongleifuck
old is: 203
old name: kfdj
old is: 209
old name: fuck
已删除9行
When的使用:如果在begin也就是说触发器的PL/SQL主体块执行前加上when(old.se=’f’)的话,DML操作照做不误,但是只会在删除
Se=’f’的那行的时候才会执行触发器的主体动作,执行效果:
SQL> delete from student;
old is: 209
old name: fuck
已删除9行; 这里虽然删了9行,但是只执行了一次触发器的主体,做为一个行级触发器;
混合类型触发器:
Inserting,deleting,updating三个谓词可以分别指示当前操作到底是哪个;
create or replace trigger hunhetrigger
before insert or update or delete on student
for each row
begin
if inserting then
dbms_output.put_line('insert le.........');
end if;
if deleting then
dbms_output.put_line('delete le .......');
end if;
end;
/
插入的时候就自动判断当前动作为插入:
SQL> insert into student values(303,'me','f');
insert le.........
删除的时候就自动判断当前动作为删除:
SQL> delete from student;
delete le .......
注意,既然触发器内部的主体PL/SQL是语句,那么它同样也可以是插入删除操作而不一定只是dbms_output打印一些信息;
这正是日志表的原理:在用户执行了DML语句的时候触发主体为插入日志表以记录操作轨迹的触发器;
为什么用触发器? 当我们有两个表用来记录商品的出库入库情况,good_store用来记录库存的产品类别和数量,
而good_out用来记录出库的产品类别和数量,那么每当我们出库的某个类别的产品一定数量的时候,我们应该在good_out中插入该产品的类别和
出库数量,而同时也应该在good_store表中用update来更新库存的相应类别的产品的数量;这就交给了我们两个必须完成的任务:插入good_out
表后更新good_store表,这样的手工过程使得我们觉得非常ugly,如果只做其中一个那造成数据的不一致;所以现在我们可以用触发器,在
Good_out表的插入操作上绑定一个对good_store进行更新的触发器;当然这个过程应该是一个事务,你不必担心插入good_out表执行了,而绑定在这个动作上的触发器操作不会执行,相信Oracle设计为原子性了;
注意:触发器会使得原来的SQL语句速度变慢;
替代触发器:
创建在视图上的触发器,就是替代触发器,只能是行级触发器;
为什么要用替代触发器?
假如你有一个视图是基于多个表的字段连接查询得到的;现在如果你想直接对着这个视图insert;那你一定在想,我对视图的插入操作
怎么来反应到组成这个视图的各个表中呢?事实上,除了定义一个触发器来绑定在对视图上的插入动作上外,你没有别的办法通过系统
的报错而直接向视图中插入数据;这就是我们用替代触发器的原因;替换的意思实际上是触发器的主体部分把对视图的插入操作转换成详细的对各个表的插入;
变异表:变异表就是当前SQL语句正在修改的表,所以在一个变异表上绑定的触发器不可以使用cout()函数,原因很简单:SQL语句刚刚修改了表,你怎么统计??
约束表:
维护:
Alter trigger …..disenable; 使得触发器不可用;
Alter trigger ……enable; 开启触发器;
Oracle初学者笔记(十四)2
调用:

我们发现必须使得输入参数和定义的顺序一致,但是也不一定要这样,可以用符号=>来乱序传入参数;
但是注意,是过程定义的参数=>调用块的值或参数而不是相反,Oracle 太不懂语言了;
自主事务:pragma autonomous_transaction;
第一个事务:
create or replace procedure p1
as
[pragma autonomous_transaction]
begin
insert into student values(105,'luweiyu','男');
rollback;
end;
/
第二个事务调用了第一个事务:
create or replace procedure p2
as
begin
update student set se='女';
p1;
end;
/