数据库基本知识(包括视图、触发器、存储过程、DTS等等)【转载】

1.触发器:【http://www.webjx.com/program/20041112005.htm
   定义: 何为触发器?在SQL Server里面也就是对某一个表的一定的操作,触发某种条件,从而执行的一段程序。触发器是一个特殊的存储过程。
   常见的触发器有三种:分别应用于Insert , Update , Delete 事件。(SQL Server 2000定义了新的触发器,这里不提)

   我为什么要使用触发器?比如,这么两个表:

   Create Table Student(       --学生表
    StudentID int primary key,   --学号
    ....
   )

   Create Table BorrowRecord(       --学生借书记录表
    BorrowRecord int identity(1,1),   --流水号 
    StudentID   int ,          --学号
    BorrowDate  datetime,        --借出时间
    ReturnDAte  Datetime,        --归还时间
    ...
   )

  用到的功能有:
    1.如果我更改了学生的学号,我希望他的借书记录仍然与这个学生相关(也就是同时更改借书记录表的学号);
    2.如果该学生已经毕业,我希望删除他的学号的同时,也删除它的借书记录。
  等等。

  这时候可以用到触发器。对于1,创建一个Update触发器:

  Create Trigger truStudent
   On Student
   for Update
  --------------------------
  --Name:truStudent
  --func:更新BorrowRecord 的StudentID,与Student同步。
  --Use :None
  --User:System
  --Author: 懒虫 # SapphireStudio (www.chair3.com)
  --Date : 2003-4-16
  --Memo : 临时写写的,给大家作个Sample。没有调试阿。
  -------------------------------------
  As
   if Update(StudentID)
   begin

    Update BorrowRecord
     Set br.StudentID=i.StudentID
     From BorrowRecord br , Deleted d ,Inserted i
     Where br.StudentID=d.StudentID

   end   
        
  理解触发器里面的两个临时的表:Deleted , Inserted 。注意Deleted 与Inserted分别表示触发事件的表“旧的一条记录”和“新的一条记录”。
  一个Update 的过程可以看作为:生成新的记录到Inserted表,复制旧的记录到Deleted表,然后删除Student记录并写入新纪录。

  对于2,创建一个Delete触发器
  Create trigger trdStudent
   On Student
   for Delete
  ----------------------------------------------
  --Name:trdStudent
  --func:同时删除 BorrowRecord 的数据
  --Use :None
  --User:System
  --Author: 懒虫 # SapphireStudio (www.chair3.com)
  --Date : 2003-4-16
  --Memo : 临时写写的,给大家作个Sample。没有调试阿。
  ----------------------------
  As
   Delete BorrowRecord
    From BorrowRecord br , Delted d
    Where br.StudentID=d.StudentID

  从这两个例子我们可以看到了触发器的关键:A.2个临时的表;B.触发机制。
  这里我们只讲解最简单的触发器。复杂的容后说明。
  事实上,我不鼓励使用触发器。触发器的初始设计思想,已经被“级联”所替代。

