第三部分:SQL数据类型与三值逻辑

feilniu 2010-08-26 06:28:20
第三部分: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的源泉”。因此,有两个建议:
- 使用常量时,最好使用对应类型的常量。比如,如果table.col是varchar类型,那么WHERE table.col = 10的查询将不能使用索引,而且当遇到col中存放有不能转换为数字的值时将出错。
- 除非相应值的隐式转换非常直观,否则宁可用CAST()/CONVERT()指定明确的显式转换

以上内容中,加下划线的粗体是联机丛书的标题。详细分析参看《Microsoft SQL Server 2005技术内幕:T-SQL程序设计》第1章。


8. NULL与三值逻辑

三值逻辑(3VL, Three-valued Logic)绝对是SQL修炼中的一个紧要关卡,值得特别注意,闭关静修。待冲破这一关卡之后,SQL中的NULL与NOT NULL将别无二致。

关于SQL是否应该允许NULL,在数据库领域已经近乎一个信仰式的争论。E.F.Codd认为NULL有存在的必要,但他的好友C.J.Date认为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相关的逻辑运算:

NOT Unknown --> Unknown
Unknown AND/OR Unknown --> Unknown
Unknown OR TRUE --> TRUE
Unknown AND TRUE --> Unknown
Unknown OR FALSE --> Unknown
Unknown AND FALSE --> FALSE

具体可查三值逻辑的真值表。

2. 在where/on/having和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 <Unknown> XXX else YYY end或case when <Unknown> 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/AVG/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。

相关讨论帖:
- 关于 not in的疑问
- varchar类型是存储''值好一点还是NULL好一点
...全文
4307 76 打赏 收藏 转发到动态 举报
写回复
用AI写文章
76 条回复
切换为时间正序
请发表友善的回复…
发表回复
wangyanru0810 2013-05-06
  • 打赏
  • 举报
回复
很好,学习了
sz9804 2013-03-25
  • 打赏
  • 举报
回复
Mark.
hchoog 2013-03-22
  • 打赏
  • 举报
回复
SQL自学中
flyReaver 2012-01-26
  • 打赏
  • 举报
回复
看完前两章, 看第三章了, 楼主写的很好~
  • 打赏
  • 举报
回复
这么巧?我也刚刚看了这块内容
郗晓勇 2011-12-31
  • 打赏
  • 举报
回复
不错不错不错不错不错
湖中芦苇 2011-12-31
  • 打赏
  • 举报
回复
非常有用啊!谢谢楼主
icbc_atm 2011-11-09
  • 打赏
  • 举报
回复
留名 感谢楼主花这么大精力
大力水手 2011-11-07
  • 打赏
  • 举报
回复
支持一下!
zxssy2 2011-08-05
  • 打赏
  • 举报
回复
看了此贴,收获颇丰
lanshi520 2011-06-07
  • 打赏
  • 举报
回复
初学的似乎看不懂啊!!!!
xuexiaopi 2011-05-11
  • 打赏
  • 举报
回复
好东西,还得接着学啊!
naja 2011-05-11
  • 打赏
  • 举报
回复
很全面,谢谢
随风_csdn 2010-12-27
  • 打赏
  • 举报
回复
8错8错,学习了
lianfeng5837 2010-12-25
  • 打赏
  • 举报
回复
很不错的文章
hsliuqiugong 2010-12-25
  • 打赏
  • 举报
回复
讲得不错
canyuechunhui 2010-12-01
  • 打赏
  • 举报
回复
写的不错 顶贴
q461714878 2010-11-19
  • 打赏
  • 举报
回复
很好,很强大!
XINGTIAN_REDBACK 2010-11-14
  • 打赏
  • 举报
回复
写的不错,正在学习中
xxh_1969 2010-10-23
  • 打赏
  • 举报
