技巧性 通过使用CASE表达式来实现,形式上有一些奇怪 SELECT num1, num2 FROM dbo.tableB CASE WHEN num1 = 0 THEN 0 WHEN num1/num2 > 2 THEN 1 ELSE 0 END = 1。 其中1表示true,0 表示false
合理规划 SELECT num1, num2 FROM dbo.tableB WHERE (num1 < 0 AND num2/num1 > 5) OR (num1 > 0 AND num2/num1 > 5)
字符数据类型及其函数
最基础的字符类型包括 ASCII(American Standard Code for Information Interchange,这单词还是第一次认真看)和Unicode类型,在T-SQL中就是(CHAR, VARCHAR)和(NCHAR, NVARCHAR)。ASCII每个字符用一个字节存储,用''单引号括起来,Unicode用2个字节存储,用N''包起来。CHAR字符类型是固定大小的,效率高但空间浪费率高,VARCHAR灵活节省空间,有2个字节偏移数据,但在字段值变长时,可能出现行扩展导致分页等,更新效率较低。字符类型默认最长(max)为8000个字符,若超过使用LOB存储,放在行外,此外数据在压缩(Data Compression)是会有一些变化。
介绍一个不常见的知识点,排序规则,知道以下概念即可
获取数据库支持的排序规则:SELECT * FROM sys.fn_helpcollations()
筛选条件区分大小写; SELECT * FROM user WHERE name COLLATE Latin1_General_CS_AS = N'xionger'
接下来是最重要的字符函数使用示例列表
关键字
解释与示例
+, CONCAT
连接字符串, SELECT firstname + lastname AS fullname FROM user,需要注意的是null与任何字符串连接操作的结果还是NULL
SUBSTRING
获取world子串:SELECT SUBSTRING('hello world', 7, 5),注意index从1开始,不是0
LEFT, RIGHT
SUBSTRING的简化形式,获取字符串左边/右边指定的字符数,有个一个很经典的应用场景如下
对ID值补0操作:SELECT RIGHT('0000000000' + CAST(1973 AS char(10)), 10), 1973可以为任何的类似ID的变量
LEN, DATALENGTH
前者返回字符长度,后者返回字节长度,SELECT LEN('abcde'), LEN(N'abcde'), DATALENGTH(N'abcde')的结果为: 5, 5, 10
CHARINDEX, PATINDEX
前者返回子串第一次出现的位置,后者返回匹配的子串第一次出现的位置,SELECT CHARINDEX(' ', 'xiong er 1'), PATINDEX('%[1-9]', 'xiong er 1'),结果6, 10
REPLACE, REPLICATE, STUFF
分别是替换、复制和删除后新增,SELECT REPLACE('1e11', 'e', '1'), REPLICATE('0', 10), STUFF('1e11', 2, 2, '222'),结果为 1111, 0000000000, 12221
LIKE
包括几个常见的通配符,% 表示任意大小字符串 ,_ 表示单个字符,以及其他常见正则表达式,如[ABC]、[A-Z]、[^1-9]
时间日期数据类型及其函数
在T-SQL中,常见的时间类型仅仅包含DATETIME,其实记住这个基本上足够用了。其他的都是一些更高精度和便捷的选择,包括SMALLDATETIME,DATE, TIME, DATETIME2,DATETIMEOFFSET等,精度达到了ns纳秒级,需要时再查阅即可。需要提及的一点时,在SQL中经常使用字符串常量格式的日期实际上最终是通过一个隐式转化为变为DATETIME类型的,如ordedate = '20160203'等价于orderdate = CAST('20160203'AS DATETIME),这儿的转化是基于当前会话的语言格式的,在实际中为了兼容,推荐使用与语言无关的常量格式: YYYYMMDD hh:mm:ss.nnn或YYYT-MM-DD。
接下来,将一个很容易忽视的知识点,筛选时间范围,涉及查询优化,比如我们想选择今年的全部订单,很自然的会想到如下SQL语句。
错误的方式 SELECT * FROM [order] WHERE YEAR(orderdate) = 2016
正确的方式 SELECT * FROM [order] WHERE orderdate >= '20160101' AND orderdate < '20170101'
对于所有的查询条件,尽可能的不要在其上使用表达式,这样查询优化器更可能通过索引的方式查找,此外想说的是,查询的条件的顺序也很重要哦,其需要和你所建立组合索引的顺序一致。
时间日期函数看起来比较简单,但在实际的使用中,由于不同的时间格式,往往会让人非常的困扰,毕竟那么多的API使用起来选择比较多,这儿将最常见的罗列了出来。
关键字
解释与示例
GETDATE(), CURRENT_TIMESTAMP
均是获得当前时间,后者遵循ANSI SQL规范
CAST, CONVERT, PARSE
将输入值转换为目标类型,CAST(value AS datatype)最简单,CONVERT(datatype, value [,style_number])足够完美,PARSE(value AS datatype [USING culture])
在SQLSERVER2008之后版本获取时间、日期方式:CAST(GETDATE() AS DATE), CAST(GETDATE() AS TIME)
老版本兼容方式:SELECT CONVERT(CHAR(8),GETDATE(),112), SELECT CONVERT(CHAR(12),GETDATE(),114)
此外如果想的到今天的午夜时间可以用:SELECT CAST(CONVERT(CHAR(8),GETDATE(),112) AS DATETIME)
DATEADD
增加一年, SELECT DATEADD(year, 1, CURRENT_TIMESTAMP), month, day,second, quarter季度, week星期等类似
DATEDIFF
返回两个日期间的差值,SELECT DATEDIFF(day, '20160101', CURRENT_TIMESTAMP)
常见的,获得本月(年)的开始:SELECT DATEADD(MONTH, DATEDIFF(month, '19000101', CURRENT_TIMESTAMP), '19000101')
获得本月(年)的结束:SELECT DATEADD(day, -1, DATEADD(MONTH, DATEDIFF(month, '19000101', CURRENT_TIMESTAMP) + 1, '19000101'))
这部分如果和之前的筛选时间日期的知识点结合在一起就能写出非常灵活的SQL代码
DATEPART, YEAR, MONTH, DAY
获取时间日期中的部分整数,DATEPART(month, CURRENT_TIMESTAMP), 后面的3个函数是前面的简化版
基本元数据查询
对于.NET程序员来说,元数据这个概念一点也不陌生,这儿指的是数据库本身以及其中对象的结构信息,接下来介绍最简单的几种元数据的查询。
元数据查询类型
解释与示例
目录视图
获取表信息:SELECT SCHEMA_NAME(schema_id) AS table_schema_name, name AS table_name FROM sys.tables
获取列信息:SELECT name AS columnName, TYPE_NAME(system_type_id) AS columnType FROM SYS.columns WHERE object_id = object_id(N'dbo.tableA')
此外还有很多的目录信息都在sys这个schema之下,这儿只选择最常见的表和列
信息架构视图(推荐使用)
这其实是前面目录视图的标准化版本,功能基本类似,相对更加的简洁,推荐使用这种方式查询,相关视图均在INFORMATION_SCHEMA这一schema下
表信息: SELECT TABLE_CATALOG, TABLE_NAME, TABLE_SCHEMA, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES
列信息:SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'tableA' AND TABLE_SCHEMA = 'dbo'
系统存储过程和函数