变量

-- 声明变量
DECLARE @variable_name [AS] variable_type;
-- 变量赋值
SET @variable_name = variable_value;

示例如下:

DECLARE @age INT;
-- SET一次只能操作一个变量
SET @age = 26;

T-SQL提供了使用SELECT语句来给变量赋值的扩展功能:

SELECT @age = 30;

也可以使用子查询来给变量赋值:

USE WJChi;

SET @age =
(
SELECT Age FROM dbo.UserInfo WHERE Name = '雪飞鸿'
);

注意,上述SET语句中的子查询必须只能返回标量,否则会报错,示例如下:

USE WJChi;

SET @age =
(
SELECT Age FROM dbo.UserInfo
);

执行报错:

子查询返回的值不止一个。当子查询跟随在 =、!=、<、<=、>、>= 之后,或子查询用作表达式时,这种情况是不允许的。

批是一条或多条被客户端作为整体发送给SQL Server进行执行的T-SQL语句,SQL Server以GO命令来标识一个批的结束,注意,GO语句不能使用分号结尾。SQL Server以批为单位进行词法、语法分析及语句执行等工作。一个批中的错误不会影响另一个批中语句的执行,因为不同的批在逻辑上彼此独立,不同批中包含的语句互相独立,彼此互不影响

批是一个解析单元,因此,即便在同一个批中修改了表结构,然后执行增删改查操作会引发解析错误,因为在同一批中的增删改查语句并不知道表结构已发生了变化。

GO n:表示执行n次批中的语句,如:

USE WJChi;

SELECT * FROM dbo.UserInfo;
GO 5

流程控制

IF...ELSE...

句式结构如下:

IF condition
BEGIN
-- do something
END
ELSE IF condition
BEGIN
-- do something
END
ELSE
BEGIN
-- do something
END;

IF...ELSE...支持嵌套

WHILE

句式结构如下:

WHILE condition
BEGIN
-- do something
END;

TRY...CATCH... & 错误处理

句式结构如下:

BEGIN TRY
-- do something
END TRY
BEGIN CATCH
-- do something
END CATCH;

SQL Server提供了一组描述错误的函数:

函数 作用
ERROR_NUMBER() 获取错误编号
ERROR_MESSAGE() 获取错误的文本信息
ERROR_SEVERITY() 获取错误严重级别
ERROR_STATE() 获取错误状态
ERROR_LINE() 获取错误发生行号
ERROR_PROCEDURE() 获取错误发生的过程名

也可以通过语句:

SELECT * FROM sys.messages;

来获取错误相关信息。可以使用THROW语句来抛出错误。

其它

RETURN、CONTINUE、BREAK、WAITFOR、GOTO

更多详细内容,参考微软官方文档:Control-of-Flow

临时表

SQL Server支持三种临时表:本地临时表、全局临时表和表变量。这三种临时表创建后都存储在tempdb数据库中。

本地临时表

创建本地临时表的方式与普通的数据表相同,但本地临时表仅在它被创建的会话中可见,会话结束后,临时表也会被销毁。

临时表以#开头,如:#UserInfo。临时表中的数据存储在磁盘中,可使用以下语句判断临时表是否存在:

IF OBJECT_ID('tempdb.dbo.#table_name') IS NOT NULL

全局临时表

与本地临时表最大的不同是:全局临时表对所有会话可见,当全局临时表不在被任何会话引用时,会被SQL Server销毁。

全局临时表以##开头,如:##UserInfo

可通过语句:

SELECT * FROM tempdb..sysobjects WHERE name LIKE '%temp%'

来查看创建的临时表信息:

表变量

表变量的声明与普通变量一样,使用DECLARE语句,但相比于普通变量,表变量具有一些表的特征,如:可以执行INSERT、DELETE等操作。表变量只在创建它的会话中可见,且只对当前批可见。超出作用域或语句执行完毕,表变量便不可用。

一个显式事务回滚,事务中对临时表的修改也会回滚,但对已完成的表变量修改,则不会回滚。数据量较少时建议使用表变量,数据量较大时推荐使用临时表,微软文档中说大于100行就要考虑使用临时表了。

表变量 vs 临时表

表变量与临时表类似,但二者有所区别。临时表更多的强调它是数据表,表变量着重点则在于变量上。

关于表变量是在内存中存储数据,还是在硬盘上存储数据,可以参考stackoverflow上的讨论:

table variable is not a memory-only structure. Because a table variable might hold more data than can fit in memory, it has to have a place on disk to store data. Table variables are created in the tempdb database similar to temporary tables. If memory is available, both table variables and temporary tables are created and processed while in memory (data cache).

个人理解:表变量和临时表对象的信息都存储在tempdb中,但临时表会将数据放到硬盘上,而表变量优先将数据放到内存中,必要时才会放到硬盘上,所以小数据量的话表变量更有性能优势。

