登录 用户中心() [退出] 后台管理 注册
 

热门搜索:
您的位置: 首页 首页 >> 很冷的技术 >> 很冷的技术 >> 主题: sqlite 的巨坑之弱类型(manifest typing)    [最新]
标题
sqlite 的巨坑之弱类型(manifest typing)
clq
浏览(374) - 2017-07-22 18:57:12 发表 编辑

关键字:

[2022-04-19 09:50:53 最后更新]
sqlite 的巨坑之弱类型(manifest typing)

sqlite 是我很喜欢的一个数据库引擎. 但因历史原因等于它有一些巨坑,
比如曾经我有一个程序写错了要保存的数据. sqlite 硬是硬生生的在 int 的字段中保存下了一段字符串!

我个人认为这实在是个大 bug ,不过目前的 sqlite 就是这样设计的,这就是 "弱类型(manifest typing)".
那么什么时候保存的是整数,什么时候会存为字符串呢.
各种文档各种语焉不详,例如以下这个流传很广的说法:
"语句中用单引号或双引号括起来的文字被指派为 TEXT"

这实际上是不对的,当这个 text 作为内容保存到 int 的字段时,如果可以转换为 int 数据库引擎是要先当做整数存入的. 所以在编写 sqlite 的 insert 语句时一定要小心!

--------------------------------------------------
以下内容来自 "SQLite权威指南 The Definitive Guide to SQLite" 的不同的两个章节,其实它们的说法是有点自想矛盾的,大家多自己测试.
其实总的来说目前的 sqlite 的意思是尽量按照使用者意图来推测数据类型.好处是这样能最大限度的支持不同数据库原有的 sql 语法,坏处则是失去的纠错的机会.
这种情况非常类似于 javascript,php 与 java,c++ 的区别.

--------------------------------------------------
Powered By Gisun  http://www.gisun.com

弱类型(manifest typing)

SQLite使用弱类型。

看下面的表:

CREATE TABLE foo( x integer,

    y text, z real );

向该表插入一条记录:

INSERT INTO foo VALUES ('1', '1', '1');

SQLite创建这条记录时,xyz3个字段中存储的是什么类型呢?答案是INTEGER, TEXTREAL

再看下面例子:

CREATE TABLE foo(x, y, z);

现在执行同样的插入语句:

INSERT INTO foo VALUES ('1', '1', '1');
现在,
xyz中存储的是什么类型呢?答案是TEXTTEXTTEXT

那么,是否SQLite的字段类型默认为TEXT呢?再看,还是第2个表,执行如下插入语句:

INSERT INTO foo VALUES (1, 1.0, x'10');
现在,
xyz中存储的是什么类型呢?答案是INTEGERREALBLOB

如果你愿意,可以为SQLite的字段定义类型,这看起来跟其它数据库一样。但这不是必须的,你可以尽管违反类型定义。这是因为在任何情况下,SQLite都可以接受一个值并推断它的类型。

总之,SQLite的弱类型可表示为:1)字段可以有类型,2)类型可以通过值来推断。类型亲和性介绍这两个规定如何相互关联。所谓类型亲和性就是在强类型(strict typing)和动态类型(dynamic typing)之间的平衡艺术。

--------------------------------------------------

存储类(Storage Classes)

如前文所述,SQLite在处理数据类型时与其它的数据库不同。区别在于它所支持的类型以及这些类型是如何存储、比较、强化(enforc)和指派(assign)。下面各节介绍SQLite处理数据类型的独特方法和它与域完整性的关系。

对于数据类型,SQLite的域完整性被称为域亲和性(affinity)更合适。在SQLite中,它被称为类型亲和性(type affinity)。为了理解类型亲和性,你必须先要理解存储类和弱类型(manifest typing)

SQLite5个原始的数据类型,被称为存储类。存储类这个词表明了一个值在磁盘上存储的格式,其实就是类型或数据类型的同义词。这5个存储类在表4-6中描述。

4-6
SQLite
存储类


名称


说明


INTEGER


