Jimmy那些事儿

SQL server_高级查询

SQLserver高级查询

批处理

  • what :同时从应用程序发送到 SQL Server 并得以执行的一组单条或多条 Transact-SQL 语句;SQL Server 将批处理的语句编译为单个可执行单元,称为执行计划。执行计划中的语句每次执行一条。
  • how :
    • 在遇到运行时错误的语句之前执行的语句不受影响
    • 唯一例外的情况是批处理位于事务中并且错误导致事务回滚。在这种情况下,所有在运行时错误之前执行的未提交数据修改都将回滚。
  • 批处理终止批处理分隔关键字是GO。批处理关键字必须是这一行的唯一关键字;
    • 关键字GO之后可添加一个注释
    • 切换数据库:把USE命令插入到批处理中

GO(Transact-SQL)

  • what :向 SQL Server 实用工具发出一批 Transact-SQL 语句结束的信号
  • how :当前批语句由上一 GO 命令后输入的所有语句组成,如果是第一条 GO 命令,则由即席会话或脚本开始后输入的所有语句组成。
    • GO 命令和 Transact-SQL 语句不能在同一行中。但在 GO 命令行中可包含注释
1
2
> # GO [count] ; # count 一个正整数,GO 之前的批处理将执行指定的次数
>
  • 语句终止:在每个命令的末尾放置一个分号(;)

    • 在CTE前面必须要放一个分号(当CTE不是批处理的第一条语句时)
    • 不要把分号放在If 或者 While 条件之后
    • 不要把分号缝在 End Try 之后
    • 语句终止符必须跟在Meger之后

声明:DECLARE

  • DECLARE;制定某个变量为特定的数据类型,并可指定具体内容
    • Declare变量跟 变量名数据类型,并用分号结尾;
    • 单个Declare 声明中用逗号隔开多个变量
    • 变量赋值用分号隔开;
    • 变量是在批处理或过程的主体中用 DECLARE 语句声明的,并用 SET 或 SELECT 语句赋值。 游标变量可使用此语句声明,并可用于其他与游标相关的语句。 除非在声明中提供值,否则声明之后所有变量将初始化为 NULL
1
2
3
Declare @test Int, @testtwo Varchar(20) ;
Set @test = 1 ;
Set @testtwo = 'a value' ;

使用Set 和 Select 命令

  • Set 与 Select 对比
命令 描述
Set 限制在从表达式中检索数据;
一次只能设置一个变量
Select 可从数据源中检所数据,还可包括其他Select子句(From、Where等);可使用函数
一次课设置多个变量

Set命令可以使用访问数据源的标量子查询(一个变量)

如果你希望在确保没有行的情况下将变量设置为NULL,以及在不止一行的情况下获得一个错误,这是最佳做法;

【Select 命令在检索多行时,只会将最后一行的值存储在变量中】

1
2
3
4
5
6
7
8
9
10
11
12
Use adventureworks2012
GO
Declare @productID Int, @producename varchar(25);
Set @productID = 782; --声明一个变量
Select
@productID = productID, -- 声明多个变量;
@productname = @productID + name --声明变量可叠加使用
From production.product
Order by productID;

Select 声明,即将 @var = value 作为一个整体,当做Select查询中的列去看待即可

声明变量可叠加使用

  • 如果Select语句没有返回行,Select语句不会影响变量
1
2
3
4
5
6
7
8
9
10
GO
Declare @productID Int, @producename varchar(25);
Set @productID = 999;
Select
@productID = productID, -- 声明多个变量;
@productname = @productID + name --声明变量可叠加使用
From production.product
Where productID = 1000; -- 由于ProductID 没有1000,故ProductID仍未NULL
  • 声明示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# DECLARE @local_var data_type [= value]
# 直接声明
declare @mycounter int;
DECLARE @find varchar(30) = 'Man%'; # 使用名为 @find 的局部变量检索所有姓氏以 Man 开头的联系人信息
--Select ... WHERE LastName LIKE @find;
# 使用select声明
DECLARE @var1 varchar(30)
SELECT @var1 = (SELECT Name FROM Sales.Store WHERE CustomerID = 1000)
# 用声明并赋值过的变量构建一个Select语句并查询
Select lastname,firstname,title
From employees
where firstname= @firstnamevariable or region=@regionvariable
# 声明日期,并应用
DECLARE @起始日期 date set @起始日期 = dateadd(dd,-3,getdate())
Select top 100 * From [exchange].[YTX].[v_allcj] where 结算日期 = @起始日期
------------------------------------------------
# 声明多个变量
declare @last_name varchar(30),@fname varchar(20);
DECLARE @起始日期 datatime, @截止日期 datatime
set @起始日期 = '2017-03-07';
set @截止日期 = '2017-03-07';
# 给多个变量赋值
declare @firstnamevariable varchar(20), @regionvariable varchar(30)
set @firstnamevariable='anne'
set @regionvariable ='wa'
------------------------------------------------------------
全局变量
select @@version --返回数据库版本
select @@error --返回最后的一次脚本错误
select @@identity --返回最后的一个自动增长列的id

过程流

  • 使用条件T-SQL的If命令
    • 一个if,一个命令的执行;并且没有Then和End来终止if命令;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
If condition
Statement;
If 1=0
Print 'Line one';
Print 'Line two';
--结果返回Line two;
--if语句之后没有分号; if语句实际上是后面语句的提前;
----------------------------------------------------------------------------------
# 使用Begin / End 有条件地执行多条语句
If condition
Begin;
Multipie Line;
End; --每个都有分号
  • 使用If Exists()作为基于存在性的条件
    • If Exists() 结构使用从SQL Select语句返回的每一行作为条件。
    • 因为If Exists() 结构会查找每一行,所以Select语句应当选择所有的列。一旦一个单行满足了If Exists(),查询就会继续执行
