zoukankan      html  css  js  c++  java
  • Sql Server专题二:数据库主要对象

    存储过程

    (1)减少网络通信量。调用一个行数不多的存储过程与直接调用sql语句的网络通信量可能不会有很大的差别,可是如果存储过程包含上百行sql语句,那么其性能绝对比一条一条的调用sql语句要高得多。

    (2)执行速度更快。有两个原因:首先,在存储过程创建的时候,数据库已经对其进行了一次解析和优化。其次,存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接调用。

    (3)更强的适应性:由于存储过程对数据库的访问是通过存储过程来进行的,因此数据库开发人员可以在不改动存储过程接口的情况下对数据库进行任何改动,而这些改动不会对应用程序造成影响。

    (4) 布式工作:应用程序和数据库的编码工作可以分别独立进行,而不会相互压制。

    存储过程可以用临时表,函数不能用临时表

    存储过程可以使用Update,函数不能使用Update

    存储过程可以用Getdate()等函数,函数不能使用Getdate()这些函数

    一、使用存储过程要注意一些问题

    1、在as后面立即跟上一个 set nocount on子句,这样会减少很大开销(相对于过程中存在DML操作的时候)

    2、创建和引用过程的时候加上架构名

    3、避免在返回许多行数据的 SELECT 语句中使用标量函数(getdate())。因为标量函数必须应用于每一行。

    4、避免使用 SELECT *。而是应指定所需的列名称。

    5、避免处理或返回”过多”的数据,一些没必要的数据就不要了

    6、通过使用 BEGIN/END TRANSACTION 来使用显式事务并且保留尽可能短的事务。更长的事务意味着更长的记录锁定和更高的死锁风险

    7、在 LIKE 子句中避免使用通配符作为前导字符,例如 LIKE ‘%a%’。因为第一个字符是不确定的,所以,查询处理器无法使用可用的索引。应改用 LIKE ‘a%’。

    8、使用 Transact-SQL TRY…CATCH 功能进行过程内的错误处理

    9、创建/修改Table时给列一个Default值

    10、使用 IF EXISTS (SELECT TOP 1 FROM table_name) 来代替 IF EXISTS (SELECT * FROM table_name)。

    11、使用 UNION ALL 运算符来代替 UNION 或 OR 运算符

    12、创建存储过程时在其定义中指定 WITH  RECOMPILE 选项,表明 SQL  Server 将不对该存储过程计划进行高速缓存;该存储过程将在每次执行时都重新编译。

    当存储过程的参数值在各次执行间都有较大差异(个人觉得应该是动态创建存储过程时,使得很可能有时候参数不同),导致每次均需创建不同的执行计划时,可使用   WITH RECOMPILE选项。此选项并不常用,因为每次执行存储过程时都必须对其进行重新编译,这样会使存储过程的执行变慢,

    二、知识点:

    1、SQL Server 启动时可以自动执行一个或多个过程。这些过程必须由系统管理员在 master 数据库中创建,并以 sysadmin 固定服务器角色作为后台进程执行。这些过程不能有任何输入或输出参数。

    2、过程可以嵌套,并且最多可以嵌套 32 级。

    3、过程可以引用尚不存在的表。在创建时,只进行语法检查。直到第一次执行该过程时才对其进行编译。只有在编译过程中才解析过程中引用的所有对象。

    加密存储过程

    Create procedure FirstP

    WITH ENCRYPTION

    as

       set nocount on

       select * from C

    go

    EXEC sp_helptext 'dbo.FirstP'

    存储过程实现递归

    select * from tb

    order by case when ISNUMERIC(col) =1 then '' else left(col,1) end,

    cast(case when ISNUMERIC(col) =0 then stuff(col,1,1,'') else col end  as int)

    drop table dbo.Example

    create table Example(ID int,ParentID int)

     

    insert Example

    select 0,null union

    select 1,0 union

    select 2,0 union

    select 3,1 union

    select 4,6 union

    select 5,2

    --取其某个ID为父节点的树结构的SQL如下:

    create procedure display(@ID int) as

    begin

    WITH Example_Table(ID,ParentID,lv)

    AS

    (

            --取根节点放入临时表

            SELECT ID,ParentID,0 FROM Example WHERE ID=@ID

            --根据已取到的数据递归取其字节点的数据

            UNION ALL

            SELECT A.ID,A.ParentID,B.lv+1 FROM Example A INNER JOIN Example_Table B ON A.ParentID = B.ID

    )

    SELECT * FROM Example_Table

    end

    drop table tb

    go

     

    自定义函数

    用户定义自定义函数像内置函数一样返回标量值,也可以将结果集用表格变量返回

    用户自定义函数的类型:

    标量函数:返回一个标量值

    表格值函数{内联表格值函数、多表格值函数}:返回行集(即返回多个值)

    1、标量函数

    Create function 函数名(参数)

    Returns 返回值数据类型

    [with {Encryption | Schemabinding }]

    [as]

    begin

    SQL语句(必须有return 变量或值)

    End

    Schemabinding :将函数绑定到它引用的对象上(注:函数一旦绑定,则不能删除、修改,除非删除绑定)

    Create function AvgResult(@scode varchar(10))

    Returns real

    As

    Begin

       Declare @avg real

       Declare @code varchar(11)

       Set @code=@scode + ‘%’

       Select @avg=avg(result) from LearnResult_baijiali

    Where scode like @code

    Return @avg

    End

    执行用户自定义函数

    select 用户名。函数名 as 字段别名

    select dbo.AvgResult(‘s0002’) as result

    用户自定义函数返回值可放到局部变量中,用set ,select,exec赋值

    declare @avg1 real ,@avg2 real ,@avg3 real

    select @avg1= dbo.AvgResult(‘s0002’)

    set @avg2= dbo.AvgResult(‘s0002’)

    exec @avg3= dbo.AvgResult ‘s0002’

    select @avg1 as avg1 ,@avg2 as avg2 ,@avg3 as avg3

     

    函数引用

    create function code(@scode varchar(10))

    returns varchar(10)

    as

    begin

    declare @ccode varchar(10)

    set @scode = @scode + ‘%’

    select @ccode=ccode from cmessage

       where ccode like @scode

    return @ccode

    end

    select name from class where ccode = dbo.code(‘c001’)

     

    2、表格值函数

    a、 内联表格值函数

    格式:

    create function 函数名(参数)

    returns table

    [with {Encryption | Schemabinding }]

    as

    return(一条SQL语句)

     

    create function tabcmess(@code varchar(10))

    returns table

    as

    return(select ccode,scode from cmessage where ccode like @ccode)

    b、 多句表格值函数

       create function 函数名(参数)

       returns 表格变量名table (表格变量定义)

       [with {Encryption | Schemabinding }]

    as

       begin

        SQL语句

       end 

     多句表格值函数包含多条SQL语句,至少有一条在表格变量中填上数据值

     表格变量格式

    returns @变量名 table (column 定义| 约束定义 [,…])

    对表格变量中的行可执行select,insert,update,delete , 但select into 和 insert 语句的结果集是从存储过程插入。 

    Create function tabcmessalot (@code varchar(10))

    Returns @ctable table(code varchar(10) null,cname varchar(100) null)

    As

    Begin

    Insert @ctable

    Select ccode,explain from cmessage

    Where scode like @code

    return

    End

    Select * from tabcmessalot(‘s0003’)

    触发器

    一: 触发器是一种特殊的存储过程﹐它不能被显式地调用﹐而是在往表中插入记录﹑更新记录或者删除记录时被自动地激活。所以触发器可以用来实现对表实施复杂的完整性约束。  

    二: SQL Server为每个触发器都创建了两个专用表:Inserted表和Deleted表。这两个表由系统来维护﹐它们存在于内存中而不是在数据库中。这两个表的结构总是与被该触发器作用的表的结构相同。触发器执行 完成后﹐与该触发器相关的这两个表也被删除。 
    Deleted表存放由于执行Delete或Update语句而要从表中删除的所有行。 
    Inserted表存放由于执行Insert或Update语句而要向表中插入的所有行。 
    三:Instead of 和 After触发器 
    SQL Server2000提供了两种触发器:Instead of 和After 触发器。这两种触发器的差别在于他们被激活的同: 
    Instead of触发器用于替代引起触发器执行的T-SQL语句。除表之外﹐Instead of 触发器也可以用于视图﹐用来扩展视图可以支持的更新操作。 
    After触发器在一个Insert,Update或Deleted语句之后执行﹐进行约束检查等动作都在After触发器被激活之前发生。After触发器只能用于表。 
    一个表或视图的每一个修改动作(insert,update和delete)都可以有一个instead of 触发器﹐一个表的每个修改动作都可以有多个After触发器。 
    四:触发器的执行过程 
    如果一个Insert﹑update或者delete语句违反了约束﹐那幺After触发器不会执行﹐因为对约束的检查是在After触发器被激动之前发生的。所以After触发器不能超越约束。 
    Instead of 触发器可以取代激发它的操作来执行。它在Inserted表和Deleted表刚刚建立﹐其它任何操作还没有发生时被执行。因为Instead of 触发器在约束之前执行﹐所以它可以对约束进行一些预处理。 
    五:使用T-SQL语句来创建触发器 
    基本语句如下: 
    create trigger trigger_name 
    on {table_name | view_name} 
    {for | After | Instead of } 
    [ insert, update,delete ] 
    as 
    sql_statement 
    六:删除触发器: 
    基本语句如下: 
    drop trigger trigger_name 
    七:查看数据库中已有触发器: 
    -- 查看数据库已有触发器 
    use jxcSoftware 
    go 
    select * from sysobjects where xtype='TR' 
    -- 查看单个触发器 
    exec sp_helptext '触发器名' 
    八:修改触发器: 
    基本语句如下: 
    alter trigger trigger_name 
    on {table_name | view_name} 
    {for | After | Instead of } 
    [ insert, update,delete ] 
    as 
    sql_statement 
    九:相关示例: 
    1:在Orders表中建立触发器﹐当向Orders表中插入一条订单记录时﹐检查goods表的货品状态status是否为1(正在整理)﹐是﹐则不能往Orders表加入该订单。 
    create trigger orderinsert 
    on orders 
    after insert 
    as 
    if (select status from goods,inserted 
    where goods.name=inserted.goodsname)=1 
    begin 
    print 'the goods is being processed' 
    print 'the order cannot be committed' 
    rollback transaction --回滚﹐避免加入 
    end 
    2:在Orders表建立一个插入触发器﹐在添加一条订单时﹐减少Goods表相应的货品记录中的库存。 
    create trigger orderinsert1 
    on orders 
    after insert 
    as 
    update goods set storage=storage-inserted.quantity 
    from goods,inserted 
    where 
    goods.name=inserted.goodsname 
    3:在Goods表建立删除触发器﹐实现Goods表和Orders表的级联删除。 
    create trigger goodsdelete 
    on goods 
    after delete 
    as 
    delete from orders 
    where goodsname in 
    (select name from deleted) 
    4:在Orders表建立一个更新触发器﹐监视Orders表的订单日期(OrderDate)列﹐使其不能手工修改. 
    create trigger orderdateupdate 
    on orders 
    after update 
    as 
    if update(orderdate) 
    begin 
    raiserror(' orderdate cannot be modified',10,1) 
    rollback transaction 
    end 
    5:在Orders表建立一个插入触发器﹐保证向Orders表插入的货品名必须要在Goods表中一定存在。 
    create trigger orderinsert3 
    on orders 
    after insert 
    as 
    if (select count(*) from goods,inserted where goods.name=inserted.goodsname)=0 
    begin 
    print ' no entry in goods for this order' 
    rollback transaction 
    end 
    6:Orders表建立一个插入触发器,保证向Orders表插入的货品信息要在Order表中添加 
    alter trigger addOrder 
    on Orders 
    for insert 
    as 
    insert into Order 
    select inserted.Id, inserted.goodName,inserted.Number from inserted

    游标

    SQl  Server的游标在你需要对记录集进行单条处理时很有用处。

    select返回一个记录集,但是你想根据每条记录的不同情况进行单条处理,这时游标的用处就显出来了。

    一个游标(cursor)可以被看作指向结果集(a set of rows)中一行的指针(pointer)。游标每个时间点只能指向一行,但是可以根据需要指向结果集中其他的行。

    例如:SELECT * FROM employees WHERE sex='M'会返回所有性别为男的雇员,在初始的时候,游标被放置在结果集中第一行的前面。使游标指向第一行,要执行FETCH。当游标指向结果集中一行的时候,可以对这行数据进行加工处理,要想得到下一行数据,要继续执行FETCH。FETCH操作可以重复执行,直到完成结果集中的所有行

    在存储过程中使用游标,有如下几个步骤:

    声明游标、打开游标、根据需要一次一行,讲游标指向的数据取到本地变量(local variables)中、结束时关闭游标

    创建游标分五个步骤:

    CREATE PROCEDURE [dbo].[Proc_Syn_Data]

    AS

    BEGIN

        SET NOCOUNT ON;

        DECLARE @ID INT;

        TRUNCATE TABLE Table2;

        -- 1.声明游标

        DECLARE CUR_MonthID CURSOR FOR

        SELECT ID FROM [Table1]

        -- 2.打开游标

        OPEN CUR_MonthID

        -- 3.从一个游标中查找信息,实现自己的数据处理。

        FETCH CUR_MonthID INTO @ID

        WHILE @@FETCH_STATUS=0

        BEGIN

            INSERT INTO [Table2]

            SELECT * FROM [Table1] tm WHERE tm.ID=@ID

            FETCH NEXT FROM CUR_MonthID INTO @ID

        END;

        -- 4.关闭游标

        CLOSE CUR_MonthID;

        -- 5.释放游标

        DEALLOCATE CUR_MonthID;

    END

  • 相关阅读:
    Provisioning profile 浅析
    Swift --> Map & FlatMap
    Swift 学习笔记(五)
    Swift 学习笔记(四)
    Swift 学习笔记 (三) 之循环引用浅析
    Swift 学习笔记 (二)
    HomeBrew
    UIGestureRecognizer 手势浅析
    frame、bounds表示大小和位置的属性以及center、position、anchorPosition
    UIViewContentMode 图文解说
  • 原文地址:https://www.cnblogs.com/java-oracle/p/5382145.html
Copyright © 2011-2022 走看看