整数值是全数字(包括正和负)。整数可以是1, 2, 3, 4, 6 8字节。整数的最大范围(8 bytes){-9223372036854775808, 0, +9223372036854775807}SQLite根据数字的值自动控制整数所占的字节数。


空注:参可变长整数的概念。


REAL


实数是10进制的数值。SQLite使用8字节的符点数来存储实数。


TEXT


文本(TEXT)是字符数据。SQLite支持几种字符编码,包括UTF-8UTF-16。字符串的大小没有限制。


BLOB


二进制大对象(BLOB)是任意类型的数据。BLOB的大小没有限制。


NULL


NULL表示没有值。SQLite具有对NULL的完全支持。


SQLite通过值的表示法来判断其类型,下面就是SQLite的推理方法:

l         SQL语句中用单引号或双引号括起来的文字被指派为TEXT。

l         如果文字是未用引号括起来的数据,并且没有小数点和指数,被指派为INTEGER。

l         如果文字是未用引号括起来的数据,并且带有小数点或指数,被指派为REAL。

l         用NULL说明的值被指派为NULL存储类。

l         如果一个值的格式为X'ABCD',其中ABCD为16进制数字,则该值被指派为BLOB。X前缀大小写皆可。

SQL函数typeof()根据值的表示法返回其存储类。使用这个函数,下面SQL语句返回的结果为:

sqlite> select typeof(3.14), typeof('3.14'), typeof(314), typeof(x'3142'), typeof(NULL);

typeof(3.14)   typeof('3.14')  typeof(314)    typeof(x'3142')      typeof(NULL)

real                text                integer            blob                      null

 

SQLite单独的一个字段可能包含不同存储类的值。请看下面的示例:

sqlite> DROP TABLE domain;

sqlite> CREATE TABLE domain(x);

sqlite> INSERT INTO domain VALUES (3.142);

sqlite> INSERT INTO domain VALUES ('3.142');

sqlite> INSERT INTO domain VALUES (3142);

sqlite> INSERT INTO domain VALUES (x'3142');

sqlite> INSERT INTO domain VALUES (NULL);

sqlite> SELECT ROWID, x, typeof(x) FROM domain;

返回结果为:

rowid      x            typeof(x)

1            3.142      real

2            3.142      text

3            3142      integer

4            1B          blob

5            NULL     null

这带来一些问题。这种字段中的值如何存储和比较?如何对一个包含了INTEGER、REAL、TEXT、BLOB和NULL值的字段排序?一个整数和一个BLOB如何比较?哪个更大?它们能相等吗?

答案是:具有不同存储类的值可以存储在同一个字段中。可以被排序,因为这些值可以相互比较。有完善定义的规则来做这件事。不同存储类的值可以通过它们各自类的“类值”进行排序,定义如下:

1. NULL存储类具有最低的类值。一个具有NULL存储类的值比所有其它值都小(包括其它具有NULL存储类的值)。在NULL值之间,没有特别的可排序值。

2. INTEGER或REAL存储类值高于NULL,它们的类值相等。INTEGER值和REAL值通过其数值进行比较。

3. TEXT存储类的值比INTEGER和REAL高。数值永远比字符串的值低。当两个TEXT值进行比较时,其值大小由“排序法”决定。

4. BLOB存储类具有最高的类值。具有BLOB类的值大于其它所有类的值。BLOB值之间在比较时使用C函数memcmp()。

所以,当SQLite对一个字段进行排序时,首先按存储类排序,然后再进行类内的排序 (NULL类内部各值不必排序) 。下面的SQL说明了存储类值的不同:

sqlite> SELECT 3 < 3.142, 3.142 < '3.142', '3.142' < x'3000', x'3000' < x'3001';

返回:

3 < 3.142              3.142 < '3.142'              '3.142' < x'3000'    x'3000' < x'3001'

1                   1                          1                          1


guest
2022-04-19 09:50:53 发表 编辑

ip: 5.188.211.22
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)


总数:1 页次:1/1 首页 尾页  
总数:1 页次:1/1 首页 尾页  


该采集也在以下书单中



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2017 clq, All Rights Reserved
CLQ工作室 版权所有