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

安装 Sqlite3 和 数据库查看工具:

sudo apt-get install sqlite3
sudo apt-get install sqlitebrowser

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

基础概念:

  数据表中,纵向的一整列叫“列”,横向的一整行叫“记录”,“记录”中每一格叫“字段”,字段的内容叫“数据”

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

SQL 创建数据表:

Create Table 表名称 { 列名称 列数据类型, 列名称 列数据类型, ... };

  首先要知道,大多数的数据库引擎都使用“静态数据类型”(基本上除了 SQLite 之外的所有 SQL 数据库引擎都使用“静态数据类型”),使用静态类型,数据的类型就由它的“列”决定,与“列”类型不相符的数据是无法写入到该“列”中的。

  而 SQLite 采用的是“动态数据类型”(可以理解为 SQLite 是“无类型限制”的),这意味着你可以保存任何类型的“数据”到任何“表”的任何“列”中(整形主键“列”除外),无论这“列”声明的数据类型是什么。对于 SQLite 来说,不指定“数据类型”是完全合法的。如:

Create Table 表名称 { 列名称, 列名称, ... };

  尽管 SQLite 为我们提供了这种方便,但是考虑到数据库的平台可移植性,我们在实际的开发中还是应该声明“数据类型”,并且保证“存入的数据类型”和“声明的数据类型”是一致的。除非你有极为充分的理由,同时不再考虑数据库平台的移植问题,在此种情况下确实可以使用 SQLite 提供的这一特性。

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

  虽然 SQLite 对“数据类型”没有强制要求,但 SQLite 定义了 5 种最基本的“存储类型”,它们决定了“数据”在数据库中的存在形式。每个存放在 SQLite 数据库中的值(或者由这个数据库引擎操作的值)都属于下面 5 种“存储类型”中的一种:

1   NULL    无值(什么也没有,不等同于“空字符串”或 0)
2   INTEGER 有符号整数(根据值的大小存储在 1、2、3、4、6、8 字节中)
3   REAL    浮点数(8 字节的 IEEE 浮点数字)
4   TEXT    字符串(使用数据库内部的编码方式存储,默认 UTF-8)
5   BLOB    字节流(原样存储)

  也就是说 SQLite 本质上只有 5 种类别的数据,在 SQLite 的数据库中,也只能存入这 5 种类别的数据。

  INTEGER “存储类型”包含 6 种不同长度的不同整形的“数据类型”,这只在磁盘上造成了差异。当 INTEGER 值被从磁盘中读入到内存中以后,它们均被转换成最一般的数据类型(8 字节有符号整形)。

  SQLite 的 TEXT 编码方式可以通过 SQL 语句 PRAGMA encoding 来查询和修改:

// 查询当前编码方式,默认 UTF-8
PRAGMA encoding;

// 设置当前编码方式,只有以下几种
PRAGMA encoding = "UTF-8";
PRAGMA encoding = "UTF-16";
PRAGMA encoding = "UTF-16le";
PRAGMA encoding = "UTF-16be";

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

  虽然 SQLite 对“数据类型”没有强制要求,但依然有自己的“数据类型”,SQLite 内定了 5 种最基本的“数据类型”,它们决定了“数据”在写入数据库时的“修正方式”。所有的非内定“数据类型”最终都会被视为相应的内定“数据类型”。下面列出了 5 种内定的数据类型:

1、INTEGER

  当“文本类型”的数据被插入到此类字段中时,会被自动转换为 INTEGER 格式(前提是转换操作不会导致数据信息丢失以及完全可逆),之后再插入到目标字段中。如果转换失败,则 SQLite 仍会以 TEXT 方式存储该数据。

  对于 NULL 或 BLOB 类型的数据,SQLite 将不做任何转换,直接以 NULL 或 BLOB 的方式存储该数据。

  需要额外说明的是,对于浮点格式的“常量文本”,如 '30000.0',如果该值可以转换为 INTEGER 类型,同时又不会丢失数值信息,那么 SQLite 就会将其转换为 INTEGER 格式 3000 进行存储。

2、REAL

  规则等同于 INTEGER 数据类型,“文本类型”的数据会被转换为 REAL 格式。

3、NUMERIC

  规则等同于 INTEGER 数据类型,“文本类型”的数据会被转换为 INTEGER 或 REAL 格式,优先转换为 INTEGER 格式,如果不能转换为 INTEGER 格式,再尝试转换为 REAL 格式。

  在执行 CAST 表达式时与 INTEGER 有差别。

4、TEXT

  当“数值类型”的数据被插入到此类字段中时,会被自动转换为 TEXT 格式,之后再插入到目标字段中。

5、BLOB

  当“任何类型”的数据被插入到此类字段中时,将不做任何的转换,直接以该数据所属的数据类型进行存储。

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

  虽然 SQLite 有自己内定的“数据类型”,但依然可以使用非内定的“数据类型”来定义“列”。事实上,SQLite 接受“任意字符串”作为“数据类型”使用,也就是说,你可以使用“ABC”、“HELLO”等作为“数据类型”来定义“列”,如果你觉得这样做有意义的话。

  最终,SQLite 会把非内定的“数据类型”归类为某一个内定的“数据类型”,并将其视为内定“数据类型”来使用。归类原则如下:

1、如果“数据类型”字符串中包含“INT”,那么这些“数据类型”被归类为 INTEGER 类型。

2、如果“数据类型”字符串中包含“CHAR”、“CLOB”或“TEXT”,那么这些“数据类型”被归类为 TEXT 类型。

