zoukankan      html  css  js  c++  java
  • SQL-Server使用点滴(三-方法篇)

    除了基本的数据库,数据表,数据记录操作之外,SQL-Server还为我们提供了比较丰富的数据处理方法。这些方法包括:过程,函数,触发器,视图。

    下面就针对这些方法做逐一介绍:

    一,存储过程

    Create Procedure ProName(    --对应有Alter和Drop方法

              @Param1 TypeName1=DefaultValue1,

              @Param2 TypeName2=DefaultValue2,

              ...

              @ParamN TypeNameN=DefaultValueN)   --这里括号可以省略

    With Encryption   --加密改存储过程,该句可以省略掉

    As

    过程主体

    --End

          1, 存储过程可以看作是一个局部的临时回话,其中所有建立的临时表,变量都会在过程结束时自动释放掉。但是过程中可以使用过程外部的临时表(即调用过程的会话),

    并且这些临时表不会在过程结束时释放。如果想使用外部变量,只有通过Output型参数进行传递,没办法直接使用。

          2,存储过程的嵌套层数最大是32层,这点对于函数和触发器也是一样的,并且共享层数,使用@@NestLevel可以看到当前的嵌套层级; 存储过程最大的内容容量是128M,含注释。

          3,可以用sp_helptext过程来查看存储过程内容(加密的只能通过工具SqlPrompt6.0以上工具查看),该内容系统存在系统表syscomments表中。

             可以用sp_depends过程来查看存储过程中使用的对象列表;可以用sp_rename来为存储过程改名。

          4,存储过程也可以创建成临时存储过程,只需要在名称前加#或##即可。临时存储过程会在创建该临时存储过程结束时释放,不能被其他用户调用,会占用tempDB空间。

          5,存储过程中,如果进行了表结构或索引内容的更改,那么调用该存储过程的用户,必须具备这些表和索引的拥有权,否则无法正常执行。

          6,存储过程中可以随意更改系统标记,例如:Set datefirst 1 --将星期一作为一周的第一天;Set Language N'Simplified Chinese',将系统语言设置为简体中文。

    二,函数

    函数定义相对过程较为复杂,常用的有三种,标量函数(返回标准定义数据类型),表值函数(返回一个表),多语句表值函数(返回表参与函数体)

          1,标量函数

          标量函数,即定义一个SQL标准类型的返回值,并用Return(参数)的模式进行返回。

    Create Function FuncName(  --对应有Alter和Drop方法

              @Param1 TypeName1=DefaultValue1,

              @Param2 TypeName2=DefaultValue2,

              ...

              @ParamN TypeNameN=DefaultValueN)   --这里括号可以省略

    Returns ReturnType 

    With Encryption   --加密函数,该句可以省略掉

    As

    Begin  --注意这里的Begin和End不可以省略。

        函数主体

        Return(返回值)     --这里返回的是一个ReturnType类型的值。

    End

          2,表值函数

          定义的返回值是一个表,并且用Return(单记录集)来获取返回的表。

    Create Function FuncName(  --对应有Alter和Drop方法

              @Param1 TypeName1=DefaultValue1,

              @Param2 TypeName2=DefaultValue2,

              ...

              @ParamN TypeNameN=DefaultValueN)   --这里括号可以省略

    Returns Table            --注意,这里的Table是个固定保留字

    With Encryption   --加密函数,该句可以省略掉

    As

    Begin  --注意这里的Begin和End不可以省略。

        函数主体

        Return(Select ...)     --这里返回的是一个语句。

    End

          3,多语句表值函数

          定义的返回值是一个表,这个表在定义返回值时,就确定表名和表结构,并且在函数主体中对这个表进行处理,返回时仅仅用一个不带参数的Return结束。

    Create Function FuncName(  --对应有Alter和Drop方法

              @Param1 TypeName1=DefaultValue1,

              @Param2 TypeName2=DefaultValue2,

              ...

              @ParamN TypeNameN=DefaultValueN)   --这里括号可以省略

    Returns @TbName Table(ColList...)           --注意,这里是一个完整的表定义

    With Encryption   --加密函数,该句可以省略掉

    As

    Begin  --注意这里的Begin和End不可以省略。

        函数主体   --函数主题中@TbName是可以参与语句运算的。

        Return    --这里是直接一个不带任何参数的返回。

    End

        

          4,函数规范中的约定

          1>,函数不支持实参,只支持形参。

          2>,函数参数的默认值在调用时不能缺省,必须用default来站位,这个跟过程不同。并且在调用函数的时候必须加拥有者,例如dbo.

          3>,可以用sp_helptext,sp_depends,sp_rename来对参数进行基本操作。

          4>,函数不允许更改系统标志位或使用非确定性的表达式。

                 例如: set datefirst 7;   @@CPU_Busy; @@Max_Connections;@@Connections;@@Total_Errors;

                 Getdate(),NewId(),Rand()

          5>,对于【多语句表值函数】的限制比较宽,除了常用的控制和赋值语句外,可以使用游标,Insert,Update,Delete语句,但是这些

                语句也局限于处理局部变量和表,不允许将数据返回到外部。另外,可以使用Execute调用扩展存储过程。

    三,触发器

          触发器主要的功能是用来保证数据的完整性,这点跟外键的Reference的作用有点类似。不过它比外键或者Check约束更强大的是可以跨越几个表。

    在处理的方法上,触发器算是比较复杂,而且很影响系统性能的一种方法,其执行的时候都是被动执行,常伴随随着表操作Insert,Update,Delete一起

    执行。触发器不亦频繁使用,而且使用时要特别小心。

          触发器从大类上分,主要有instead of 触发器和 After触发器,一般都以After触发器为主(默认选择)。触发器子功能又分为三种:insert,Update,Delete,

    我们建Instead of 或After触发器时可以选择这三种触发器的一个子集。触发器创建格式如下:

    Create Trigger TrNameOn (TbName 或 ViewName)

    With Encryption

    For 功能子集 或 instead of 功能子集         --这里For开头的代表是After触发器,Instead of代表instead触发器,两种只能选一种。子集是insert,Update,Delete

                                                             --中的一种或几种。

    As

        触发器方法主段    --这里会出现几张系统临时表,表名分别为:inserted,deleted。

                                --其中,insert子功能会使系统出现表Inserted;delete子功能会使系统出现表deleted;而update子功能会同时出现inserted和deleted

    Go

    这里主要针对After类型的触发器作一说明:

           1,下面通过一个举例,来实现通过触发器,对一个表数据修改,插入,删除历史数据的保存。

            先是建立了四个表,T_TRTest,  T_TRTest_History,  T_TRTest_Append, T_TRTest_Modify 第一个是数据表,后三个保存对应操作的历史记录。


    IF not EXISTS(SELECT 1 FROM sysobjects WHERE NAME='T_TRTest' AND xtype='U')
    CREATE TABLE T_TRTest        --主测试表,用来建立触法器
    (sid uniqueidentifier Default(Newid()) primary key,
     TestData VARCHAR(10))
     
    IF not EXISTS(SELECT 1 FROM sysobjects WHERE NAME='T_TRTest_History' AND xtype='U')
    CREATE TABLE T_TRTest_History --历史表,记录删除的数据
    (sid uniqueidentifier Default(Newid()) primary key,
     msid UNIQUEIDENTIFIER,    --用来保存测试表主键
     TestData VARCHAR(10)IF not EXISTS(SELECT 1 FROM sysobjects WHERE NAME='T_TRTest_Append' AND xtype='U')
    CREATE TABLE T_TRTest_Append  --同步表,新增数据时,同时记录到这里
    (sid uniqueidentifier Default(Newid()) primary key,
     msid UNIQUEIDENTIFIER,
     TestData VARCHAR(10))
     
    IF not EXISTS(SELECT 1 FROM sysobjects WHERE NAME='T_TRTest_Modify' AND xtype='U')
     CREATE TABLE T_TRTest_Modify --修改表,记录所有的修改细节
     (sid uniqueidentifier Default(Newid()) primary key,
      msid UNIQUEIDENTIFIER,
      TestData VARCHAR(10),
      OpSign VARCHAR(1)           --用来记录操作类型,'I'为新增的数据,'D'为删除的数据。
     )
     
     GO
     
    --==========分界线,上面是建表,下面是建出发器================================
     ---建立触发器,为了方便理解共建立三个独立事件的触发器
    --先建立删除触发器
    IF  exists(select 1 from dbo.sysobjects where NAME='TRD_T_TRTest' AND xtype='TR')
    DROP TRIGGER  TRD_T_TRTest
    GO
    CREATE TRIGGER TRD_T_TRTest on T_TRTest   --删除触发器
    for DELETE
    as
    BEGIN
      --把所有删除的数据都拷贝到历史表中
      INSERT T_TRTest_History (msid,TestData)
      SELECT sid, TestData FROM DELETED        
    END
    GO
     
    --再建立新增触发器
    IF  exists(select 1 from dbo.sysobjects where NAME='TRI_T_TRTest' AND xtype='TR')
    DROP TRIGGER  TRI_T_TRTest
    GO
    CREATE TRIGGER TRI_T_TRTest on T_TRTest   --插入触发器
    for INSERT
    as
    BEGIN
      --把所有新增的数据都同时拷贝到新增记录表中
      INSERT T_TRTest_Append (msid,TestData)
      SELECT sid, TestData FROM INSERTED        
    END
    GO

    --最后建立修改触发器
    IF  exists(select 1 from dbo.sysobjects where NAME='TRU_T_TRTest' AND xtype='TR')
    DROP TRIGGER  TRU_T_TRTest
    GO
    CREATE TRIGGER TRU_T_TRTest on T_TRTest   --更新触发器
    for UPDATE
    as
    BEGIN
      --先把所有新增的数据都拷贝到修改表中,并且操作标记设置为I
      INSERT T_TRTest_Modify (msid,TestData,OpSign)
      SELECT sid, TestData, 'I' FROM INSERTED   
      --再把所有删除的数据也拷贝到修改表中,并且操作标记设置为D
      INSERT T_TRTest_Modify (msid,TestData,OpSign)
      SELECT sid, TestData, 'D' FROM Deleted        
    END
    GO

    --INSERT T_TRTest(TestData) VALUES('AABBCC')
    --INSERT T_TRTest(TestData) VALUES('BBCCDD')
    --INSERT T_TRTest(TestData) VALUES('FFFFFF')

    --UPDATE T_TRTest SET TestData='SSSSSS'
    --WHERE  TestData='FFFFFF'

    --DELETE T_TRTest

    --SELECT * FROM T_TRTest
    --SELECT * FROM T_TRTest_History
    --SELECT * FROM T_TRTest_Append
    --SELECT * FROM T_TRTest_Modify

         以上的例子分别说明了After触发器中的Update,Insert,Delete触发器的用法。

         2,利用RollBack实现回滚,防止对特定的数据进行操作。同样举例如下:

     IF not EXISTS(SELECT 1 FROM sysobjects WHERE NAME='T_TRTestRollBack ' AND xtype='U')
    CREATE TABLE T_TRTestRollBack        --主测试表,用来建立触法器
    (sid uniqueidentifier Default(Newid()) primary key,
     TestDataRollBack  VARCHAR(10))
     
     IF  exists(select 1 from dbo.sysobjects where NAME='TRD_T_TRTestRollBack' AND xtype='TR')
    DROP TRIGGER  TRD_T_TRTestRollBack
    GO
    CREATE TRIGGER TRD_T_TRTestRollBack on T_TRTestRollBack   --删除触发器
    for DELETE
    as
    BEGIN
      IF EXISTS(SELECT 1 FROM Deleted WHERE TestDataRollBack='AAA')
      Rollback    
    END
    GO

    INSERT T_TRTestRollBack(TestDataRollBack)VALUES('AAA')
    INSERT T_TRTestRollBack(TestDataRollBack)VALUES('BBB')

    DELETE T_TRTestRollBack WHERE TestDataRollBack='BBB'
    DELETE T_TRTestRollBack WHERE TestDataRollBack='AAA'

     

    在这个例子中,我们会发现,试图删除内容为'AAA'的数据是永远删除不掉的,并且系统会报触发器回滚异常。

     

    3,instead of触发器

    Instead of 触发器会完全用触发器的主体语句去代替对表的Insert,Update,Delete等操作。其使用场景一般有两种,一是

    防止误操作,这个比Rollback效率高,也不会报异常;另一个是保护特定的字段,不被操作。例如:

    IF not EXISTS(SELECT 1 FROM sysobjects WHERE NAME='T_TRTestInstead ' AND xtype='U')
    CREATE TABLE T_TRTestInstead        --主测试表,用来建立触法器
    (sid uniqueidentifier Default(Newid()) primary key,
     TestDataInstead  VARCHAR(10))

    IF  exists(select 1 from dbo.sysobjects where NAME='TRD_T_TRTestInstead' AND xtype='TR')
    DROP TRIGGER  TRD_T_TRTestInstead
    GO
    CREATE TRIGGER TRD_T_TRTestInstead
    on T_TRTestInstead
    instead of Delete
    as
    begin
        IF EXISTS(SELECT 1 FROM Deleted WHERE TestDataInstead='AAA')
     SELECT * FROM deleted
    end
    GO

    IF  exists(select 1 from dbo.sysobjects where NAME='TRD_T_TRTestInstead2' AND xtype='TR')
    DROP TRIGGER  TRD_T_TRTestInstead2
    GO
    CREATE TRIGGER TRD_T_TRTestInstead2
    on T_TRTestInstead
    instead of INSERT
    as
    begin
        INSERT INTO T_TRTestInstead(TestDataInstead)
     SELECT TestDataInstead FROM inserted
    end
    GO

    INSERT T_TRTestInstead(sid,TestDataInstead)VALUES('00000000-0000-0000-0000-000000000000','AAA')
    INSERT T_TRTestInstead(sid,TestDataInstead)VALUES('00000000-0000-0000-0000-000000000000','BBB')
    INSERT T_TRTestInstead(sid)VALUES('00000000-0000-0000-0000-000000000000')

    DELETE T_TRTestInstead WHERE TestDataInstead='BBB'
    DELETE T_TRTestInstead WHERE TestDataInstead='AAA'

    SELECT * FROM T_TRTestInstead

     

    以上的例子建立了两个instead of触发器,我们在后面的执行代码中可以看到,主动插入Sid值时,全部失效了,系统会按照其默认的

    DF约束增加值,这种方法有利于保护indentity,timestamp, 及计算数据字段不受其他语句的干扰;另外,我们发现数据根本删除不

    掉了,并且删除数据总AAA内容的数据,还会直接显示出所有AAA内容的记录,原本的Delete功能已经消失了。

     

     

     四,视图

     Create View VwName

         With Check Option  --对View更新时即时改变数据,可省略

         With Encryption  --可省略

     AS

         具有 Select的语句段

     Go

          View 可以查看一个或多个表的内容,常用于使用频率比较高的表访问。设计中常用的方法是,一,将多个表当作一个表使用,这样有助于代码

    和数据流程的简练。二,将一个表根据标志位和使用字段不同,拆作多个表(视图)使用,这样的好处是数据结构比较紧密,运行效率高。

          在使用View中,应该注意以下几点:

          1,不要企图使用Create View [其他数据库]..ViewName 来在其他数据库上建立View,只允许在当前数据库上建立View,但是可以在内容中

              利用[其他数据库]的前缀来访问其他数据库中的表。

              当然,也有种间接在其他服务器上建立View的方法: [其他数据库]..sp_executesql N' 创建View语句' 来实现跨数据库建视图。

          2,视图的创建名称在sysobjects表;视图的创建语句在syscomments表;视图所用到的表在sysdepends表中。

               这里需要注意的是调用sp_rename进行更改时,不会改变syscomments中的创建语句,可以用sp_helptext进行查看。

          3,视图的语句有这样几个限制:

              1>,不能包含Compute [By]字句。

              2>,不能直接使用Order by,但是允许用Top N...Order By。

              3>,不能使用into[表]。

              4>,不能使用临时表或表变量。

           4,如果想要让视图具备可更新性质(可写),那需要有以下几点限制:

              1>,可以直接利用instead of 触发器来实现视图的更新。

              2>,视图中不能包含聚合函数,Group by,Top N,Distinct 语句。

              3>,列中不能有很复杂的计算列(非常规算法)。

              4>,结果列,至少有一列是由实际表字段查询得到的,不能所有列都是纯数据列(例如常量'a')。

              5>,分区视图,即由Union或Union All串起来的若干表组成的视图其可更新情况限制比较复杂,因用得少,这里不作表述。

  • 相关阅读:
    Mesos源码分析(8): Mesos-Slave的初始化
    OpenStack(一)——OpenStack的相关概念
    awk(gawk)文本报告生成器
    echo的色彩处理
    bash命令检测Shell脚本中的语法错误和查看详细执行过程
    Linux命令之cut
    sed流编辑器
    shell中函数的使用
    shell中的shift左移参数命令
    shell中跳出循环语句break和continue
  • 原文地址:https://www.cnblogs.com/Murphieston/p/6253271.html
Copyright © 2011-2022 走看看