1
2
3
4
5
If Exists
(Select * From production.product Where quantity = 0)
Begin;
Print 'Relpenish Inventory';
End;
  • 使用If / Else 执行替换语句
    • 可选的Else定义了if条件为False时的执行代码;Else可控制下一个单个命令,后者Begin/End块
1
2
3
4
If condition
Single line or Begin/End block of code;
Else
Single line or Begin/End block of code;

使用While循环

  • what :当条件为ture时循环代码

触发器 - trigger

  • what:一种特殊类型的存储过程,对特定事件作出相应。一种隐式的存储过程
    • 数据定义语言(DDL)触发器
      • DDL触发器在用户以某些方式(CREATE、ALTER、DROP或相似的语句)对数据库结构进行修改时激活作出响应。一般来说,只会在对数据库结构的改变或历史进行极为严格的审计时才会用到DDL触发器。
    • 数据操纵语言(DML)触发器
      • 附加在特定表或视图上的代码片段;与需要显式调用代码的存储过程不同,只要有附加触发器的时间在表中发生,触发器中的代码就会自动运行。实际上也不能显式地调用触发器
      • after触发器(之后触发)
        • INSERT触发器、DELETE触发器、UPDATE触发器
      • instead of 触发器(之前触发)

有时即使执行的动作是前面这些类型中的一种,触发器也不会激活。问题在于进行的操作是否在记录的活动中。

例如,DELETE语句是一个正常的记录活动,它会激活任何删除触发器,而TRUNCATE TABLE也有删除行的作用,但只是把表使用的空间释放而已-没有记录单个行删除操作,所以没有激活任何触发器。批量操作默认情况下不激活触发器,需要显式告知批量操作激活触发器。

1
2
3
4
5
6
7
--创建触发器
CREATE TRIGGER <trigger name>
ON [ <schema name>. ]<table or view name>
[WITH ENCRYPTION | EXECUTE AS <CALLER | SELF | <user> > ]
{{{ FOR | AFTER} < [DELETE][,][INSERT][,][UPDATE] > } | INSTEAD OF }
[WITH APPEND][NOT FOR REPLICATION]
AS < <sql statements> | EXTERNAL NAME <assembly method specifier> >
  1. ON子句:对创建触发器所针对的对象进行命名。

    如果触发器的类型是AFTER触发器(使用FOR或AFTER来声明触发器),那么ON子句的目标就必须是一个表-AFTER触发器不支持视图。

  2. WITH ENCRYPTION选项:加密触发器

    如果添加了这个选项,则可以确保没有人能够查看你的代码(甚至是你自己)

  3. FOR|AFTER子句与INSTEAD OF子句

    除了要确定激活触发器(INSERT、UPDATE、DELETE)的查询类型以外,还要对触发器的激活时间做出选择。虽然人们经常考虑使用FOR触发器,但是也可以使用INSTEAD OF触发器。对着两个触发器的选择将会影响到是在修改数据之前还是之后进入触发器。 ( FOR和AFTER的意义是一样的。)

    FOR|AFTER:表明了期望触发器在何种动作类型下激活。当有INSERT、UPDATE或DELETE或三者混合操作时,都可以激活触发器。

    1
    2
    3
    4
    > > FOR INSERT,DELETE --或者是:
    > > FOR UPDATE,INSERT --或者是:
    > > FOR DELETE
    > >

    >

    • INSERT触发器:当有人向表中插入新的一行时,被标记为FOR INSERT的触发器的代码就会执行。

      对于插入的每一行来说,SQL Server会创建一个新行的副本并把该副本插入到一个特殊的表中,该表只在触发器的作用域内存在,该表被称为Inserted表。

    • DELETE触发器 :它和INSERT触发器的工作方式相同,只是Inserted表示空的(毕竟是进行删除而非插入,所以对于Inserted表示没有记录)。

      相反,每个被删除的记录的副本将会插入到另一个表中,该表称为Deleted表,和Inserted表类似,该表只存在于触发器激活的时间内。

    • UPDATE触发器 :对表中现有的记录进行修改时,都会激活被声明FOR UPDATE的触发器的代码。

      唯一的改变是没有UPDATE表。SQL Server认为每一行删除了现有记录,并插入了全新的记录。声明为FOR UPDATE的触发器并不是只包含一个表,而是两个特殊的表,称为Inserted表和Deleted表。

  4. WITH APPEND选项:到它的可能性很小;WITH APPEND选项只能应用于6.5兼容模式中。

    一旦创建了更新(或插入、删除)触发器,那么就不能创建另一个同一动作类型的触发器。为解决这个问题,WITH APPEND子句显式地告诉SQL Server,即使在表上已经有了这种类型的触发器,还可以添加一个新的触发器。当有合适的触发动作(INSERT、UPDATE、DELETE)发生时,会同时激活两个触发器。

  5. NOT FOR REPLICATION选项

    如果添加了该选项,会稍微地改变关于何时激活触发器的规则。在适当的位置使用这个选项,无论与复制相关的任务何时修改表,都不会激活触发器。通常,当修改了原始表,并且不会再进行修改的时候会激活触发器(进行内务处理或级联等操作)。

  6. AS子句:AS关键字告诉SQL Server,代码将要启动。