回复
持续关注
加载更多回复(37)
第一篇 Oracle管理配置 第1章 Oracle安装配置(教学视频:10分钟) 23 1.1 Oracle简介 23 1.1.1 数据库术语 23 1.1.2 主流数据库简介 24 1.1.3 Oracle数据库的特点 24 1.2 安装Oracle数据库 25 1.2.1 Oracle数据库的版本变迁及安装环境 25 1.2.2 安装过程 26 1.2.3 安装中需要注意的问题 27 1.3 本章小结 28 1.4 习题 28 第2章 Oracle常用工具(教学视频:7分钟) 29 2.1 Net Configuration Assistant(网络配置助手) 29 2.1.1 监听程序配置 29 2.1.2 命名方法配置 31 2.1.3 本地Net服务名配置 32 2.2 Net Manager(网络管理员) 34 2.3 本章实例 36 2.4 本章小结 38 2.5 习题 38 第3章 SQL Plus和PL/SQL(教学视频:11分钟) 39 3.1 SQL Plus与PL/SQL简介 39 3.2 使用SQL Plus 40 3.2.1 登录SQL Plus 40 3.2.2 SQL Plus输出结果的格式化 41 3.2.3 SQL Plus小结 46 3.3 PL/SQL 46 3.3.1 PL/SQL常用开发工具 46 3.3.2 开发一个简单的PL/SQL程序 48 3.4 本章实例 49 3.5 本章小结 50 3.6 习题 50 第二篇 Oracle数据库对象 第4章 Oralce数据库(教学视频:15分钟) 51 4.1 创建Oracle数据库 51 4.2 Oracle数据库的相关术语 52 4.2.1 数据库 53 4.2.2 数据库实例和SID 53 4.2.3 ORACLE_SID 54 4.3 Oracle数据库的备份与恢复 55 4.3.1 逻辑备份/恢复(导出/导入) 55 4.3.2 物理备份/恢复 56 4.3.3 利用PL/SQL Developer备份数据库 60 4.4 本章实例 61 4.5 本章小结 61 4.6 习题 62 第5章 Oracle数据表对象(教学视频:42分钟) 63 5.1 Oracle表空间 63 5.1.1 Oracle表空间简介 63 5.1.2 创建Oracle表空间 64 5.1.3 查看表空间 66 5.1.4 修改数据库默认表空间 67 5.1.5 修改表空间名称 68 5.1.6 删除表空间 69 5.2 创建Oracle数据表 70 5.2.1 利用工具创建数据表 70 5.2.2 利用工具查看数据表 71 5.2.3 利用命令创建数据表 72 5.2.4 利用命令查看表结构 72 5.3 修改Oracle数据表结构 73 5.3.1 利用工具修改数据表结构 73 5.3.2 利用命令修改数据表结构 74 5.4 删除数据表 75 5.4.1 利用工具删除数据表 76 5.4.2 利用SQL语句删除数据表 76 5.5 备份/恢复数据表 76 5.5.1 利用工具备份/恢复数据表 77 5.5.2 利用命令备份/恢复数据表 82 5.6 临时表 83 5.6.1 临时表简介 83 5.6.2 会话级临时表 84 5.6.3 事务级临时表 85 5.6.4 查看临时表在数据库中的信息 86 5.6.5 临时表的应用场景 86 5.7 特殊的表dual 87 5.7.1 分析dual表 87 5.7.2 dual表的应用场景 87 5.7.3 修改dual表对查询结果的影响 88 5.8 本章实例 89 5.9 本章小结 90 5.10 习题 90 第6章 约束(教学视频:43分钟) 91 6.1 主键约束 91 6.1.1 主键简介 91 6.1.2 创建主键约束 92 6.1.3 修改表的主键约束 94 6.1.4 主键应用场景 96 6.2 外键约束 97 6.2.1 外键简介 97 6.2.2 创建外键约束 97 6.2.3 级联更新与级联删除 100 6.2.4 修改外键属性 102 6.2.5 外键使用 104 6.3 唯一性约束 105 6.3.1 唯一性约束简介 105 6.3.2 创建唯一性约束 105 6.3.3 修改唯一性约束 107 6.3.4 唯一性约束的使用 108 6.4 检查约束 108 6.4.1 检查约束简介 108 6.4.2 创建检查约束 108 6.4.3 修改检查约束 110 6.4.4 检查约束的使用 111 6.5 默认值约束 111 6.5.1 默认值约束简介 112 6.5.2 创建默认值约束 112 6.5.3 修改默认值约束 113 6.6 本章实例 115 6.7 本章小结 116 6.8 习题 116 第7章 视图(教学视频:50分钟) 117 7.1 关系视图 117 7.1.1 建立关系视图 117 7.1.2 修改/删除视图 118 7.1.3 联接视图 120 7.1.4 编译视图 122 7.1.5 使用force选项强制创建视图 124 7.1.6 利用视图更新数据表 125 7.1.7 with check option选项 126 7.1.8 关系视图小结 128 7.2 内嵌视图 128 7.2.1 内嵌视图简介 128 7.2.2 内嵌视图的使用 128 7.2.3 内嵌视图小结 130 7.3 对象视图 131 7.3.1 对象视图简介 131 7.3.2 对象视图简介 131 7.4 物化视图 133 7.4.1 物化视图简介 133 7.4.2 物化视图的使用 133 7.4.3 物化视图的数据加载 135 7.4.4 物化视图的数据更新 135 7.4.5 查询重写 136 7.5 本章小结 136 7.6 本章实例 137 7.7 习题 137 第8章 函数与存储过程(教学视频:48分钟) 138 8.1 函数 138 8.1.1 函数简介 138 8.1.2 创建函数 139 8.1.3 函数中的括号 140 8.1.4 函数的参数 141 8.1.5 函数的确定性 142 8.1.6 典型函数举例 143 8.2 存储过程 144 8.2.1 存储过程简介 144 8.2.2 创建存储过程 144 8.2.3 存储过程的参数——IN参数 146 8.2.4 存储过程的参数——OUT参数 147 8.2.5 存储过程的参数——IN OUT参数 149 8.2.6 存储过程的参数——参数顺序 149 8.2.7 存储过程的参数——参数的默认值 152 8.2.8 存储过程的参数——参数顺序总结 153 8.3 程序包 153 8.3.1 规范 153 8.3.2 主体 155 8.3.3 调用程序包中的函数/存储过程 157 8.3.4 程序包中的变量 158 8.4 本章实例 159 8.5 本章小结 161 8.6 习题 161 …… 第9章 游标(教学视频:36分钟) 162 第10章 触发器(教学视频:58分钟) 178 第11章 序列(教学视频:28分钟) 206 第12章 用户角色与权限控制(教学视频:45分钟) 215 第三篇 Oracle中的SQL 第13章 Oracle数据类型(教学视频:21分钟) 231 第14章 Oracle中的函数与表达式(教学视频:111分钟) 240 第15章 Oracle中的控制语句(教学视频:16分钟) 282 第16章 SQL查询(教学视频:55分钟) 290 第17章 SQL更新数据(教学视频:34分钟) 319 第四篇 Oracle编程高级应用 第18章 数据库速度优化与数据完整性(教学视频:32分钟) 332 第19章 数据一致性与事务管理(教学视频:46分钟) 341 第20章 并发控制(教学视频:35分钟) 356 第21章 Oracle中的正则表达式(教学视频:29分钟) 369 第五篇 Oracle与编程语言综合使用实例 第22章 Oracle在Java开发中的应用(教学视频:38分钟) 376 第23章 Oracle在C#开发中的应用(教学视频:12分钟) 391

34,576

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