SQL Server本身也在不断的进化,有关最新版本(这里是2019)中关于临时表和表变量的优化,可以参考:Faster temp table and table variable by using memory optimization

表类型

当创建了表类型,就会在数据库中保留表的定义,可以复用它创建表变量,也可作为存储过程和自定义函数的输入参数。

CREATE TYPE TableType AS TABLE
(
Id INT PRIMARY KEY
);

DECLARE @t TableType;

删除表类型

DROP TYPE TableType;

点击此处,查看有关类型的更多内容。

动态执行SQL

SQL Server中可以使用两种方式来执行动态SQL:EXEC命令与sql_executesql存储过程。

EXEC

EXEC是T-SQL提供的执行动态SQL的原始技术,接收一个字符串作为输入并执行字符串中的语句:

USE WJChi;

EXEC('SELECT * FROM dbo.UAddress');

EXEC支持正则与Unicode字符作为输入。

sql_executesql

sql_executesql存储过程在EXEC命令之后引入,与EXEC相比,sql_executesql更安全,更灵活,可以支持输入与输出参数。但,sql_executesql只支持Unicode字符作为输入。

ADO.NET发送到SQL Server的参数化查询语句就是使用sql_executesql来执行的,参数化查询可以有效避免SQL注入攻击。示例如下:

exec sp_executesql N'SELECT * FROM dbo.UAddress WHERE ShortAddress=@sd AND LongAddress=@ld',N'@sd nvarchar(4000),@ld nvarchar(4000)',@sd=N'河南省',@ld=N'河南省郑州市'

函数 & 存储过程 & 触发器

函数

使用函数的目的在于计算逻辑的封装及代码的复用。SQL Server中函数返回值分为:标量与表值两种。

创建函数的CREATE FUNCTION语句必须是当前批中的第一条语句,否则报错:'CREATE FUNCTION' 必须是查询批次中的第一个语句。

创建标量值函数:

CREATE FUNCTION dbo.GetSum
(
@left AS INT,
@right AS INT
)
RETURNS INT
AS
BEGIN
RETURN @left+@right;
END;

创建表值函数:

CREATE FUNCTION dbo.TableFunc
(
@name AS VARCHAR(8)
)
RETURNS TABLE
AS
RETURN
(
SELECT *
FROM dbo.UserInfo
WHERE Name = @name
);

修改函数定义,将创建函数语句中的CREATE换为ALTER即可。如下所示:

ALTER FUNCTION [dbo].[TableFunc]
(
@name AS VARCHAR(8)
)
RETURNS TABLE
AS
RETURN
(
SELECT * FROM dbo.UserInfo WHERE Name=@name
);

删除函数:

DROP FUNCTION function_name;

SQL Server内置常用函数

存储过程

存储过程与函数有相似之处,如都体现了封装的思想,但存储过程可以执行更为复杂的逻辑,可以有多个返回值。创建存储过程语句如下:

CREATE PROCEDURE HumanResources.uspGetEmployeesTest2
@LastName nvarchar(50),
@FirstName nvarchar(50)
AS

SET NOCOUNT ON;
SELECT FirstName, LastName, Department
FROM HumanResources.vEmployeeDepartmentHistory
WHERE FirstName = @FirstName AND LastName = @LastName
AND EndDate IS NULL;
GO

更多详细内容,请参阅:存储过程(数据库引擎)

⚠️存储过程移植比较困难

触发器

触发器是特殊的存储过程,在满足条件时(事件被触发),会隐式执行,从这个角度讲,触发器会增加复杂性。

触发器个人接触和使用较少,这里不多介绍。详细内容可参考:CREATE TRIGGER (Transact-SQL)

小结

本章内容较为杂乱,但也都是平时编写T-SQL代码时较为常用的内容。

推荐阅读

Control-of-Flow

存储过程与函数的区别

存储过程(数据库引擎)

CREATE TYPE (Transact-SQL)