2.存储过程http://www.webjx.com/program/20041112006.htm
  存储过程是数据库编程里面最重要的表现方式了

  在SQL 2000里,说实话,我实在找不出触发器可以存在的理由。回忆一下:触发器是一种特殊的存储过程。它在一定的事件(Insert,Update,Delete 等)里自动执行。我建议使用sp和级联来代替触发器。

  在SQL 7 里面,触发器通常用于更新、或删除相关表的数据,以维护数据的完整。SQL 7里面,没有级联删除和级联修改的功能。 只能建立起关系。既然SQL 2000里面提供了级联,那么触发器就没有很好的存在理由。更多的情况下是作为一个向下兼容的技术而存在。

  当然,也有人喜欢把触发器作为处理数据逻辑,甚至是业务逻辑的自动存储过程。 这种方法并不足取。这里列举以下使用触发器的一些坏处:

 a、“地下”运行 。
   触发器没有很好的调试、管理环境。调试一段触发器,要比调试一段sp更耗费时间与精力。

 b、类似于goto语句。(过分自由的另外一个说法是:无政府主义!)
   一个表,可以写入多个触发器,包括同样for Update的10个触发器!同样for Delete的10个触发器。也就是说,你每次要对这个表进行写操作的时候,你要一个一个检查你的触发器,看看他们是做什么的,有没有冲突。
   或许,你会很牛B的对我说:我不会做那么傻B的事情,我记得住我做了些什么!3个月以后呢?10个月以后呢?你还会对我说你记得住么?
 c、嵌套触发器、递归触发器
   你敢说你这么多的触发器中不会存在Table1更新了Table2表,从而触发Table2表更新TAble3,TAble3的触发器再次触发Table1更新Table2…… ??
   或许还会发生这种情况:你的程序更新了Table1.Fd1,触发器立马更新Table1.fd1,再次触发事件,触发器再次更新Table1.fd1……

   当然,SQL Server可以设置和避免应用程序进入死循环,可是,得到的结果,或许就不是你想要的。
 
 …… 
  我想不出触发器更多的坏处了,因为我早就抛弃了它。算了,不批它了,酸是各人爱好把!我建议使用完全存储过程来实现数据逻辑和事务逻辑!

  先讲讲sp的编写格式(我个人的编程习惯)。良好的习惯有助于日后的维护。


  Create Proc spBuyBook(           --@@存储过程头,包括名字、参数、说明文档
   @iBookID int,   --书的ID       --@@参数
   @iOperatorID int  --操作员ID
  )
  -------------------------------------------------------  @@说明文档
  --Name : spBuyBook                    @@名字   
  --func : 购买一本书的业务逻辑              @@存储过程的功能           
  --Return: 0,正确;-1,没找到该书;-2,更新Book表出错;-3..... @@返回值解释
  --Use  : spDoSomething,spDoSomething2....        @@引用了那些外部程序,比如sp,fn,vw等
  --User : 懒虫                      @@该存储过程的使用者
  --Author: 懒虫 # SapphireStudio (www.chair3.com)     @@作者
  --Date : 2003-5-4                    @@最后更新日期
  --Memo : 临时写写的,给大家作个Sample。没有调试阿。   @@备注
  -------------------------------------------------------
  As                            --@@程序开始
  begin
   
   Begin Tran                       --@@激活事务
    Exec spDoSomething                  --@@调用其他sp
    if @@Error<>0                    --@@判断是否错误
    begin
     Rollback Tran                   --@@回滚事务
     RaisError ('SQL SERVER,spBuyBook: 调用spDoSomeThing发生错误。', 16, 1) with Log --@@记录日志
     Return -1                     --@@返回错误号
    end 
  
   .... --更多其他代码

   Commit Tran                      --@@提交事务
  end
        
  妈 的我怎么这么背啊我??什么时候不死机,偏偏在这时!!丢了不少……:(:(
  下面默哀3分钟……

   1……
   2……
   3……
  
  好了,继续!回忆刚才写的内容ing ……

  AA、存储过程的几个要素: a. 参数 b.变量 c.语句 d.返回值 e.管理存储过程
  BB、更高级的编程要素:  a.系统存储过程 b.系统表 c.异常处理 d.临时表 e.动态SQL f.扩展存储过程 g.DBCC命令

  AA.a 参数: 知识要点包括:输入参数,输出参数,参数默认值

   Sample:

    Create Proc spTest(
     @i int =0 ,    --输入参数
     @o int output   --输出参数
    )
    As
     Set @o=@i*2    --对输出参数付值
     
   Use the Sample:

    Declare @o int
    Exec spTest 33,@o output
    Select @o          --此时@o应该等于33*2=66。

   ----------------------------------------------------------------------
   以上代码没有测试,顺手写写的。希望不会出错:) 
                          --懒虫 # SapphireStudio

         精彩世界,尽在3腿软件网(www.chair3.com)!!
   -----------------------------------------------------------------------                       
  AA.b 变量:AA.a中已经有声明变量的例子了,就是Declare @o int
  AA.c 语句:在Sql Server 中,如果仅仅使用标准SQL语句将是不可想象的,通常认为,标准的SQL 语句就那么几条,如:   
        Select, Update, Delete
       因此,我们需要引入更多更强大的功能,那就是T-SQL语句:
  
       赋值语句:Set     
       循环语句:While 
       分支语句:if , Case ( Case语句不能单独使用,与一般高级语言的不同)
       
       一起举个例子吧:
       Sample :
       
       Declare @i int
       Set @i=0

       While @i<100
       begin

        if @i<=20
        begin

         Select Case Cast(@i As Float)/2 When (@i/2) then Cast(@i As varchar(3)) + '是双数'
                         else       Cast(@i As varchar(3)) + '是单数'

             end

        end

        Set @i=@i+1
       end 
     
       ----------------------------------------------------------------------
       以上代码判断20之内的单数与双数。
                             --懒虫 # SapphireStudio
             精彩世界,尽在3腿软件网(www.chair3.com)!!
       -----------------------------------------------------------------------
  AA.d 返回值
    Sample:

     Create Proc spTest2
     As
      Return 22

    Use the Sample
     Declare @i int
     Exec @i=spTest2
     Select @i 

  AA.e 管理存储过程: 创建,修改,删除。
    分别为:
    Create Proc ... , Alter Proc ... , Drop Proc ...



 BB、更高级的编程要素:  a.系统存储过程 b.系统表 c.异常处理 d.临时表 e.动态SQL f.扩展存储过程 g.DBCC命令哈哈,以下课程收费!!(玩笑,实际上打算放到后面去讲了。)

3.函数
  函数是SQL 2000的新功能。一般的编程语言都有函数,我就不用解释函数是什么东东了。:)
  或许不少朋友会问:我用存储过程不就可以了么,我为什么要使用函数?

  这里特别指出的一点:fn可以嵌套在Select语句中使用,而sp不可以。

  这里不打算大批特批一番游标了,当然,在我的程序里面,基本抛弃了游标(这里特别说明,是“基本”!因为还是有很多地方费用导游表不可的。),转而采用了fn。游标太消耗资源了。受不了……我快要感动得要流泪了…
 
  fn其实要比sp要简单得多。因为它的不确定性,从而也使他受到了不少的限制。
  举个函数的小粒子:

    Create Function fnTest ( @i int )
     Returns bit
    As
    begin
     Declare @b bit
     if (Cast(@i As Float)/2)=(@i/2)
      Set @b= 1
     else
      Set @b= 0

     Return @b 
     
    end

       ----------------------------------------------------------------------
       以上代码判断@i是单数还是双数。
                             --懒虫 # SapphireStudio
             精彩世界,尽在3腿软件网(www.chair3.com)!!
       -----------------------------------------------------------------------


   Use the Sample:


     Create Table #TT( fd1 int)
     Declare @i int
     Set @i=0
     While @i<=20
     begin
      Insert Into #tt Values(@i)
      Set @i=@i+1
     end

     Select fd1,
         '是否双数'=dbo.fnTest(fd1)  --在这里调用了函数,注意哈:函数之前一定要加上他的owner.
     From #tt

     Drop Table #tt


       ----------------------------------------------------------------------
       以上代码虚拟一段数据,然后判断数据表中是单数还是双数。
                             --懒虫 # SapphireStudio
             精彩世界,尽在3腿软件网(www.chair3.com)!!
       -----------------------------------------------------------------------

    有了sp的编程基础,写fn也就不是什么很难的事情了。刚才我提到了,fn受到限制颇多,这里稍稍列举:

     chair1. 只能调用确定性函数,不可以调用不确定函数。 比如,不可以调用GetDate(),以及自己定义的不确定性函数。
     chair2. 不可以使用动态SQL 。如:Execute, sp_ExecuteSQL (这是我最痛苦的事情了,痛哭中……)
     chair3. 不可以调用扩展存储过程
     chair4. 不可以调用Update语句对表进行更新
     chair5. 不可以在函数内部创建表(Create TAble ),修改表(Alter TAble)

     等等……头脑发昏中……反正稍微一些不可预测后果,无法返回后果的都不能用。

