• sql之T-SQL


    http://www.cnblogs.com/xiaoxiaogogo/p/3469785.html

    下面就T-SQL的几个方面来分别讲解一下。

    1、变量

     要动态的写sql语句,就不能没有变量。

    声明变量并赋值:

    1 declare @i as int;--定义一个 int 类型的 变量 (as可以省略)
    2 print @i;--这注意:没有赋值之前,程序不会报错,而且输出一个 空
    3 set @i=3;
    4 print @i;

    在sql server 2008之后就可以对变量 在声明的同时进行赋值

    1 declare @a int=3;
    2 print @a;

    在变量的使用过程中,一定要注意nvarcahr 和nchar的区别。

    复制代码
    1 declare @s nvarchar(20);
    2 set @s='Hello';
    3 set @s=@s+' World!';
    4 print @s;--输出的是 Hello  World!
    5 
    6 declare @s2 nchar(20);
    7 set @s2='Hello';
    8 set @s2=@s2+' World!';
    9 print @s2;--输出的是 Hello。
    复制代码

    为什么使用nchar却是输出的 Hello,因为:nchar是固定长度,即使长度没有达到最大,但是其余长度用 空来代替了,所以 相当于是满的,所以在进行字符串的相加 是不会起作用的。

    在查询中赋值:

    1 declare @now datetime;
    2 select @now=GETDATE();
    3 print @now;
    4 declare @orderNum int;
    5 select @orderNum = COUNT(1) from [Sales.Orders];--这条查询语句只是用来 对 变量进行赋值的,不会返回查询结果的.
    6 print @orderNum; 

    主要作用:是将查询结果保存在 变量里,为了下面的使用。

    其实也可以使用 set 赋值的方式 实现 上面的作用

    1 set @orderNum =(select COUNT(1) from [Sales.Orders])
    2 print @orderNum

    2、批处理

     使用“go”,go前面的 所有的 语句处于在一个 批里面。不同批 的变量是不能互相调用。

    3、流程控制

    1)条件控制

    1 declare @minute int ;
    2 set @minute =DATEPART(minute,getdate());
    3 if @minute>20
    4    begin--一条语句可以将  begin end 省略
    5       print '马上睡觉';
    6    end
    7 else
    8    print '继续快乐玩耍';
    if条件控制

    2)循环控制

     1 --高斯问题
     2 declare @sum int,@i int;
     3 set @sum=0;
     4 set @i=0;
     5 while @i<100
     6    begin
     7    set @i=@i+1;
     8    set @sum=@sum+@i;
     9    end
    10 print @sum;
    while循环控制

     在sql server 里面的 continue 和 break 和c#里面的 使用是相同的。

    4、游标

    什么是游标:

     不是基于集合的操作,而是将集合中的数据逐条取出来,逐条进行操作。

    什么时候使用游标:

     默认的情况下是使用集合的方式 查询,如果要使用 游标  必须是在 能有让人信服的 理由下才考虑使用。

    一般不使用游标的原因:

     1、使用游标,严重违背了关系模型,关系模型是基于集合考虑的。

    2、逐条对记录进行操作会带来性能上的开销。给定一个集合,对集合进行一系列的游标代码的操作,一定会带来性能上的开销,并且这种使用游标的 方式 性能比 集合 慢了好几倍。
    3、使用游标 要写很多代码。但是使用集合的,就只 把需要的数据查询出来,不描述怎么获取他们。游标写很多代码,可读性差,维护差。

    存在的意义:

     说了这么多的 弊端,那是游标还有存在的意义吗?当然:当需要对查询出来的数据  逐条进行 处理的 时候就要使用游标.

    使用游标的步骤:

    1、在查询中声明游标

    2、打开游标

    3、从第一个值开始将值赋值到对应的变量里面。

    4、循环遍历游标,将赋值变量拿过来进行操作。

    5、关闭游标

    6、释放游标

     1 --1、首先在查询基础上声明游标
     2 declare c cursor
     3    for
     4    select shipperid,companyname 
     5    from [Sales.Shippers];
     6 
     7 --2、打开游标
     8 open c;
     9 
    10 --3、从第一个游标开始把 值 赋值到 对应的变量里面
    11 declare @id int,@name nvarchar(20);
    12 
    13 --每次取出来一条数据,  添加到指定的 变量。
    14 fetch next from c into @id,@name;
    15 
    16 --4、循环遍历 游标,将赋值的变量 拿过来进行相应的操作
    17 while @@FETCH_STATUS=0--等于0代表  游标没有超过最后一行
    18     begin
    19        --相应的操作处理
    20        print @name;
    21        
    22        --尝试 读取下一条 数据
    23        fetch next from c into @id,@name;
    24     end
    25 
    26 --5、关闭游标
    27 close c;
    28 
    29 --6、释放游标
    30 deallocate c;
    使用游标过程

    总结:

    1、使用游标,要非常谨慎,因为性能消耗很大,不确定的时候绝对不能使用

    2、游标的唯一 好处:就是可以对查询数据,进行 逐条操作。这也正是它适应的场合。

    5、临时表

    使用场景:

    当要将一些 数据 放到表里面 保存,但是又不想 创建一张数据表(因为一般 公司只有DBA 才有权限创建表),  或者我指向让当前 数据 只有当前 会话可见 ,甚至 只要当前 批 可见。

    临时表的种类:

    sql server三种临时表:局部临时表、全局临时表、表变量

    下面对三种临时表进行分别讲解:

    局部临时表:

    1、创建过程和使用方式 都普通表是 一样,加上“#” 就代表是临时表.

    2、只对 创建 他的 会话 是可见的,并且存储 在 系统数据库的 tempdb 数据的 临时表 里面。当前会话(进程)结束后,临时表会自动被删除

    3、在 sql server 里 系统创建的临时表 都会加 后缀名,就是为了防止 不同进程之间 创建相同的表名的 表名,保证唯一性。

    普通创建临时表的方法:

    复制代码
    1 create table #partTable
    2 (
    3   num int
    4 );
    5 
    6 insert into #partTable (num) values (1),(2),(3);
    7 go;--不再 一个 批 里面 也能使用 ,只要是在同一个 进程里面
    8 select * from #partTable;
    复制代码

    在查询过程中创建临时表,并将查询出的数据插入到临时表里面

    1 select * into #table from [Sales.Shippers]
    2 select * from #table;  

    全局临时表:

    1、在 表名 前面 添加两个 “#” 代表是 全局临时表

     2、注意:对所有的 会话(进程) 都是可见的, 但是 当前进程 如果关闭或者  全局临时表 长时间没有被使用,那么就会被删除

    1 create table ##allTable
    2 (
    3   num int
    4 );
    5 insert into ##allTable (num) values(1),(2),(3),(4);
    6 select * from ##allTable

    表变量:

    注意:它也会在  tempdb数据库 里面创建一个 对应物理 临时表,只不过,他只对当前操作他的"批"可见,而且 当前 批 执行完成 之后就会 删除 临时表.(所以一定要注意:表 变量 并不是 存在内存中,他也会 创建一张物理数据表)

    性能考虑:当 只有几行数据的时候,当然是 表变量 性能好;;但是如果是大量数据,应该使用临时表

    复制代码
     1 declare @tableVariable table
     2 (
     3   num int
     4 ) 
     5 
     6 insert into @tableVariable (num) values (1),(2),(3);
     7 select * from @tableVariable;
     8 go;
     9 --不再同一 批 里面是不能访问到  表 变量
    10 select * from @tableVariable;
    复制代码

    最重要的一点:表变量同变量一样,当事务回滚之后,变量的值不会回滚。同理表变量也不会回滚。

     1 --回滚中 变量的不会回滚的  特殊情况
     2 declare @num int;
     3 set @num =1;
     4 begin transaction;
     5 set @num=12;
     6 print @num;
     7 rollback;
     8 --注意:事务回滚,如果变量在 事务里面 改变,回滚的时候 变量是不会回滚的.
     9 print @num;
    10 
    11 --同理:表变量也是如此的
    12 declare @tableVariable2 table
    13 (
    14   num int
    15 );
    16 insert into @tableVariable2 (num) values(1),(2),(3);
    17 begin transaction;
    18 delete from @tableVariable2 where num =1;
    19 rollback;
    20 --表变量是不会 回滚的
    21 select * from @tableVariable2;
    事务回滚表变量不会回滚

    6、动态sql

    什么是动态sql

    首先静态sql就是普通的静态查询语句。

    动态sql:就是使用 exec来执行字符串sql语句。

    1 declare @sql nvarchar(100);
    2 set @sql ='select * from [Sales.Shippers]';
    3 exec(@sql)

    缺点:不能防止sql注入漏洞攻击。(什么是sql注入漏洞大家应该都懂的吧。就不做介绍了)

    为解决 上面的 sql注入漏洞攻击 所以又出现了 第二种动态sql :sp_executesql存储过程:

    1、安全,因为他 支持 输入和输出参数的设置

    2、性能比 exec 要好:因为它的 参数化 有助于 重用 缓存过 的执行计划. 执行计划:就是sql server 处理 sql 语句时 生成的指令.  如果 要想要 复用  缓存 中执行计划.必须保证 sql 字符串语句 相同.所以要 因为 使用  参数化 的sql语句 只要替换 参数就可以,所以 sql语句 不变化 可以复用.

     1 declare @sql nvarchar(100);
     2 set @sql='select * from [Sales.Shippers] where companyname=@name';
     3 declare @name nvarchar(20);
     4 --set @name='顺丰';
     5 set @name='顺丰;select * from [Sales.Shippers]';--即使这样,想要进行sql 注入漏洞攻击,不可能,因为 在sql 语句 把整个 @name里面的 值  作为一个 字符串 来使用的,就是执行 companyname 和 整个字符串的对比
     6 
     7 exec sp_executesql 
     8   --下面两个是非常重要的
     9   @stmt=@sql,--动态执行的 sql语句
    10   @params=N'@name as nvarchar(20)',--参数的类型
    11   @name=@name;--参数赋值
    sp_executesql

    7、例程

    例程是什么:

    为了 计算结果 或者 执行任务 而 封装的代码 的一种编程现象.提到例程,大家可能不知道,但是提到下面的他的三个种类,就全都知道了。

    例程的种类:

    用户自定义函数、存储过程、触发器

    最常用的是存储过程,下面先对存储过程进行介绍。

    存储过程:

    创建存储过程:

    复制代码
    1 --存储过程:最常用的方法
    2 create procedure MyDemoPro
    3 (
    4    --存储过程中 要使用到 的参数
    5    @orderid int
    6 )
    7 as
    8 --下面是执行的 sql 语句
    9 select * from [Sales.Orders] where orderid=@orderid;
    复制代码

    执行存储过程:

    exec MyDemoPro @orderid=10;
    --可以简写成:exec MyDemoPro 10;

    要搞懂存储过程,就必须搞懂他的三个参数类型:

    传入参数、传出参数、return参数。

    传入参数:

    就是普通的参数;上面使用的那中就是 参入参数

    传出参数:

    output 定义的参数:可以  传出 供用户使用的

     1 create procedure OrderCount
     2 (
     3    @count int output
     4 )
     5 as
     6 select @count=COUNT(*) from [Sales.Orders];
     7 go;
     8 
     9 --执行 ,一定以声明一个变量 ,赋值给  传出参数
    10 declare @outCount int ;
    11 exec OrderCount  @count=@outCount output;
    12 print @outCount;
    传出参数

    return参数:

    特殊的参数:和 c#里面的不一样,这里只用来,表示 操作结果的正确或错误,只能返回数字

     1 alter procedure ReturnProc
     2 (
     3    @username nvarchar(100)
     4 )
     5 as
     6   declare @usernameLen int;
     7   set @usernameLen=LEN(@username);
     8   
     9   if @usernameLen>=5
    10   return '1';
    11   else
    12   return '0';
    13 
    14 
    15 declare @result int;
    16 --如何为 return 参数 赋值
    17 exec  @result = ReturnProc @username='wanglihong';
    18 print @result;
    returns参数

    如果将一个返回参数设置成'asd',就会报错如下:

    自定义函数:

    1、可以直接返回一个值  

    2、分两种:

    标量函数(返回值为一个 值)

    表函数(返回值是一张表)(存在与 可编程性 里面的函数里面)

    3、实际开发中很少使用。

     1 create function GetMinute
     2 (
     3    @date datetime
     4 )
     5 --设置返回值:
     6 returns int
     7 as
     8   begin
     9      declare @minute int;
    10      set @minute =datepart(minute,@date);
    11      return @minute;
    12   end
    13 
    14 --使用自定义函数
    15 select dbo.GetMinute(GETDATE());
    自定义函数

    触发器:

    特殊的存储过程。主要作用:检索。

    种类分为两种:

      DML触发器(修改触发器:对表的数据修改:如:update等)

      DLL触发器(架构触发器:对数据库的架构进行修改:如创建表)

    DML触发器:

    分为两种:

      after触发器(对表操作)

      instead of 触发器(对视图进行操作)

    注意:在触发器的代码里,只能访问到 inserted 和deleted 两张表.对数据进行更新的是 先删除然后在插入执行的。

    对于after触发器是经常使用,所以这里只对 after做介绍:

    为shipper(货运公司)表创建一张日志表:

    复制代码
    1 create table Ship_Log
    2 (
    3    id int identity(1,1) primary key,
    4    op_date datetime default getdate(),
    5    op_uaer nvarchar(50),
    6    op      nvarchar(50),
    7    shipname nvarchar(50),
    8    shipphone nvarchar(50)
    9 )
    复制代码

    为表 dbo.Sales.Shipper创建触发器

    1 create trigger ship_log_trigger
    2 on [Sales.Shippers] after insert
    3 as
    4    --当对上面的表进行 增删改的时候执行 触发器的下面的代码
    5    insert into Ship_Log (op_uaer,op,shipname,shipphone)
    6    select user_name()--返回当前操作的用户名
    7    ,'insert',companyname,phone  from inserted;
    触发器

    向表 dbo.Sales.Shipper 中插入数据触发触发器:

    1 insert into [Sales.Shippers] (companyname,phone) values('shits','12345678')

    查询日志表:

    select * from Ship_Log;

    查询结果:

    已经将日志插入进去了。

    DLL触发器

    一般用不到。

    分为两种:

    对数据库的触发(例如:创建表)

    对服务器的触发(例如:创建数据库)

    8、标识

    标识:就是有时我们会将主键设置为标识列(自动增加列),然后查询标识的时候就是查到最新增加的标识列的值。

    分为两种:

    1、全局范围的:@@identity

    2、当前 表 范围的 :SCOPE_IDENTITY();最常用

    注意:如果想一张表含有触发器的表中插入数据的话,查询到的结果就是不同(因为向表中插入数据之后,触发器还会再向日志表中插入数据,所以全局标识查到的是日志表中的标识,而 SCOPE_IDENTITY()查到的 插入数据表里的 标识)

    1 insert into [Sales.Shippers] (companyname,phone) values('asd','12345');
    2 select @@identity;--整个数据库中所有的  最新最新增加的 标识列
    3 
    4 select SCOPE_IDENTITY();--获得 当前操作的表的最新增加的 标识列的值

    如果想没有触发器的 表 插入数据,两个就查询的标识列的值相同

  • 相关阅读:
    19.SimLogin_case07
    19.SimLogin_case06
    19.SimLogin_case05
    19.SimLogin_case04
    19.SimLogin_case03
    闲说性能测试
    iostat命令详解
    Linux vmstat命令实战详解
    RAC集群节点故障模拟测试
    Oracle RAC功能测试
  • 原文地址:https://www.cnblogs.com/blsong/p/3470441.html
Copyright © 2020-2023  润新知