3、如果“数据类型”字符串中包含“BLOB”,那么这些“数据类型”被归类为 BLOB 类型。

4、如果“数据类型”字符串中包含“REAL”、“FLOA”或“DOUB”,那么这些“数据类型”被归类为 REAL 类型。

5、其余的“数据类型”被归类为 NUMERIC 类型。

  这 5 条归类原则具有先后优先级,前面的规则优先于后面的规则,比如某“列”的“数据类型”声明为“CharInt”,既有第 2 条规则中的“Char”,又有第 1 条规则中的“Int”,那么根据先后顺序,应该优先遵循第 1 条规则,则“CharInt”会被视为 INTEGER 类型。

  在 SQLite 中,类型 CHAR(255) 的长度信息 255 没有任何实际意义,仅仅是为了与其它数据库平台的声明保持一致性,CHAR(255) 最终会以 TEXT 格式存入数据库,没有长度限制。

----------

举例说明:

  比如声明某“列”的“数据类型”是“CHAR(255)“,根据“类型归类原则”,该“列”被视为 TEXT 类型,如果存入的数据是数值 32,那么在存入之前,SQLite 会把 32 转换为字符串 '32' 再存入相应的字段中。

  如果声明的“数据类型”是“SMALLINT”,根据“类型归类原则”,该“列”被视为 INTEGER 类型,如果存入的数据是字符串 '-32.0',那么在存入之前,SQLite 会把 '-32.0' 转换为整数 -32 再存入相应的字段中。但是,如果存入的是 'A32' 或 '-32.5',则无法正确转换,此时 SQLite 会以 TEXT 的形式将 'A32' 或 '-32.5' 存入相应的字段中。

  如果声明的“数据类型”是“ABC”,根据“类型归类原则”,该“列”被视为 NUMERIC 类型,如果存入的数据是字符串 '-32.0',那么在存入之前,SQLite 会把 '-32.0' 转换为整数 -32 再存入相应的字段中。如果存入的是 '-32.5',则 SQLite 会把 '-32.5' 转换为浮点数 -32.5 再存入相应的字段中。如果存入的是 'A32',则 SQLite 会以 TEXT 的形式将 'A32' 存入相应的字段中。

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

关于布尔值的存储:

  SQLite 没有单独的“布尔存储类型”,它使用 INTEGER 类型来存储布尔值,0 为 false,1 为 true。一般的做法是将布尔值转换为 0 或 1,然后再写入 SQLite 数据库中。

  下面的 Golang 代码会自动将 true 和 false 转换为 1 和 0:

sql.DB.Exec("insert into data values (?,?)", true,false)

  不能直接在 SQL 语句中使用 true 或 false,比如下面的代码将无法执行成功:

sql.DB.Exec("insert into data values (true,false)")

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

关于日期时间的存储:

  SQLite 没有提供专门的“日期时间存储类型”,如果要存储日期时间,必须先将日期时间转换成 SQLite 内定的“数据类型”,然后再写入数据库。

  SQLite 内置的日期和时间函数(date、time、datetime、julianday、strftime)能够将“日期时间字符串”转换为 TEXT,REAL 或 INTEGER 形式存放,程序可以任意选择这几个“存储类型”去存储日期和时间:

  TEXT    作为 IS08601 字符串("YYYY-MM-DD HH:MM:SS.SSS")
  REAL    从格林威治时间 11 月 24 日,4174 B.C 中午以来的天数
  INTEGER 从 1970-01-01 00:00:00 UTC 以来的秒数

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

关于比较表达式:

  在 SQLite3 中支持的“比较表达式”有:=、==、<、<=、>、>=、!=、<>、IN、NOT IN、BETWEEN、IS、IS NOT。

  数据的比较结果主要依赖于操作数的存储方式,其规则为:

1、存储方式为 NULL 的数值小于其它存储类型的值。

2、存储方式为 INTEGER 和 REAL 的数值小于 TEXT 或 BLOB 类型的值,如果同为INTEGER 或 REAL,则基于数值规则进行比较。

3、存储方式为 TEXT 的数值小于 BLOB 类型的值,如果同为 TEXT,则基于文本规则(ASCII 值)进行比较。

4、如果是两个 BLOB 类型的数值进行比较,其结果为 C 运行时函数 memcmp() 的结果。

  即:NULL < INTEGER、REAL < TEXT < BLOB

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

关于数学操作符:

  所有的“数学操作符”(+、-、*、/、%、<<、>>、&、、|)在执行数学运算前都会先将“操作数”转换为 NUMERIC 存储类型,即使在转换过程中可能会造成数据信息的丢失。此外,如果其中一个操作数为 NULL,那么它们的运算结果亦为 NULL。在数学操作符中,如果其中一个操作数看上去并不像数值类型,那么它们的运算结果为 0 或 0.0。

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

总结:

  在使用 Create Table 表名称 { 列名称 列数据类型, 列名称 列数据类型, ... }; 创建 SQLite 数据表时,“列数据类型”最好选用 INTEGER、REAL、NUMERIC、TEXT、BLOB 其中之一,因为 SQLite 本质上只支持这些“数据类型”。如果要兼容其它数据库平台,那么最好选用其它数据库平台支持的“数据类型”作为“列数据类型”。

  在向数据库中写入数据时,要保证“写入的数据类型”与“声明的数据类型”一致,这样创建出来的数据库文件才能兼容其它数据库平台。



posted on 2017-08-20 21:08  GoLove  阅读(2428)  评论(0编辑  收藏  举报