4.范式

 
第一讲:范式设计

首先,俺说,数据库重在设计,然后才是开发。按照第三范式开发,会让你提升到一个新的境界!

名词解释:第三范式

第一范式:一个不包含重复列的表归于第一范式。 

第二范式:如果一个表归于第一范式且只包含依赖于主键的列,则归于第二范式。 

第三范式:如果一个表归于第二范式且只包含那些非传递性地依赖于主键的列,则归于第三范式。 

chair3口述简单解释:

第一范式:不设计重复字段的表

比如:
Create Table tb1 ( 
  fd1 varchar(20),  --用来存放电话
  fd2 varchar(20),  --用来存放电话
  fd3 int           --其他
)

则fd1,fd2违反第一范式

第二范式:

第二范式:不设计没有主键,或没有唯一索引的表

比如:如果一个表存在相同的数据,那必然是违反第二范式无疑。

第三范式:能细分则细分每个字段。

比如:一个表,原来设计为:

Create TAble Clothes( 
  ClothesID int primary key,--ID
  Color     varchar(10),     --颜色
  Description varchar(20)    --描述
)

那么Color违反了第三范式

于是,第三范式应该这样设计

Create TAble Clothes( 
  ClothesID int primary key,--ID
  ColorID     Int,     --颜色ID
  Description varchar(20)    --描述
)


Create Table Color(
  ColorID int primary key,
  Color  varchar(20)
)

Color作为主表,Clothes作为子表,两者用ColorID互联.


三范式设计的好处:减少数据冗余,提高系统可维护性,提高系统可扩展性。
三范式设计的缺点:会降低数据库的性能。(嘻嘻,不过非常少,大家放心)



5.设计细节

到现在已经是第三讲了,也不知道听众几何……说得好的话,送之鲜花,说得不好的话,丢个鸡蛋把!好歹也让我chair3知道有几个人听了。
好,废话少说,now begin:

要点:


  1、约束
  2、默认值
  3、计算字段 
  4、索引 


