第三部分:sql数据类型与三值逻辑。
7. 数据类型。
在数据库理论中,关系模型和数据类型这两部分内容是正交的(参看《程序员修炼之道》第8节关于“正交性”的讨论),互不依赖。换言之,关系模型并不关心每个表的字段的数据类型是什么,是整数、字符串等基本类型也好,是组合类型、类等自定义类型也好,关系模型只要求每个字段是原子的。
在数据库理论中,数据类型又被称为域,但域是更为严格的定义。比如一个班级的学生个数和学生平均分可能都是int类型,但这是两个不同的域,“学生个数 * 学生平均分 = 学生总分”,但“学生个数 + 学生平均分”是没有意义的。目前的主流dbms似乎尚未对域有很好的支持,但未来的情况可能会有所改变,而且,设计自定义类型也需要对这一问题有充分的认识。
详见《深度探索关系数据库》第2章。
对于数据库和sql的应用来说,除掌握关系模型的原理,还需要对dbms支持的数据类型及其转换规则有所认识。
1. 基本数据类型。
一个dbms通常都会支持以下几类基本数据类型(以sql server为例):
精确数字:整数(bigint/int/smallint/tinyint/bit),定点小数(decimal),货币(money/smallmoney)
近似数字:浮点数(float)
日期和时间:datetime/smalldatetime; date, time, datetime2, datetimeoffset(后4种为sql server 2008的新增类型)
字符串和unicode字符串:varchar/nvarchar, char/nchar(text/ntext已不再建议使用,用varchar(max)/nvarchar(max)代替)
二进制串(即字节流):varbinary, binary(image已不再建议使用,用varbinary(max)代替)
其他数据类型:具有特殊功能的类型(sql_variant, timestamp, uniqueidentifier, xml),不能用于表的特殊类型(cursor, table)
2. 关于数据类型需要注意的问题。
a. 两类特殊的数据类型。
日期和时间类型的数据存储方式和可用值范围、相关的计算、比较、显示**换为指定格式的字符串)都比较复杂,还涉及一组日期时间函数。参看datetime类型分析一帖。
字符串类型涉及到字符编码和排序规则,比较操作还包含like匹配(未来还可能会支持正则表达式匹配),非常需要注意。参看理解字符编码和sqlserver中文处理二帖。
b. 如果对不同排序规则的两个字符串进行计算或比较,将会根据排序规则优先顺序来决定计算结果的排序规则或比较的方法。
c. 如果对不同类型的两个值进行计算或比较,将会根据数据类型优先级进行隐式转换。数据类型优先级基本规则如下:
大 > 小(>指优先级高于,下同):如bigint > int > smallint > tinyint > bit,varchar(20) >varchar(10),datetime > smalldatetime,等等。
可变 > 固定:如float > decimal,varchar > char,nvarchar > nchar,varbinary > binary。
各类型大类的优先级:datetime > float > decimal > integer > unicode string > ansi string > binary。
特殊数据类型的优先级和转换规则需要特殊考虑,详见联机丛书。
d. 如果对不同大小的两个值进行计算,将会根据精度、小数位数和长度的规则来产生新的类型大小。
e. 常量的数据类型(可以通过select col = 常量值 into testdt然后查看testdt表col字段的数据类型来观察)
如果不显式指定和隐式转换,null会按int类型处理。
''n'',1, 0x01, 1.0, 1e0, $1分别对应varchar, nvarchar, int, varbinary, decimal, float, money类型,并且长度是存储相应值所需要的最小长度。
f. 在软件开发领域众所周知:“隐式转换是bug的源泉”。因此,有两个建议:
使用常量时,最好使用对应类型的常量。比如,如果是varchar类型,那么where = 10的查询将不能使用索引,而且当遇到col中存放有不能转换为数字的值时将出错。
除非相应值的隐式转换非常直观,否则宁可用cast()/convert()指定明确的显式转换。
以上内容中,加下划线的粗体是联机丛书的标题。详细分析参看《microsoft sql server 2005技术内幕:t-sql程序设计》第1章。
8. null与三值逻辑。
三值逻辑(3vl, three-valued logic)绝对是sql修炼中的一个紧要关卡,值得特别注意,闭关静修。待冲破这一关卡之后,sql中的null与not null将别无二致。
关于sql是否应该允许null,在数据库领域已经近乎一个信仰式的争论。认为null有存在的必要,但他的好友认为null完全可以取消。最终结果是,sql标准支持null。
理论上的争论且不管。但在实践中,一定要知道null的三值逻辑会带来很多困扰的问题。
a. 不使用null的理由:
null会引入复杂的三值逻辑。
null在查询条件、外键和check约束、唯一约束、group by、order by中的行为都是不一致的。
b. 使用null的理由:
当需要表示一个未知的、不确定的值时,用null更自然。比如一个现在职员工的离职时间、顶级员工(boss)的上级员工,等等。
外联接通常会引入null,即使所有表的字段都定义为not null。
首先,如果可能,尽量让所有字段都声明为not null。除非是更适合使用null的场合(从业务出发)。
其次,在使用null时,一定要搞清楚三值逻辑和数据库引擎对null的处理:
sqlserver有一个选项set ansi_defaults,默认为on,即与sql标准一致。设为off的效果详见联机丛书。)
1. null与别的值进行+-*等计算操作(包括在大多数函数中使用null)后,结果是null(标量表达式)。null与别的值进行=、>等比较操作后,结果是unknown(断言)。
unknown相关的逻辑运算:
code=sql]
not unknown --unknown
unknown and/or unknown --unknown
unknown or true --true
unknown and true --unknown
unknown or false --unknown
unknown and false --false
/code]
具体可查三值逻辑的真值表。
2. 在where/on/h**ing和if/case when中,只有true才使条件成立(即unknown当作false来处理)。比如:
where column = value:表中column为null的行永远不会返回,即使value是null;
case value when null then xxx when ..end:xxx永远不会执行,即使value是null;
if xxx else yyy end或case when then xxx else yyy end:这两种情况下,yyy会执行。
3. 包含外键约束和check约束的字段允许null(即约束只当条件为false时出错,unknown是不管的)。
4. 包含唯一约束(unique index)的字段只允许一个null的行,再插入或更新该字段为null的行会报字段重复的错误。
5. group by时,所有null被视为一组。
6. order by时,所有null排在一起,但null排在非空值的前面(如sql server)还是后面(如oracle),sql标准未规定。
7. 聚集函数(sum/**g/max/min/count)忽略null的行。
8. declare的变量,在未赋值之前为null。
9. 与null处理相关的运算符和函数:
is null/is not null:用这两个运算符来判断一个值是否为null,而不是=或<>。
isnull/coalesce:取第一个非空值(注意两个函数的数据类型转换规则不同)。
nullif(a,b):等价于case when a = b then null else a end。
第四部分:dbms扩展功能与sql高级话题。
9. dbms提供的扩展功能。
掌握了基本的关系模型原理和dbms的数据类型,还需要对dbms提供的扩展功能有所了解,才能充分运用dbms进行数据库开发。
9.1. 控制流。
sql是说明式语言,但dbms面对实际开发的需求,通常在sql方言中都提供了过程式的扩展,包括(以t-sql为例):
1. 变量定义和赋值。
code=sql]
declare @var 变量定义语句
set @var = 通过set语句赋值
select @var = max(column_value) from [table] -通过select语句赋值
/code]
2. **块。
begin ..end定义一个**块。
对于下面的if/else和while,如果忽略了begin ..end**块,条件和循环将只对其后的第一个语句生效。
3. 条件分支语句。
if ..else ..
注意if语句与case when表达式的区别。
4. 循环控制语句。
while可以进行循环。break/continue可以跳出或进行下一次循环。
5. 异常处理语句。
sql server 2005支持try-catch语句进行异常处理,但只能处理一部分异常。详见联机丛书。
9.2. 动态语句。
sql动态语句的功能很强大,但是难以调试和维护(字符串拼接、无语法高亮)、效率低(难以重用执行计划)、安全性差(sql注入)。除非功能上必须,否则尽量避免使用动态sql。
假如真的需要使用动态sql,使用sp_executesql的方式优于exec()的方式。因为前者有些时候可以重用执行计划而改善性能,而且允许传参,数据类型上更安全。
9.3. dbms支持的数据库对象。
sql server还支持临时表、视图、存储过程、自定义函数(标量和表值)、触发器、游标等数据库对象,这是利用sql server进行开发必须掌握的知识。参看《microsoft sql server 2005技术内幕:t-sql程序设计》相关章节。
9.4. dbms提供的系统函数、系统视图和系统存储过程。
system functions:提供特定的表达式运算功能,如日期时间函数、字符串函数、数学函数、聚合函数等,是t-sql编程必需的。
system views:包含了数据库元数据、系统内部运行数据等,如目录视图(用来代替sql server 2000中的系统表)、信息架构视图、动态管理视图等。
system procedures:查看系统信息、修改系统配置等,如目录存储过程、数据库引擎存储过程等。
9.5. dbms提供的工具。
数据库服务器配置工具:配置管理器、外围应用配置器等。
数据库客户端应用工具:ssms、sqlcmd、bcp等。
数据库性能工具:sql server profiler等。
10. 高级话题。
以下是数据库相关的高级话题,每一块都值得单独讨论,本帖不再详述。
1. 高级技术专题。
数据库设计。
服务器架构。
索引和性能优化。
事务、锁定与并发。
备份与还原。
相关书目: 《sql server 2005数据库服务器架构设计》
《microsoft sql server 2005技术内幕:存储引擎》
《microsoft sql server 2005技术内幕:查询、调整和优化》
《sql server 2005性能调校》
2. 开发和维护相关的管理专题。
数据库权限管理。
数据库对象的版本控制。
数据库开发的命名规范。
SQL学习
distinct 用于返回唯一不同的值。从 company 列中仅选取唯一不同的值,我们需要使用 select distinct 语句。order by 语句。order by 语句用于根据指定列对结果集进行排序,默认为升序排序,desc为降序排序。以字母顺序显示公司名称 以逆字母顺序显示 以逆字母...
sql学习
53学习笔记 sql server总结 基本涵盖sql的所有操作 sqlserver总结 基本涵盖sql的所有操作ddl databasedefinitionla dml databasemanipulation dcl databasecontrollangu dtm databasetrasac...
SQL学习
sql备份和还原。sql备份。1 sql数据库恢复模型。1 完全恢复模型。1 备份时要备份数据库的数据文件和日志文件。2 还原时使用数据库的备份的数据文件副本和全部日志信息来恢复数据库。3 能还原全部数据,并可以将数据库恢复到任意指定的时刻。4 为保证实现即时点恢复,对数据库的所有 作都将完整地记入...