T-SQL基础(六)之可编程对象的更多相关文章

  1. 《SQL Server 2012 T-SQL基础》读书笔记 - 10.可编程对象

    Chapter 10 Programmable Objects 声明和赋值一个变量: DECLARE @i AS INT; SET @i = 10; 变量可以让你暂时存一个值进去,然后之后再用,作用域 ...

  2. [SQL] SQL 基础知识梳理(六)- 函数、谓词、CASE 表达式

    SQL 基础知识梳理(六)-  函数.谓词.CASE 表达式 目录 函数 谓词 CASE 表达式 一.函数 1.函数:输入某一值得到相应输出结果的功能,输入值称为“参数”,输出值称为“返回值”. 2. ...

  3. sql server查询可编程对象定义的方式对比以及整合

    本文目录列表: 1.sql server查看可编程对象定义的方式对比 2.整合实现所有可编程对象定义的查看功能的存储dbo.usp_helptext2 3.dbo.helptext2的选择性测试 4. ...

  4. JAVA基础知识之JDBC——编程步骤及执行SQL

    JDBC编程步骤 下面以mysql数据库为例, 1.加载驱动 首先需要下载数据库的驱动jar文件,并且在eclipse包中加入到class path中去, 例如mysql的驱动文件 mysql-con ...

  5. SQL Server ->> Database Promgramming Object Security Control(数据库编程对象安全控制)

    对于SQL Server内编程对象的安全控制是今天我在思考的问题.在MSDN上找到了几篇有用的文章. 首先微软推荐了三种做法: 1)第一种做法是在SQL Server中对一个应用程序对应创建应用程序角 ...

  6. SQL Server ->> 重新创建Assembly和自动重建相关的数据库编程对象(存储过程,函数和触发器)

    在SQL Server中,一旦一个Assembly被其他的数据库编程对象(存储过程,函数和触发器)引用了,这个Assembly就不能被删除.但是问题是,在SQL Server要更新一个Assembly ...

  7. [SQL]SQL语言入门级教材_跟我学SQL(六)

    跟我学SQL:(一)数据查询 且不说你是否正在从事编程方面的工作或者不打算学习SQL,可事实上几乎每一位开发者最终都会遭遇它.你多半还用不着负责创建和维持某个,但你怎么着也该知道以下的一些有关的SQL ...

  8. Java基础教程:JDBC编程

    Java基础教程:JDBC编程 1.什么是JDBC JDBC 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库. JDBC A ...

  9. 《SQL基础教程》+ 《SQL进阶教程》 学习笔记

    写在前面:本文主要注重 SQL 的理论.主流覆盖的功能范围及其基本语法/用法.至于详细的 SQL 语法/用法,因为每家 DBMS 都有些许不同,我会在以后专门介绍某款DBMS(例如 PostgreSQ ...

  10. 常见SQL语句和SQL基础知识

    引自:http://blog.csdn.net/u012467492/article/details/46790205 SQL语句考察(一) 1.查询出每门课都大于80 分的学生姓名 name   k ...

随机推荐

  1. pytorch 损失函数

    pytorch损失函数: http://blog.csdn.net/zhangxb35/article/details/72464152?utm_source=itdadao&utm_medi ...

  2. spark配置参数

    ~/.bashrc export SPARK_HOME=/usr/local/spark export PATH=$PATH:$SPARK_HOME/bin /usr/local/spark/conf ...

  3. javascript中的replace方法

    1.replace 调用方法str.replace(regexp|substr, newSubStr|function) regexp,正则表达式 substr,需要被替换的字符串 newSubStr ...

  4. VSCode插件开发全攻略(九)常用API总结

    更多文章请戳VSCode插件开发全攻略系列目录导航. 本文提炼一些常见的API使用场景供参考,本文内容有待完善. 编辑器相关 修改当前激活编辑器内容 替换当前编辑器全部内容: vscode.windo ...

  5. ES6之命令妙用

     很多人都听说过ES6(也就是ECMAScript的新一代标准)并且对她充满了向往,下面通过一个ES6中小知识点——let命令,来解开她的神秘面纱,让大家初步认识一下ES6的语法规范.        ...

  6. java中如何模拟真正的同时并发请求?

    有时需要测试一下某个功能的并发性能,又不要想借助于其他工具,索性就自己的开发语言,来一个并发请求就最方便了. java中模拟并发请求,自然是很方便的,只要多开几个线程,发起请求就好了.但是,这种请求, ...

  7. Scala - 快速学习05 - 数据结构

    1- 数组(Array) 数组一般包括定长数组和变长数组. 可以不指明数组类型,Scala会自动根据提供的初始化数据来推断出数组的类型. 在Scala中,对数组元素的应用,是使用圆括号,而不是方括号. ...

  8. PHP之ThinkPHP框架(会话)

    网页会话即是实现页面跳转及数据传递,在web开发中,Cookie和Session的使用是极其重要的,GET和POST是最常使用的页面间数据传递的方法,相对于PHP脚本基础,在ThinkPHP中对网页会 ...

  9. tensorflow笔记4:函数:tf.assign()、tf.assign_add()、tf.identity()、tf.control_dependencies()

    函数原型: tf.assign(ref, value, validate_shape=None, use_locking=None, name=None)   Defined in tensorflo ...

  10. c#使用dynamic关键字传输数据的用法

    问: 在实际开发中,特别是在ORM框架的基础下,我们返回的数据都是强类型的实体对象.如果是单表查询我们就可以直接返回对应的实体,如果是多表联合查询,我们可能就需要各个表中都返回一部分字段,组成一个新的 ...