以上乃数据库设计以及编程的最常用的部分了,下面听我一一将来


1、约束。  

   约束?何为约束?也就是对某一字段数值限定。以维护数据库数据的最党的纯洁性。一流的程序员打一开始,就应当知道某一字段的填写范围。
算了,理论不说了,举例子:

   Create Table People (
      Name   varchar(20) Not Null,  --姓名
      Age    int Not Null  Check(Age>0)  --年龄
   )


大伙看了      Age    int Not Null  Check(Age>0)     ,中的Check(Age>0)就是防止用户不小心填写入<0的数值。哈哈,难道娘胎里的就算是-1岁么?
显然国务院没有如此规定。因此必须强迫Age>0。

2、默认值。

   什么叫默认值不用我说了。数据表设计中,尽量避免Null的字段。采用默认值。

   还是举例子有说服力!看:

   Create Table People (
      Name   varchar(20) Not Null,  --姓名
      Sex    bit Not Null Default 1, --性别 
      Age    int Not Null  Check(Age>0)  --年龄
   )


看到了没?      Sex    bit Not Null Default 1  ,性别,也就“男”或者“女”,用数字表示也就1 or 0 。在防止数据字段出现更多的情况(比如null),就必须使用not null。
照顾很多懒虫一般的客户(好像是说自己了),就给他默认一个“男”好了!唉,毕竟男女不打平等,很多地方都是男得多。(痛苦中…)
这里仅仅是举个例子,很多地方都可以用得到,比如日期之类的。请尽量避免 null,而采用not null + default 能够更为纯洁你的数据库。


3、计算字段

   优秀的设计人员,一开始就应当知道如何考虑到以后的使用的问题。比如在一个学生的表中(我这里是举个例子,实际上我不会写死subject的数量的)
    
  Create Table Student(
    StudentID int primary key ,
    ...

    Chinese  Float not null default 0,
    English  Float not null default 0,
    Mathematics Float not null default 0
    
    Sum      As  Chinese+English+Mathematics,
    Average  As (Chinese+English+Mathematics)/3,
   ....
  )

相信 这里聪明的人甚多,这个说些什么好呢?  肚子有点饿…… 坚持一下,写完第4点马上作饭吃!

4、索引【http://www.gvstudio.net/showartical.asp?id=256】 
  
   这可是这里设计中的最最最最最最最最最最最最最最最最最最最最重要的部分!!
   数据库的性能取决于索引的设计的好坏。
   俺先给大家大致讲讲索引的种类:聚类索引,非聚类索引(Clustered Index and nonClustered index)

   聚类索引通常创建于主键,主要创建于这些字段
    1、主键、外建
    2、返回某范围的数据 
    等等

   非聚类索引通常用于
    1、乱糟糟的数据,很多都不一样D
    2、而且数据经常要更改D


   这样说大家似乎都不是很明白吧?

   来吧,来吧,相约DevClu吧!

   Create Table OperateRecord  (  --操作记录

       OperateRecordID  int primary key,     --流水号
       OperatorID         int not null,       --操作员ID
       Operation         varchar(100),        --操作内容
       OperateDate       DAteTime,            --时间
       Memo             varchar(30)           --备注
    )


   比如,在这里,如果经常要求对该操作员进行查询,那么OperatorID就应该采用聚类索引,如果还经常对操作内容进行查询,那么Operation就应该采用非聚类索引。

   于是:
    Create UNIQUE CLUSTERED Index idxOperateRecord_OperateREcordID On OperateRecord(OperateREcordID)
    Go
    Create  Index idxOperateRecord_Operation On OperateRecord(Operation)
    Go

    使用索引:

    Select * 
      From OperateRecord With(Index=(idxOperateRecord_OperateREcordID))  --指定索引查询
      Where OperateRecordID   between 1 and 20000                        --条件是OperateRecordID .
      order by OperateRecordID  

   大家看明白了否?我肚子很饿了,没力气说了 :(:(
   
   试验证明,优秀的索引 将大大提高查询的速度.

   chair3以前曾经作个一个例子:
   
              pIII (好像是500),128M Ram ,Win2K Server, SQLServer Enterprise
              
              History表为 1000万的数据。
               1、使用聚类索引,我提取100万,耗时1分钟;提取1条,耗时2秒 (我可能记错了,可能不用2秒的…我现在的机器都是一瞬间就提取出来了,不过我现在用P4,512内存。数据为1800万)
               2、不使用任何索引(我把索引删掉),提取1条记录,耗时55秒;提取100万数据………我不敢,我怕死机。
   
    
   当然也不是索引越多越好,索引越多,将会影响写的速度。一般说,一个表,有2-3个索引即可。根据实际情况。

转载于:https://www.cnblogs.com/penboy/archive/2005/03/31/129697.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值