sqlite学习笔记

内容主要来自: https://www.sqlite.net.cn/tutorial/2.html

目录

1. SQLite入门

1.1 开始

在官网(https://www.sqlite.org/download.html)的Windows 区下载预编译的二进制文件(Precompiled Binaries for Windows):
sqlite-dll-win32-x86-3380500.zip或sqlite-dll-win64-x64-3380500.zip
sqlite-tools-win32-x86-3380500.zip
两个都要下载.

把下载的两个.zip文件解压出来都放到文件夹: D:\sqlite,
得到5个文件:

D:\sqlite>
sqldiff.exe
sqlite3.def
sqlite3.dll
sqlite3.exe
sqlite3_analyzer.exe

把D:\sqlite\添加到环境变量PATH中.

打开cmd窗口, 输入命令 sqlite3, 即可进入sqlite3的环境.
具体操作命令见第3章.

D: \xx\xx> sqlite3
SQLite version 3.27.2 2019-02-25 16:06:06
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>
sqlite>

1.2 点命令

使用.help可以获取点命令的清单

命令 选项 描述
.backup ?DB? FILE 备份 DB 数据库(默认是 "main")到 FILE 文件.
.bail ON|OFF 发生错误后停止. 默认为 OFF.
.databases 列出数据库的名称及其所依附的文件.
.dump ?TABLE? 以 SQL 文本格式转储数据库.
如果指定了 TABLE 表, 则只转储匹配 LIKE 模式的 TABLE 表.
.echo ON|OFF 开启或关闭 echo 命令.
.exit 退出 SQLite 提示符.
.explain ON|OFF 开启或关闭适合于 EXPLAIN 的输出模式.
如果没有带参数, 则为 EXPLAIN on, 即开启 EXPLAIN.
.header(s) ON|OFF 开启或关闭头部显示.
.help 显示消息.
.import FILE TABLE 导入来自 FILE 文件的数据到 TABLE 表中.
.indices ?TABLE? 显示所有索引的名称.
如果指定了 TABLE 表, 则只显示匹配 LIKE 模式的 TABLE 表的索引.
.load FILE ?ENTRY? 加载一个扩展库.
.log FILE|off 开启或关闭日志. FILE 文件可以是 stderr(标准错误)/stdout(标准输出).
.mode MODE 设置输出模式, MODE 可以是下列之一:
  1. csv 逗号分隔的值
  2. column 左对齐的列
  3. html HTML 的 <table> 代码
  4. insert TABLE 表的 SQL 插入(insert)语句
  5. line 每行一个值
  6. list 由 .separator字符串分隔的值
  7. tabs 由 Tab 分隔的值
  8. tcl TCL 列表元素
.nullvalue STRING 在 NULL 值的地方输出 STRING 字符串.
.output FILENAME 发送输出到 FILENAME 文件.
.output stdout 发送输出到屏幕.
.print STRING... 逐字地输出 STRING 字符串.
.prompt MAIN CONTINUE 替换标准提示符.
.quit 退出 SQLite 提示符.
.read FILENAME 执行 FILENAME 文件中的 SQL.
.schema ?TABLE? 显示 CREATE 语句.
如果指定了 TABLE 表, 则只显示匹配 LIKE 模式的 TABLE 表.
.separator STRING 改变输出模式和 .import 所使用的分隔符.
.show 显示各种设置的当前值.
.stats ON|OFF 开启或关闭统计.
.tables ?PATTERN? 列出匹配 LIKE 模式的表的名称.
.timeout MS 尝试打开锁定的表 MS 毫秒.
.width NUM NUM 为 "column" 模式设置列宽度.
.timer ON|OFF 开启或关闭 CPU 定时器.
sqlite> .databases  
main: E:\myfile\python\pycharm\test\sqlite3.db  
sqlite>  
sqlite> .dump book  
PRAGMA foreign_keys=OFF;  
BEGIN TRANSACTION;  
CREATE TABLE book(  
        id   int primary key,  
        sort int,  
        name text,  
        price real,  
        category int,  
        foreign key (category) references category(id) on update cascade on delete cascade  
    );  
INSERT INTO book VALUES(2,3,'Python Intro',17.5,2);  
COMMIT;  
sqlite>   

1.3 格式化输出

sqlite>.header on   --显示表头
sqlite>.mode column --输出格式为左对齐的列
sqlite>.timer on    --开始cpu定时器
sqlite>

1.4 语法规则

语法 说明
大小写 SQLite不区分大小写, 但个别命令要区分, 比如GLOB和glob是不相同的.
注释
  1. 不能嵌套
  2. 以两个连续"-"开始, 到下一个换行符或输入结束位置
  3. 以"/*"开始, 到"*/"字符或输入结束
语句 以关键字开始, 以分号结束, 常用关键字
  • select
  • insert
  • update
  • delete
  • alter
  • drop

2. 数据类型

2.1 常用类型

SQLite中, 每一列、每个变量、每个表达式都有相关的数据类型.
可以在创建表时使用这些数据类型.

存储类 描述
NULL 值是一个 NULL 值.
INTEGER 值是一个带符号的整数, 根据值的大小存储在 1、2、3、4、6 或 8 字节中.
REAL 值是一个浮点值, 存储为 8 字节的 IEEE 浮点数字.
TEXT 值是一个文本字符串, 使用数据库编码(UTF-8、UTF-16BE 或 UTF-16LE)存储.
BLOB 值是一个 blob 数据, 完全根据它的输入存储.

2.2 亲和(Affinity)类型

什么是亲和性:
SQLite不强制数据类型约束, 任何数据类型可以插入任何列.
比如, 可以向整型列中插入任意长度的字符串, 可以向bool型列中插入浮点数.
在create table时, 虽然对每列指定了数据类型, 但实际插入数据时并不会限制.
任何列均可接受任意长度的字符串(有一个例外: INTEGER PRIMARY KEY的列只能存储64位整数).
当向整型列中插入字符串时, SQLite会试图将该字串转换成一个整数, 如果转换成功则插入该整数, 如果转换失败, 则插入字符串.
这种特性被称为类型或列亲和性(type or column affinity).

SQLite有5种数据类型:

亲和类型 描述
TEXT 数值型数据在被插入之前, 需要先被转换为文本格式, 之后再插入到目标字段中.
NUMERIC
INTEGER 对于亲缘类型为INTEGER的字段, 其规则等同于NUMERIC, 唯一差别是在执行CAST表达式时.
REAL 其规则基本等同于NUMERIC, 唯一的差别是不会将"30000.0"这样的文本数据转换为INTEGER存储方式.
NONE 不做任何的转换, 直接以该数据所属的数据类型进行存储.

2.3 亲和类型及类型名称

2.4 boolean数据类型

SQLite没有单独的 Boolean 存储类. 相反, 布尔值被存储为整数 0(false)和 1(true).

2.5 Date与Time数据类型

SQLite 没有一个单独的用于存储日期和/或时间的存储类, 但 SQLite 能够把日期和时间存储为 TEXT、REAL 或 INTEGER 值.

3 操作数据库

3.1 创建

如下命令创建了一个数据库文件test.db.

PS E:\myfile\python\pycharm\test> sqlite3.exe test.db  
SQLite version 3.27.2 2019-02-25 16:06:06  
Enter ".help" for usage hints.  
sqlite>   
sqlite> .databases  
main: E:\myfile\python\pycharm\test\test.db  


--也可以使用.open命令:
--   1) 如果test1.db存在, 就直接打开它.
--   2) 如果test1.db不存在, 就创建它.
sqlite> .open test1.db

3.2 导出

使用.dump命令, 把数据库导出到文本文件中.

PS E:\myfile\python\pycharm\test> sqlite3 test.db .dump > test.db.sql  
PS E:\myfile\python\pycharm\test> cat test.db.sql  
PRAGMA foreign_keys=OFF;  
BEGIN TRANSACTION;  
COMMIT;  
PS E:\myfile\python\pycharm\test>  

还可以从.sql文件中恢复数据库

--注, 在window下, 直接用上一步导出的test.db.sql会报错,
--    而使用手工书写的test.sql没有问题.
sqlite3 test.db < test.sql

3.3 附加

假设这样一种情况, 当在同一时间有多个数据库可用, 您想使用其中的任何一个.
SQLite 的 ATTACH DATABASE 语句是用来选择一个特定的数据库, 并把数据库文件与一个名称连接起来.
使用该命令后, 所有的 SQLite 语句将在附加的数据库下执行.

PS E:\myfile\python\pycharm\test> sqlite3 sqlite3.db  
SQLite version 3.27.2 2019-02-25 16:06:06  
Enter ".help" for usage hints.  
sqlite>   
sqlite> .database  
main: E:\myfile\python\pycharm\test\sqlite3.db  
sqlite>   
sqlite> attach database 'test.db' as 'test'; --添加一个现有的数据库test.db, 数据库名叫test.
sqlite>   
sqlite> .database  
main: E:\myfile\python\pycharm\test\sqlite3.db  
test: E:\myfile\python\pycharm\test\test.db  
sqlite>  

注意, main和temp这两个名称是保留的, 所以不能被attach

sqlite> attach database 'test.db' as 'temp';  
Error: database temp is already in use  
sqlite>   
sqlite> attach database 'test.db' as 'main';  
Error: database main is already in use  
sqlite>  

3.4 分离

与attach相反, detach命令把数据库文件与名称的关联进行分离.
如果同一个数据库文件被附加上多个别名, detach只断开当前名称的连接, 其余名称连接仍然有效.

注意: 无法分离main和temp.
注意: 如果是内存中的数据库或临时数据库, detach后对应数据库将会被摧毁, 内容将会丢失.

sqlite>.databases  
seq  name             file  
---  ---------------  ----------------------  
0    main             /home/sqlite/testDB.db  
2    test             /home/sqlite/testDB.db  
3    currentDB        /home/sqlite/testDB.db  
sqlite>   
sqlite> DETACH DATABASE 'currentDB';  
sqlite> .databases  
seq  name             file  
---  ---------------  ----------------------  
0    main             /home/sqlite/testDB.db  
2    test             /home/sqlite/testDB.db  

4 操作表

4.1 列出表名称.table

语法:

1.	.table
2.	select tbl_name from sqlite_master where type='table'; --见4.4查询表

4.2 创建表(CREATE)

语法:

CREATE TABLE database_name.table_name(  
  column0 data_type PRIMARY KEY(one or more columns),  
  column1 data_type,  
  column2 data_type,  
  ...  
  columnN data_type,  
);  

例:

PS E:\myfile\python\pycharm\test> sqlite3 test.db  
SQLite version 3.27.2 2019-02-25 16:06:06  
Enter ".help" for usage hints.  
sqlite>   
sqlite> CREATE TABLE company( --create a table company  
   ...>     id      INT  PRIMARY KEY NOT NULL,  
   ...>     name    TEXT             NOT NULL,  
   ...>     age     INT              NOT NULL,  
   ...>     address CHAR(50),  
   ...>     salary  REAL  
   ...> );  
sqlite> CREATE TABLE department( --create a table department  
   ...>     id      INT  PRIMARY KEY NOT NULL,  
   ...>     dept    CHAR(50)         NOT NULL,  
   ...>     emp_id  INT              NOT NULL  
   ...> );  
sqlite>  
sqlite> .tables --列出附加数据库中的所有表.   
company     department  
sqlite>  
sqlite> .schema company --得到表的完整信息  
CREATE TABLE company(  
    id      INT  PRIMARY KEY NOT NULL,  
    name    TEXT             NOT NULL,  
    age     INT              NOT NULL,  
    address CHAR(50),  
    salary  REAL  
);  
sqlite>  

4.3 删除表(DROP)

语法:

DROP TABLE database_name.table_name;

例:

sqlite> .tables  
company     department  
sqlite>  
sqlite> DROP TABLE company;  
sqlite>  
sqlite> .tables  
department  
sqlite>  

4.4 查询表(SELECT)

获取库中所有表的名称:

sqlite> --注意, tbl_name和sqlite_master都是固定名称, 不能随便取  
sqlite> select tbl_name from sqlite_master where type='table';  
tbl_name  
---------------  
department  
company  
Run Time: real 0.007 user 0.000000 sys 0.000000  
sqlite>  

获取表的完整信息

sqlite> select sql from sqlite_master where type='table' and tbl_name='company';  
CREATE TABLE company(  
    id      INT  PRIMARY KEY NOT NULL,  
    name    TEXT             NOT NULL,  
    age     INT              NOT NULL,  
    address CHAR(50),  
    salary  REAL  
)  
sqlite>  

5 操作表中的记录

5.1 增(INSERT)

语法:

INSERT INTO table_name                        VALUES(value0, value1, value2, …); --为所有列添加值
INSERT INTO table_name (colx, coly, cloz, …) VALUES(valuex, valuey, valuez, …); --为指定列添加值

例:

sqlite> CREATE TABLE company(  
   ...>     id      INT  PRIMARY KEY NOT NULL,  
   ...>     name    TEXT             NOT NULL,  
   ...>     age     INT              NOT NULL,  
   ...>     address CHAR(50),  
   ...>     salary  REAL  
   ...> );  
sqlite>  
sqlite> INSERT INTO company(id, name, age, address, salary) VALUES(1, 'Paul' , 32, 'California', 20000.0);  
sqlite> INSERT INTO company(id, name, age, address, salary) VALUES(2, 'Allen', 25, 'Texas'     , 15000.0);  
sqlite> INSERT INTO company(id, name, age, address, salary) VALUES(3, 'Teddy', 23, 'Norway'    , 20000.0);  
sqlite> INSERT INTO company(id, name, age, address, salary) VALUES(4, 'Mark' , 25, 'Rich-mond' , 65000.0);  
sqlite> INSERT INTO company(id, name, age, address, salary) VALUES(5, 'David', 27, 'Texas'     , 85000.0);  
sqlite> INSERT INTO company(id, name, age, address, salary) VALUES(6, 'Kim'  , 22, 'South-Hall', 45000.0);  
sqlite> INSERT INTO company                                 VALUES(7, 'James', 24, 'Houston'   , 10000.0);  
sqlite>   

也可以使用另一个表的数据来填充表格
语法:

INSERT INTO first_table_name [(colx, coly, colz, ...)]
    SELECT colo, colp, colq FROM second_table_name
    [WHERE condition];

5.2 删(DELETE)

用于删除表中已经有的记录

语法:

DELETE FROM table-name
[WHERE condition];

只删除WHERE子句匹配的记录.
如果没有WHERE子句, 则删除所有记录.

sqlite> select * from company;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          Texas       1.0  
2           Allen       25          Texas       1.0  
3           Teddy       23          Texas       1.0  
4           Mark        25          Texas       1.0  
5           David       27          Texas       1.0  
6           Kim         22          Texas       1.0  
7           James       24          Texas       1.0  
sqlite> delete from company where id=6; --删除id=6的记录  
sqlite> select * from company;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          Texas       1.0  
2           Allen       25          Texas       1.0  
3           Teddy       23          Texas       1.0  
4           Mark        25          Texas       1.0  
5           David       27          Texas       1.0  
7           James       24          Texas       1.0  
sqlite>  
sqlite> delete from company; --删除所有记录  
sqlite> select * from company;  
sqlite>  

5.3 改(UPDATE)

语法:

UPDATE table-name
SET colA=valueA,  colB=valueB, …
[WHERE condition]

只对WHERE匹配到的条目进行修改.
如果不指定WHERE子句, 则会修改所有的记录

sqlite> select * from company;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
sqlite>  
sqlite> update company set address='Texas' where id=6;  
sqlite> select * from company;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          Texas       45000.0  
7           James       24          Houston     10000.0  

对所有条目修改addr和salary.

sqlite> update company set address='Texas', salary=1.0;  
sqlite> select * from company;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          Texas       1.0  
2           Allen       25          Texas       1.0  
3           Teddy       23          Texas       1.0  
4           Mark        25          Texas       1.0  
5           David       27          Texas       1.0  
6           Kim         22          Texas       1.0  
7           James       24          Texas       1.0  
sqlite>  

5.4 查(SELECT)

语法:

SELECT col1,  col2, … FROM table_name;
SELECT * FROM table_name;

例:

sqlite> --设置显示格式  
sqlite> .header on  
sqlite> .mode column  
sqlite> .timer on  
sqlite>  
sqlite> --获取company内的所有字段  
sqlite> SELECT * FROM company;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
Run Time: real 0.009 user 0.000000 sys 0.000000  
sqlite>  
sqlite> --获取部分字段  
sqlite> SELECT name, salary FROM company;  
name        salary  
----------  ----------  
Paul        20000.0  
Allen       15000.0  
Teddy       20000.0  
Mark        65000.0  
David       85000.0  
Kim         45000.0  
James       10000.0  
Run Time: real 0.016 user 0.000000 sys 0.000000  
sqlite>  
sqlite> --设置列宽度, 单位为字符数  
sqlite> .width 2, 10 --第一列2个字符(会导致显示不全), 第二列10个字符.
sqlite> SELECT name, salary FROM company;  
na  salary  
--  ----------  
Pa  20000.0  
Al  15000.0  
Te  20000.0  
Ma  65000.0  
Da  85000.0  
Ki  45000.0  
Ja  10000.0  
Run Time: real 0.016 user 0.000000 sys 0.000000  
sqlite>  

子查询+外查询

sqlite> --查询salary>60000的age, 有两个, 25, 27  
sqlite> select age from company where salary>60000;   
age  
----------  
25  
27  
sqlite> --子查询:salary>60000的age, 返回25和27, 外查询:age大于25的条目.   
sqlite> select * from company where age>(select age from company where salary>60000);  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
5           David       27          Texas       85000.0  
sqlite>  

6 运算符与表达式

6.1 运算符

在WHERE语句中执行操作.
用于指定语句中的条件、连接多个条件.

算术运算符、比较运算符、逻辑运算符、位运算符.

6.1.1 算术运算符

算术运算符 描述
+
-
*
/
%

例:

sqlite> .mode line --每行一个值  
sqlite>   
sqlite> select 12 + 5;  
12 + 5 = 17  
sqlite>   
sqlite> select 12 - 5;  
12 - 5 = 7  
sqlite>   
sqlite> select 12 * 5;  
12 * 5 = 60  
sqlite>   
sqlite> select 12 / 5; --整数相除得整数  
12 / 5 = 2   
sqlite>   
sqlite> select 12.0 / 5; --real相除得real  
12.0 / 5 = 2.4  
sqlite>   
sqlite> select 12 % 5;   
12 % 5 = 2  
sqlite>  

6.1.2 比较运算符

比较运算符 描述
== 相等
= 相等, 与==同
!= 不相等
<> 不相等, 与!=同
>、>= 大于、大于等于
<、<= 小于、小于等于
!> 不大于
!< 不小于

例:

sqlite> .mode column  
sqlite> .headers on  
sqlite> select * from company; --全体数据  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
sqlite>  
sqlite> select * from company where salary>50000; --大于  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
sqlite>  

sqlite> select * from company where salary=20000; --等于  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
3           Teddy       23          Norway      20000.0  
sqlite>  
sqlite> select * from company where salary!=20000; --不等于  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
2           Allen       25          Texas       15000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
sqlite>  
sqlite> select * from company where salary<>20000; --不等于  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
2           Allen       25          Texas       15000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
sqlite>  

6.1.3. 逻辑运算符

逻辑运算符 描述
AND 两个表达式都为真, 则返回true
BETWEEN 操作数在指定范围内, 则返回true
EXISTS 子查询有结果集, 则返回true
IN 操作数等于列表中的值之一, 则返回true
NOT IN 操作数不等于列表中的所有值, 则返回true
LIKE 操作数与模式匹配, 则返回true
GLOB
NOT 反转其它布尔运算符的结果
OR 任一表达式为真, 则返回true
IS NULL 把操作数与NULL值比较
IS 与=相似
IS NOT 与!=相似
|| 连接两个字符串为一个新字符串
UNIQUE 搜索表中每一行, 如果唯一, 则返回true
sqlite> select * from company; --全体数据  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
sqlite>  

6.1.3.1 AND

sqlite>  --使用and  
sqlite> select * from company where age>=25 and salary>=65000;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
sqlite>  

6.1.3.2 OR

sqlite> --使用or  
sqlite> select * from company where age>=25 or salary>=65000;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
sqlite>   

6.1.3.3 IS, IS NOT

例:

sqlite> --使用is  
sqlite> select * from company where age is null;  
sqlite>   
sqlite> --使用is not  
sqlite> select * from company where age is not null;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
sqlite>  

6.1.3.4 LIKE

作用:用于匹配指定模式的文本值, 如果匹配则返回1.

通配符:

通配符 匹配的数目 匹配的内容
%(百分号) 0个、1个、多个 数字或字符
_(下划线) 1个 数字或字符

例:

语句 说明
where salary like ‘200%’ 以200开头的值
where salary like ‘%200%’ 在任意位置包含200的值
where salary like ‘_00%’ 第二第三位为00的值
where salary like ‘2_%_%’ 以2开头且长度至少为3的值
where salary like ‘%2’ 以2结尾的值
where salary like ‘_2%3’ 第二位为2, 最后一位为3的值
where salary like ‘2___3’ 第二位为2, 最后一位为3, 长度为5的值
sqlite> --使用like, 以Ki开始的字符  
sqlite> select * from company where name like 'Ki%';  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
6           Kim         22          South-Hall  45000.0  
sqlite>  

6.1.3.5 GLOB

作用:用于匹配指定模式的文本值, 如果匹配则返回1.

glob与like区别:

  1. glob的pattern对大小写敏感;
  2. 通配符不同

通配符:

通配符 匹配的数目 匹配的内容
*(星号) 0个、1个、多个 数字或字符
?(问号) 1个 数字或字符

sqlite> select * from company;--全体记录  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
  
sqlite> --匹配Pa*的记录  
sqlite> select * from company where name glob 'Pa*';  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
  
sqlite> --匹配PA*的记录, 大小写敏感, 所以无返回  
sqlite> select * from company where name glob 'PA*';  
  
sqlite> --匹配Pa的记录, 这个patten要求name长度为2, 所以无返回  
sqlite> select * from company where name glob 'Pa';  
  
sqlite> --使用like, 匹配时忽略大小写, 所以‘PA%’可以匹配Paul  
sqlite> select * from company where name like 'PA%';  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
sqlite>  

6.1.3.6 IN, NOT IN

sqlite> --使用in, 注意, 只包含23和27,  不是23到27之间的值.   
sqlite> select * from company where age in (23, 27);  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
3           Teddy       23          Norway      20000.0  
5           David       27          Texas       85000.0  
sqlite>   
sqlite> --使用not in, 与in相反  
sqlite> select * from company where age not in (23, 27);  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
4           Mark        25          Rich-mond   65000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
sqlite>  

6.1.3.7 BETWEEN a AND b

sqlite> --使用between A and B, 界于23和27之间的值, 包括边界  
sqlite> select * from company where age between 23 and 27;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
7           James       24          Houston     10000.0  
sqlite>  

6.1.3.8 EXISTS

exists操作符, 只返回真/假, 下例的select id, name, salary还是从总库中查找数据, 而不是在exists的结果中查找.

sqlite> select id, name, salary from company where exists(select age from company where salary>65000);  
id          name        salary  
----------  ----------  ----------  
1           Paul        20000.0  
2           Allen       15000.0  
3           Teddy       20000.0  
4           Mark        65000.0  
5           David       85000.0  
6           Kim         45000.0  
7           James       10000.0  
sqlite>  

6.1.4 位运算符

按位与:&
按位或:|
按位非:~
左移:<<
右移:>>

式子 DEC HEX
A 0011 1100 60 0x3C
B 0000 1101 13 0x0D
A&B 0000 1100 12 0x0C
A|B 0011 1101 61 0x3D
~A 1100 0011 195->-61 0xC3
A>>2 0000 1111 15 0x0F
A<<2 1111 0000 240 0xF0
sqlite> .mode line  
sqlite> select 60&13;  
60&13 = 12  
sqlite> select 60|13;  
60|13 = 61  
sqlite> select ~60;  
  ~60 = -61  
sqlite> select 60>>2;  
60>>2 = 15  
sqlite> select 60<<2;  
60<<2 = 240  
sqlite>  

十进制数60, 按位取反, 得到-61, 过程如下:

1. 十进制  :  60 对应 二进制8'b0011_1100.
2. 按位取反: ~60 对应 二进制8'b1100_0011, 最高位为1, 负数, 计算机认为负数应该是按补码存储的, 需要推出它的原码, 才能知道是什么值.
3. 得到补码:     对应 补码  8'b1100_0011,
3. 计算反码:     对应 反码  8'b1100_0010, 补码=反码+1, 反码=补码-1.
4. 计算原码:     对应 原码  8'b1011_1101, 最高位是符号位, 不取反, 其余位取反.
5. 十进制  :     0b(1011_1101)=0x(-3D)=-61, 最高位是符号位, 最终得到~60 = -61.

6.2 表达式

语法:

SELECT colA, colB, …
FROM table_name
[WHERE CONDITION | EXPRESSION]

6.2.1 布尔表达式

例:
SELECT * FROM company WHERE salary=10000;

salary=10000就是一个布尔表达式, 它通过匹配单个值获取数据.

6.2.2 数值表达式

用来执行查询中的任何数学运算.
可以使用内置函数:avg()、sum()、count()等

例:调用count函数, 计算表中内容的条数

sqlite> select count(*) as "item_cnt" from company;  
item_cnt = 7  -- company中共7条内容
sqlite>  

6.2.3 日期表达式

sqlite> select current_timestamp;  
current_timestamp = 2020-05-12 07:30:23  
sqlite>  

7 子句

7.1 WHERE子句

作用:
where子句用于指定(从一个表或多个表中)获取数据的条件.
可以使用where子句来过滤记录, 只获取需要的记录.
where子句可以用在SELECT、UPDATE、DELETE语句中.

语法:

SELECT column-list
FROM table_name
[WHERE condition];

sqlite> select * from company where age>=25 and salary>=65000;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
sqlite>  
sqlite> select * from company where name glob 'Ki*';  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
6           Kim         22          South-Hall  45000.0  
sqlite>  

7.2 limit子句

作用:用于限制select语句返回的数据数量

语法:

SELECT column-list
FROM table-name
LIMIT [row cnt] [OFFSET row-num];

例:

sqlite> select * from company; --全体数据  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  
sqlite> select * from company limit 3; --限制只提取3条记录  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
sqlite> select * from company limit 3 offset 2; --限制跳过两条记录后, 提取3条  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
sqlite>  

7.3 order by子句

语法:

SELECT column-list
FROM table-name
[WHERE condition]
ORDER BY colA [ASC | DESC], colB [ASC | DESC],  … ;

例:
全体数据:

sqlite> select * from company;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
2           Allen       25          Texas       15000.0  
3           Teddy       23          Norway      20000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
6           Kim         22          South-Hall  45000.0  
7           James       24          Houston     10000.0  

按age排序, 默认升序.

sqlite> select * from company order by age;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
6           Kim         22          South-Hall  45000.0  
3           Teddy       23          Norway      20000.0  
7           James       24          Houston     10000.0  
2           Allen       25          Texas       15000.0  
4           Mark        25          Rich-mond   65000.0  
5           David       27          Texas       85000.0  
1           Paul        32          California  20000.0  

按age排序, 降序

sqlite> select * from company order by age desc;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
5           David       27          Texas       85000.0  
2           Allen       25          Texas       15000.0  
4           Mark        25          Rich-mond   65000.0  
7           James       24          Houston     10000.0  
3           Teddy       23          Norway      20000.0  
6           Kim         22          South-Hall  45000.0  
sqlite>  

先按age降序排序, 如果age相同, 再按salary降序排序

sqlite> select * from company order by age desc, salary desc;  
id          name        age         address     salary  
----------  ----------  ----------  ----------  ----------  
1           Paul        32          California  20000.0  
5           David       27          Texas       85000.0  
4           Mark        25          Rich-mond   65000.0  
2           Allen       25          Texas       15000.0  
7           James       24          Houston     10000.0  
3           Teddy       23          Norway      20000.0  
6           Kim         22          South-Hall  45000.0  
sqlite>  

7.4 group by子句

作用:
用在SELECT语句中, 对相同的数据进行分组.
SELECT语句中, 以WHERE/GROUP BY/ORDER BY的顺序出现.

语法:

SELECT column-list
FROM table-name
WHERE condition
GROUP BY colA, colB, …
ORDER BY colX, colY, …

例:
全体数据, 其中有几个名字相同的:James, Paul

sqlite> select id,name,salary from company order by name;  
id          name        salary  
----------  ----------  ----------  
2           Allen       15000.0  
5           David       85000.0  
7           James       10000.0  
9           James       5000.0  
10          James       5000.0  
6           Kim         45000.0  
4           Mark        65000.0  
1           Paul        20000.0  
8           Paul        20000.0  
3           Teddy       20000.0  

把name相同人的salary进行求和:
其中三个James的记录合并为一条, 总工资为20000.0, 两条Paul记录合并为一条, 总工资为40000.0

sqlite> select id,name,sum(salary) from company group by name order by name;  
id          name        sum(salary)  
----------  ----------  -----------  
2           Allen       15000.0  
5           David       85000.0  
7           James       20000.0  
6           Kim         45000.0  
4           Mark        65000.0  
1           Paul        40000.0  
3           Teddy       20000.0  
sqlite>  

7.5 having子句

作用:允许指定条件来过滤将出现在最终结果中的分组结果.

与WHERE语句的关系:
WHERE子句:设置的条件作用到所选列上;
HAVING子句:设置的条件作用到(由GROUP BY子句创建的)分组上;

语法:HAVING子句必须放在GROUP BY与ORDER BY子句之间.

SELECT column-list
FROM table-name
WHERE conditions
GROUP BY colA, colB, …
HAVING conditions
ORDER BY colX, colY, …;

例:
全体记录

sqlite> select id,name,salary from company order by name;  
id          name        salary  
----------  ----------  ----------  
2           Allen       15000.0  
5           David       85000.0  
7           James       10000.0  
9           James       5000.0  
10          James       5000.0  
6           Kim         45000.0  
4           Mark        65000.0  
1           Paul        20000.0  
8           Paul        20000.0  
3           Teddy       20000.0  

选择name计数>=2的记录:

sqlite> select id, name, salary from company group by name having count(name)>=2;  
id          name        salary  
----------  ----------  ----------  
7           James       10000.0  
1           Paul        20000.0  
sqlite>  

7.6 distinct关键字

作用:与SELECT语句一起使用, 用于消除所有重复记录, 并只获取唯一一次记录.

语法:

SELECT DISTINCT column-list
FROM table-name
WHERE condition;

例:
全体数据:

sqlite> select id,name, salary from company order by name;  
id          name        salary  
----------  ----------  ----------  
2           Allen       15000.0  
5           David       85000.0  
7           James       10000.0  
9           James       5000.0  
10          James       5000.0  
6           Kim         45000.0  
4           Mark        65000.0  
1           Paul        20000.0  
8           Paul        20000.0  
3           Teddy       20000.0  
sqlite>  

去除name重复的记录, 返回没有任何重复的条目.

sqlite> select distinct name from company order by name;  
name  
----------  
Allen  
David  
James  
Kim  
Mark  
Paul  
Teddy  
sqlite>  

8. 进阶教程

8.1 PRAGMA

作用:pragma是一个特殊的命令, 用于在SQLite环境内部控制"环境变量"和"状态标志".

语法:

读取:PRAGMA pragma-name;
设置:PRAGMA pragma-name=value;
变量 作用 -
auto_vacuum 控制数据库文件大小是否自动缩小 -
cache_size - -
case_sesitive_like - -
count_changes - -
database_list - -
encoding - -
foreign_keys 外键 OFF, ON
freelist_count - -
index_info - -
index_list - -
journal_mode - -
max_page_count - -
page_count - -
page_size - -
parser_trace - -
recursive_triggers - -
schema_version - -
secure_delete - -
sql_trace - -
synchronous - -
temp_store_directory - -
user_version - -
writable_schema - -

8.2 约束

定义:在表的数据列上强制执行的规则. 用来限制插入到表中的数据类型. 保证数据的准确性和可靠性.

约束可以是列级或表级. 列级约束仅适用于列, 表级约束应用到整个表.

常用的约束如下:

约束 说明
NOT NULL 该列不能有NULL值
DEFAULT 该列没指定值时, 为该列提供默认值
UNIQUE 该列所值都是不同的
PRIMARY KEY 唯一标识数据库表中的各记录
CHECK 确保某列中所有值满足一定条件

8.2.1 not null

默认情况:列可以保存null值, 使用not null约束后, 该列不允许null值.
null不同于没有数据, null代表未知的数据.

create table compary(
    id int primary key not null
);

8.2.2 default约束

如果在insert into语句中没有提供特定值, default约束为该列提供一个默认值

create table compary(
    id int primary key not null,
    salary real default 50000.0 --指定默认值
);

8.2.3 unique约束

防止在一个特定的列存在相同的值.
如果某列在其它表中被设置为foreign key, 则该列必须设置为primary key或者unique, 见9.1 foreign key.

create table compary(
    id int primary key not null,
    name text not null unique,  --设置唯一性
    salary real default 50000.0 
);

8.2.4 primary key

primary key唯一标识数据库表中的每个记录.
一个表可以有多个unique列, 但只能有一个primary key.
primary key是唯一的ID.
可以使用primary key来引用表中的行.
可以把primary key设置为其它表的外键, 以此来创建表之间的关系.
SQLite中primary key可以是null(自动递增autoincrement?).

create table compary(
    id int primary key autoincrement, --id设置为primary key, 如果insert值为null时, 则自动递增.
    name text not null unique,
    salary real default 50000.0 
);

8.2.5 check约束

check约束检查值的条件, 如果条件值为false, 则记录违反约束, 不能输入到表.

create table company(
  id integer primary key autoincrement, --int类型不能AUTOINCREMENT, AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY.
  salary real CHECK(salary>0)
);

insert into company values(null, 0); --报错, Error: CHECK constraint failed: company

8.2.6 删除约束

SQLite支持ALTER TABLE的有限子集(见8.7节).
在SQLite中, ALTER TABLE命令允许用户重命名表, 或向现有表中添加一个新的列.
但以下操作不被允许: 重命名列, 删除一列, 给一个表添加约束, 给一个表删除约束.

8.3 Join

Join子句用于结合两个或多个表的记录.
Join通过共同值来结合表中的字段.
三种主要类型的连接:Cross join(交叉连接)/Inner join(内连接)/Outer join(外连接)
其中inner join是默认的连接方式;

以如下表进行说明:
表定义

create table grade(  
    gradeid  text not null primary key,  
    name     text not null  
);  
create table class(  
    classid  text not null primary key,  
    name     text not null,  
    gradeid  text references grade(gradeid) ON UPDATE CASCADE  
);  

表赋值:

--grade 1, 2  
INSERT INTO grade VALUES("1", "grade_1");  
INSERT INTO grade VALUES("2", "grade_2");  
  
--class 1-1, 1-2, 2-1, 2-2  
INSERT INTO class VALUES("1_1", "class_1_1", "1");  
INSERT INTO class VALUES("1_2", "class_1_2", "1");  
INSERT INTO class VALUES("2_1", "class_2_1", "2");  
INSERT INTO class VALUES("2_2", "class_2_2", "2");  

查看表:

sqlite> select * from grade;  
gradeid     name  
----------  ----------  
1           grade_1  
2           grade_2  
sqlite>  
sqlite> select * from class;  
classid     name        gradeid  
----------  ----------  ----------  
1_1         class_1_1   1  
1_2         class_1_2   1  
2_1         class_2_1   2  
2_2         class_2_2   2  

8.3.1 Cross Join

语法:SELECT * FROM table1 CROSS JOIN table2 [CROSS JOIN table3 …]
作用:把第一个表的每一行与第二个表的每一行进行连接.
1) 第一个表的第一行 与 第二个表的每一行进行连接.
2) 第一个表的第二行 与 第二个表的每一行进行连接.
...
n) 第一个表的第n行 与 第二个表的每一行进行连接.
相当于两层的循环遍历.

例:
grade表:2行, 2列
class表:4行, 3列

SELECT * FROM grade CROSS JOIN class
生成一个2*4行, 2+3列的表
由于结果集巨大, 所以比较少用(几乎不用)

sqlite> select * from grade cross join class;  
gradeid     name        classid     name        gradeid  
----------  ----------  ----------  ----------  ----------  
1           grade_1     1_1         class_1_1   1  
1           grade_1     1_2         class_1_2   1  
1           grade_1     2_1         class_2_1   2  
1           grade_1     2_2         class_2_2   2  
2           grade_2     1_1         class_1_1   1  
2           grade_2     1_2         class_1_2   1  
2           grade_2     2_1         class_2_1   2  
2           grade_2     2_2         class_2_2   2  

8.3.2 Inner Join

作用:
类似Cross Join, 但需要满足一定条件才会连接, 如果不加约束条件, 则结果跟cross join一样.
返回的行数在0~n*m之间, 列数不超过x+y列.

语法:

SELECT * FROM table1 [INNER] JOIN table2 ON condition;
SELECT * FROM table1 [INNER] JOIN table2 USING(column1, …);
SELECT * FROM table1 NATURAL JOIN table2 …

有3种方法指定InnerJoin的判断条件:

方法 优点 缺点
on表达式 1. 语句长, 2. 存在重复列
using表达式 返回的结果集中无重复字段 每个字段必须存在于各个表中: USING(gradeid)要求table1和table2中都有gradeid列
natural join sql自动检测表中每一列是否匹配, 即使表结构发生变化, 也不用修改SQL语句, 可以自动适应变化 同上, 要求被连接的表中有相同的列名. 与USING不同的是, NATURAL JOIN自动匹配这些列, 不需要用户指定.

使用ON CONDITION

sqlite> select * from grade join class on grade.gradeid=class.gradeid;
gradeid     name        classid     name        gradeid  
----------  ----------  ----------  ----------  ----------  
1           grade_1     1_1         class_1_1   1  
1           grade_1     1_2         class_1_2   1  
2           grade_2     2_1         class_2_1   2  
2           grade_2     2_2         class_2_2   2  

使用USING:using(gradeid)返回的结果集中, gradeid只出现了一次

sqlite> select * from grade inner join class using(gradeid);  
gradeid     name        classid     name  
----------  ----------  ----------  ----------  
1           grade_1     1_1         class_1_1  
1           grade_1     1_2         class_1_2  
2           grade_2     2_1         class_2_1  
2           grade_2     2_2         class_2_2  

使用NATURAL JOIN:没有成功, 原因不明.

8.3.3 Outer Join

作用:
sqlit3中outer join与inner join类似, 需要ON/USING的约束条件, 否则返回CROSS JOIN的结果.
与INNER JOIN不同的是:如果存在不满足条件的行, 将保留左边表格的行, 右边表格的行忽略, 这就是LEFT OUTER JOIN.
sqlite3只支持LEFT OUTER JOIN, 不支持RIGHT OUTER JOIN和FULL OUTER JOIN.

语法:

SELECT * FROM table1 LEFT OUTER JOIN table2 ON condition;
SELECT * FROM table1 LEFT OUTER JOIN table2 USING(column1, …);

(此处有一个图...)

例1:由于grade.gradeid在class中都能找到匹配的数据行, 所以返回的结果与inner join相同.

sqlite> select * from grade left outer join class on grade.gradeid=class.gradeid;  
gradeid     name        classid     name        gradeid  
----------  ----------  ----------  ----------  ----------  
1           grade_1     1_1         class_1_1   1  
1           grade_1     1_2         class_1_2   1  
2           grade_2     2_1         class_2_1   2  
2           grade_2     2_2         class_2_2   2  

例2:给grade表中添加一个新的grade数据, 没有class与之对应, 则outer join后, 这个新grade对应的class列为空.

sqlite> INSERT INTO grade VALUES("3", "grade_3");  
sqlite> SELECT * FROM grade LEFT OUTER JOIN class USING(gradeid);  
gradeid     name        classid     name  
----------  ----------  ----------  ----------  
1           grade_1     1_1         class_1_1  
1           grade_1     1_2         class_1_2  
2           grade_2     2_1         class_2_1  
2           grade_2     2_2         class_2_2  
3           grade_3  

8.4 别名

作用: 可以暂时把表或列重命名为另一个名字, 这被称为别名. 重命名是临时的改名, 数据库中实际名称不会改变.

语法:
表别名:SELECT t0.c0, t0.c1, t1.c0, t1.c1 FROM table0 AS t0, table1 AS t1 WHERE t0.id=t1.eid;
列别名:SELECT t0.c0 as t0c0 FROM table0 as t0;

例, 将表grade别名为g, class别名为c, 方便书写.

sqlite> select g.gradeid, g.name, c.name from grade as g, class as c where g.gradeid=c.gradeid;  
gradeid     name        name  
----------  ----------  ----------  
1           grade_1     class_1_1  
1           grade_1     class_1_2  
2           grade_2     class_2_1  
2           grade_2     class_2_2  

上例的结果集中有个问题, 有两列name, g.name和c.name都是name, 这时可以用列别名

例:

sqlite> SELECT g.gradeid, g.name AS gname, c.name AS cname FROM grade AS g, class AS c WHERE g.gradeid=c.gradeid;  
gradeid     gname       cname  
----------  ----------  ----------  
1           grade_1     class_1_1  
1           grade_1     class_1_2  
2           grade_2     class_2_1  
2           grade_2     class_2_2  
sqlite>  

8.5 触发器

SQLite触发器(Trigger)是数据库的回调函数, 会在指定的数据库事件发生时自动执行/调用.

SQLite触发器的要点如下:

  1. SQLite Trigger触发条件:
    1. 可以指定在特定的表发生改变(delete, insert, update)时触发,
    2. 也可以在指定表的(一个或多个)列发生更新时触发.
  2. SQLite只支持FOR EACH ROW Trigger, 不支持For each statement trigger. 所以不用明确指定for each row trigger.
    for each row trigger的意思是: 操作语句每修改一行, 就触发一次, 比如删除10行数据变触发10次.
    for each statement trigger的意思是: 一条操作语句只触发一次.
  3. 如果有WHERE子句, 则只针对WHERE子句为真的行执行函数, 如果没有WHERE子句, 则对所有行执行函数.
  4. BEFORE和AFTER关键字决定何时执行触发动作(在关联行被修改的之前或者之后执行触发器动作).
  5. 当Trigger相关联的表被删除时, Trigger也自动被删除.
  6. 被修改的表必须在同一数据库中, Trigger附加的表必须使用tablename, 不能使用database.tablename.
  7. RAISE()可用于在Trigger程序内抛出异常.

8.5.1 创建trigger

语法:

CREATE TRIGGER trigger_name [BEFORE|AFTER] event_name ON table-name
BEGIN
    --触发器逻辑--
END;

其中event_name可以是在table_name上的insert/delete/update操作, 比如

CREATE TRIGGER trigger_name [BEFORE|AFTER] UPDATE OF column_name ON table-name
BEGIN
    --触发器逻辑--
END;

例1:

sqlite> CREATE TABLE grade(  
   ...>     gradeid  text not null primary key,  
   ...>     name     text not null  
   ...> );  
sqlite>   
sqlite> CREATE TABLE recorder(  
   ...>     id         integer primary key autoincrement,--自增ID  
   ...>     entry_date text    not null  
   ...> );  
sqlite>   
sqlite> CREATE TRIGGER recorder_log AFTER insert ON grade  
   ...> BEGIN  
   ...>     insert into recorder values(NULL, datetime('now'));  
   ...> END;  
sqlite>   
sqlite> INSERT INTO grade VALUES("4", "grade_4");  
sqlite> INSERT INTO grade VALUES("5", "grade_5");  
  
sqlite> SELECT * FROM recorder;  
id          entry_date  
----------  -------------------  
1           2020-06-04 07:11:48  
2           2020-06-04 07:12:09  
sqlite>  

8.5.2 查看trigger

sqlite> --查看所有trigger  
sqlite> select name from sqlite_master where type='trigger';  
name  
------------  
recorder_log  
sqlite>   
sqlite> --查看某个表上的trigger  
sqlite> select name from sqlite_master where type='trigger' and tbl_name='grade';  
name  
------------  
recorder_log  
sqlite>   
sqlite> --查看某个表上的trigger  
sqlite> select name from sqlite_master where type='trigger' and tbl_name='class';  
sqlite>  

8.5.3 删除trigger

语法

DROP TRIGGER trigger_name;

例子:

DROP TRIGGER recorder_log;

8.6 索引Index

8.6.1 定义

作用:
索引是一种特殊的查找表, 数据库搜索引擎用它来加快数据检索速度.
索引是一个指向表中数据的指针. 数据库中的索引类似于一本书的目录.
索引有助于加快SELECT查询WHERE子句, 但会减慢UPDATE和INSERT语句.
索引可以创建或删除, 对索引的操作不会影响数据.

语法:

CREATE INDEX index_name ON table_name(column_name); --创建索引
DROP INDEX index_name; --删除索引

注意以下情况避免使用索引

  1. 索引不应该使用在较小的表上.
  2. 索引不应该使用在有频繁大批量修改操作(更新/插入)的表上.
  3. 索引不应该使用在含有大量NULL值的列上.
  4. 索引不应该使用在频繁操作的列上.

8.6.2 四种索引

名称 说明 语法
单列索引 基于表的一个列创建的索引 CREATE INDEX index_name ON table_name(column_name);
唯一索引 唯一索引不允许任何重复的值插入到表中 CREATE UNIQUE INDEX index_name ON table_name(column_name);
组合索引 基于表中的两个或多个列上创建的索引 CREATE INDEX index_name ON table_name(column1, column2);
隐式索引 创建对象时, 数据库服务器自动创建的索引, 索引自动创建为主键约束和唯一约束 ....

8.6.3 查看索引:

sqlite> .indices grade   --列出grade表上所有可用的索引
sqlite_autoindex_grade_1 --这个是创建表时创建的隐式索引
sqlite>
sqlite> create index gidx on grade(name); --创建一个新索引
sqlite> .indices grade   --再次查看表上的索引
gidx                     --这是新创建的索引
sqlite_autoindex_grade_1 --这是隐式索引
sqlite>
sqlite> select * from sqlite_master where type='index'; --查看数据库范围的所有索引.
type        name                      tbl_name    rootpage    sql
----------  ------------------------  ----------  ----------  ----------
index       sqlite_autoindex_grade_1  grade       5
index       sqlite_autoindex_class_1  class       7
index       gidx                      grade       9           CREATE IND
sqlite>

8.6.4 子句INDEXED BY

说明:
子句"INDEXED BY index_name;"规定必须使用命名的索引来查找对应表中的值.
如果index_name不存在或不能用于查询, SQLite语句会失败.

语法:

SELECT|DELETE|UPDATE column1, column2...
INDEXED BY (index_name)
table_name
WHERE (CONDITION);

举例:

sqlite> create index gidx on grade(name);
sqlite>
sqlite> select * from grade;
gradeid     name
----------  ----------
1           grade_1
2           grade_2
4           grade_4
5           grade_5
sqlite>
sqlite> select * from grade INDEXED BY gidx WHERE name='grade_2'; --使用indexed by, where中使用索引对应的列, 可以获取数据.
gradeid     name
----------  ----------
2           grade_2
sqlite>
sqlite> select * from grade INDEXED BY gidx WHERE gradeid>2; --使用indexed by, 但where中使用非gidx索引的列, 不能获取数据
Error: no query solution
sqlite> select * from grade WHERE gradeid>2; --不使用indexed by, 能获取数据
gradeid     name
----------  ----------
4           grade_4
5           grade_5

8.7 Alter命令

作用: ALTER TABLE命令, 在不执行完整的转储和数据重载的情况下, 用来修改已有的表.

语法, 支持两种修改:

ALTER TABLE database_name.table_name RENAME TO new_table_name; --重命名已有的表
ALTER TABLE database_name.table_name ADD COLUMN column_def …; --已有的表中添加列
                                                               --注意, 新添加的列以null来填充.
sqlite> select * from grade;  
gradeid     name  
----------  ----------  
1           grade_1  
2           grade_2  
3           grade_3  
4           grade_4  
5           grade_5  
  
sqlite> --将表grade改名为new_grade  
sqlite> ALTER TABLE grade RENAME TO new_grade;  
sqlite> select * from grade;  
Error: no such table: grade  
sqlite> select * from new_grade;  
gradeid     name  
----------  ----------  
1           grade_1  
2           grade_2  
3           grade_3  
4           grade_4  
5           grade_5  
  
sqlite> --给new_grade中添加一列  
sqlite> ALTER TABLE new_grade ADD COLUMN schoolid text;  
sqlite> select * from new_grade;  
gradeid     name        schoolid  
----------  ----------  ----------  
1           grade_1                 --注意, 新添加的列以null来填充.
2           grade_2  
3           grade_3  
4           grade_4  
5           grade_5  
sqlite>  

8.8 清空表数据

SQLite中没有Truncate table命令, 但可以使用delete命令将表中的数据全部删除.

DELETE FROM table_name --这种方法不能将递增数归零
DELETE FROM sqlite_sequence WHERE name='table_name' --可以将递增数归零. 

8.9 视图View

View是一种虚表, 是通过相关的名称存储在数据库中的SQLite语句(以预定义的SQLite查询形式存在的表的组合).

View是只读的, 不能在View上执行delete/insert/update语句.
可以在View上创建触发器, 当尝试delete/insert/update View时触发.

作用:

  1. 用户/用户组 查找结构数据的方式更直观;
  2. 限制数据访问, 用户只能看到有限的数据, 而不是完整的表;
  3. 汇总多个表中的数据, 用于生成报告;

创建View:
使用CREATE VIEW语句创建, view可以从单一的表创建, 也可以从多个表创建, 也可以从其它view创建.

CREATE [TEMP|TEMPORARY] VIEW view_name AS
SELECT column1, column2, …
FROM table_name
[WHERE condition];

删除View:

DROP VIEW view_name;

例子:

--全体数据
sqlite> select * from class;
classid     name        gradeid
----------  ----------  ----------
1_1         class_1_1   1
1_2         class_1_2   1
2_1         class_2_1   2
2_2         class_2_2   2
sqlite>
sqlite> --创建view
sqlite> create view cls_view as select name, gradeid from class where gradeid=2;
sqlite>
sqlite> --查询view
sqlite> select * from cls_view;
name        gradeid
----------  ----------
class_2_1   2
class_2_2   2
sqlite>
sqlite> drop view cls_view;
sqlite>

8.10 事务Transaction

8.10.1 说明

事务是一个对数据库执行的工作单元.
事务是以逻辑顺序完成的"工作单位或序列", 可以由用户手工操作完成, 也可以由数据库程序自动完成.
事务是指一个或多个更改数据库的扩展.

例如: 以下两个操作就是在表上执行事务: 创建记录, 从表中删除记录.

重要的是要控制事务, 以确保数据的完整性和处理数据库错误.
可以把请多的SQLite查询联合成一组, 把所有这些放在一起作为事务的一部分进行执行.

8.10.2 事务的属性

事务有四个标准属性, 根据首字母缩写为ACID.

  1. 原子性(Atomicity): 确保工作单位内的所有操作都成功完成, 否则事务会在出现故障时终止, 之前的操作也会回滚到以前的状态.
  2. 一致性(Consistency): 确保数据库在成功提交的事务上正确地改变状态.
  3. 隔离性(Isolation): 使事务操作相互独立和透明.
  4. 持久性(Durability): 确保已提交事务的结果或效果在系统发生故障的情况下仍然存在.

8.10.3 事务控制

使用下面的命令来控制事务

  1. BEGIN TRANSACTION: 开始处理事务.
  2. COMMIT: 保存更改, 或者可以使用END TRANSACTION命令.
  3. ROLLBACK: 回滚所做的更改.

事务控制命令只与DML命令(INSERT, UPDATE, DELETE)一起使用. 他们不能在创建表或删除表时使用, 因为这些操作在数据库中是自动提交的.

8.10.3 BEGIN TRANSACTION命令

可以使用BEGIN TRANSACTION(或BEGIN)命令来启动事务, 然后事务会持续执行下去, 直到遇到下一个COMMIT或ROLLBACK命令.
不过在数据库关闭或发生错误时, 事务处理也会回滚.
语法:

BEGIN;
--or
BEGIN TRANSACTION;

8.10.4 COMMIT命令

作用: 把事务调用的更改保存到数据库中. 该命令把自上次COMMIT或ROLLBACK命令以来的所有事务保存到数据库.
语法:

COMMIT;
--or
END TRANSACTION;

8.10.4 ROLLBACK命令

作用: 用于撤消尚未保存到数据库的事务. 只能撤消自上次发出COMMIT或ROLLBACK命令以来的事务.
语法:

ROLLBACK;

例子:

sqlite> --全体数据
sqlite> select * from class;
classid     name        gradeid
----------  ----------  ----------
1_1         class_1_1   1
1_2         class_1_2   1
2_1         class_2_1   2
2_2         class_2_2   2
sqlite> 
sqlite> --一个事务, DELETE后回滚
sqlite> BEGIN;
sqlite> delete from class where classid='2_1';
sqlite> select * from class; --delete后, 显示数据被删除
classid     name        gradeid
----------  ----------  ----------
1_1         class_1_1   1
1_2         class_1_2   1
2_2         class_2_2   2
sqlite> ROLLBACK;  --rollback后, 被删除的数据又回来了.
sqlite> select * from class;
classid     name        gradeid
----------  ----------  ----------
1_1         class_1_1   1
1_2         class_1_2   1
2_1         class_2_1   2
2_2         class_2_2   2
sqlite>
sqlite> --another transaction, 删除数据后提交
sqlite> BEGIN;
sqlite> DELETE FROM class WHERE classid='2_1';
sqlite> COMMIT; --提交
sqlite> SELECT * FROM class; --COMMIT后, 数据真被删除了.
classid     name        gradeid
----------  ----------  ----------
1_1         class_1_1   1
1_2         class_1_2   1
2_2         class_2_2   2
sqlite>

8.11 子查询

8.11.1 说明

子查询又叫内部查询/嵌套查询, 指的是在SQLite查询的WHERE子句中嵌入查询语句.
也就是说: 一个SELECT语句的查询结果可以作为另一个语句的输入值.

子查询可以与SELECT, INSERT, UPDATE, DELETE语句一起使用.
可伴随使用运算符: =, <, <=, >, >=, IN, BETWEEN, 等.

子查询要遵守的规则:

  1. 子查询要用括号括起来;
  2. 子查询在SELECT子句中只能在一个列, 除非在主查询中有多列, 与子查询的所选列进行比较.
  3. ORDER BY 不能用在子查询中, 虽然主查询可以使用 ORDER BY. 可以在子查询中使用 GROUP BY, 功能与 ORDER BY 相同
  4. 子查询返回多于一行, 只能与多值运算符一起使用, 如 IN 运算符;
  5. BETWEEN 运算符不能与子查询一起使用, 但是, BETWEEN 可在子查询内使用.

8.11.2 SELECT语句中的子查询使用:

语法:

SELECT column0[, column1, …]
FROM table1[, table2, …]
WHERE column_name OPERATOR
    (SELECT column0[, column1, …]
    FROM table1[, table2, …]
    [WHERE]
    );

例:

sqlite> create table student(  
   ...>     id   int not null,  
   ...>     name text not null,  
   ...>     score int not null  
   ...> );  
sqlite> insert into student values(1, 'Name1', 80);  
sqlite> insert into student values(2, 'Name2', 90);  
sqlite> insert into student values(3, 'Name3', 85);  
sqlite> insert into student values(4, 'Name4', 65);  
  
sqlite> --查找最高分数  
sqlite> select max(score) from student;  
max(score)  
----------  
90  
  
sqlite> --查找最高分数对应学生的信息  
sqlite> select * from student where score=(select max(score) from student);  --使用子查询
id          name        score  
----------  ----------  ----------  
2           Name2       90  
sqlite>  
sqlite> --等价于以下语句
sqlite> select id, name, max(score) from student;
id          name        max(score)
----------  ----------  ----------
2           Name2       90
sqlite>  

8.11.2 INSERT语句中的子查询使用:

语法

INSERT INTO table_name [(column1[, column2, …])]
    SELECT [*|column1[, column2, …]]
    FROM table1[, table2]
    [WHERE VALUE OPERATOR];

例子

sqlite> --student表中的全体数据
sqlite> select * from student;
id          name        score
----------  ----------  ----------
1           Name1       80
2           Name2       90
3           Name3       85
4           Name4       65
sqlite>
sqlite> 创建一个与student数据结构相同的表student_new
sqlite> create table student_new(
   ...>   id int not null,
   ...>   name text not null,
   ...>   score int not null
   ...> );
sqlite>
sqlite> --把分数大于85的数据 从student插入到student_new.
sqlite> insert into student_new select * from student where id in(select id from student where score>=85);
sqlite> select * from student_new;
id          name        score
----------  ----------  ----------
2           Name2       90
3           Name3       85
sqlite>
sqlite> --感觉跟如下语句没差别啊, 为什么要像上条insert语句写那么长???
sqlite> insert into student_new select * from student where score>=85;
sqlite> select * from student_new;
id          name        score
----------  ----------  ----------
2           Name2       90
3           Name3       85
2           Name2       90
3           Name3       85
sqlite>

8.11.3 UPDATE语句中的子查询使用:

语法

UPDATE table_name SET column1=new_value
[WHERE OPERATOR [ VALUE]];
    (SELECT column_name
    FROM table_name
    [WHERE]);

例子

sqlite> --原始数据
sqlite> select * from student;
id          name        score
----------  ----------  ----------
1           Name1       80
2           Name2       90
3           Name3       85
4           Name4       65
sqlite> --把特定学生(另一个表格中存在的且分数>=85的学生)的分数减半
sqlite> update student set score=score*0.5 where id in(select id from student_new where score>=85);
sqlite> select * from student;
id          name        score
----------  ----------  ----------
1           Name1       80
2           Name2       45
3           Name3       42.5
4           Name4       65
sqlite>

8.11.4 DELETE语句中的子查询使用:

语法

DELETE FROM table_name
[WHERE OPERATOR [ VALUE]];
    (SELECT column_name
    FROM table_name
    [WHERE]);

例子

sqlite> --原始数据
sqlite> select * from student;
id          name        score
----------  ----------  ----------
1           Name1       80
2           Name2       45
3           Name3       42.5
4           Name4       65
sqlite> 
sqlite> --把特定学生(另一个表格中存在的且分数>=85的学生)的记录删除
sqlite> delete from student where id in (select id from student_new where score>=85);
sqlite> select * from student;
id          name        score
----------  ----------  ----------
1           Name1       80
4           Name4       65
sqlite>

8.12 自动递增Autoincrement

AUTOINCREMENT是一个关键字, 作用于表中的某些列, 这些列的值自动递增.
AUTOINCREMENT只能用于整型(INTEGER)字段.

语法:

CREATE TABLE table_name(
column1 integer autoincrement, --必须是integer类型. 
column2 datatype,
…
);

每次向表中insert数据时, 不必为column1赋值, 它自动加1.

例子:

sqlite> --创建表格
sqlite> create table visitor(
   ...>   name text not null,
   ...>   id integer primary key autoincrement
   ...> );
sqlite> --插入数据, id给值null, 数据库自动为它赋递增的值
sqlite> insert into visitor values ('name0', null);
sqlite> insert into visitor values ('name1', null);
sqlite> insert into visitor values ('name2', null);
sqlite> insert into visitor values ('name3', null);
sqlite>
sqlite> select * from visitor;
name        id
----------  ----------
name0       1
name1       2
name2       3
name3       4
sqlite> --
sqlite> --删除数据, 并不会影响递增数据的值, 继续insert数据时, 递增列继续递增.
sqlite> delete from visitor where name='name1';
sqlite> select * from visitor;
name        id
----------  ----------
name0       1
name2       3 --删除id=2的记录, 后面的id不会改变.
name3       4 
sqlite> insert into visitor values ('name4', null);
sqlite> select * from visitor;
name        id
----------  ----------
name0       1
name2       3
name3       4
name4       5 --新增数据, id在4基础上继续增加.
sqlite>

8.13 注入

如果您的站点允许用户通过网页输入, 并将输入内容插入到 SQLite 数据库中, 这个时候您就面临着一个被称为 SQL 注入的安全问题.
需要防止这种情况发生, 确保脚本和SQLite语句的安全.

注入通常在请求用户输入时发生, 比如需要用户输入姓名, 但用户却输入了一个 SQLite 语句, 而这语句就会在不知不觉中在数据库上运行.

8.14 解释Explain

在使用SQLite语句之前, 可以使用"EXPLAIN"关键字或者"EXPLAIN QUERY PLAN"短语, 用于描述表的细节.
如果省略了EXPLAIN关键字或者短语, 任何修改都会引起SQLite语句的查询行为. 并返回有关SQLite语句如何操作的信息.

注意:

  1. 来自EXPLAIN和EXPLAIN QUERY PLAN的输出只用于交互式分析和排除故障.
  2. 输出格式的细节可能会随着SQLite版本的不同而有变化.
  3. 应用程序不应该使用EXPLAIN或EXPLAIN QUERY PLAN, 因为其确切的行为是可变的且只有部分会被记录.

语法:

EXPLAIN [SQLite Query]
EXPLAIN QUERY PLAN [SQLite Query]

例子:

sqlite> --全体数据
sqlite> select * from class;
classid     name        gradeid
----------  ----------  ----------
1_1         class_1_1   1
1_2         class_1_2   1
2_2         class_2_2   2
sqlite> 
sqlite> --使用explain
sqlite> explain select * from class;
addr  opcode         p1    p2    p3    p4             p5  comment
----  -------------  ----  ----  ----  -------------  --  -------------
0     Init           0     9     0                    00  Start at 9
1     OpenRead       0     6     0     3              00  root=6 iDb=0; class
2     Rewind         0     8     0                    00
3       Column         0     0     1                    00  r[1]=class.classid
4       Column         0     1     2                    00  r[2]=class.name
5       Column         0     2     3                    00  r[3]=class.gradeid
6       ResultRow      1     3     0                    00  output=r[1..3]
7     Next           0     3     0                    01
8     Halt           0     0     0                    00
9     Transaction    0     0     15    0              01  usesStmtJournal=0
10    Goto           0     1     0                    00
sqlite> 
sqlite> --使用explain query plan
sqlite> explain query plan select * from class;
QUERY PLAN
`--SCAN TABLE class
sqlite> 
sqlite> --使用explain query plan
sqlite> explain query plan select * from class where classid='1_2';
QUERY PLAN
`--SEARCH TABLE class USING INDEX sqlite_autoindex_class_1 (classid=?)
sqlite>

8.15 Vacuum

操作: VACUUM命令通过复制主数据库中的内容到一个临时数据库文件, 然后清空主数据库, 并从副本中重新载入原始的数据库文件.
作用: 消除空闲页, 把表中的数据排列为连续的, 另外会清理数据库文件结构.

如果表中没有明确的整型主键(INTEGER PRIMARY KEY), VACUUM命令可能会改变表中条目的行ID(ROWID).
VACUUM命令只适用于主数据库, 附加的数据库文件是不可能使用VACUUM命令.
如果有一个活动的事务, VACUUM命令会失败.
VACUUM命令是一个用于内存数据库的任何操作.
由于VACUUM命令从头开始重新创建数据库文件, 所以VACUUM也可以用于修改许多数据库特定的配置参数.

8.15.1 手动VACUUM

$ sqlite3 database_name "VACUUM;" # 在命令行对整个数据库发出VACUUM命令的语法
sqlite> VACUUM; --在SQLite提示符中运行VACUUM.
sqlite> VACUUM table_name; --在特定表中运行VACUUM.

8.15.1 自动VACUUM(Auto-VACUUM)

操作: SQLite的auto-VACUUM与VACUUM不大一样, 它只是把空闲页移到数据库末尾, 从而减小数据库大小.
作用: 通过这样做, 它可以明显地把数据库碎片化, 而VACUUM则是反碎片化. 所以Auto-VACUUM只会让数据库更小.

在SQLite的提示符中, 可以通过下面的编译运行, 启用/禁止SQLite的Auto-VACUUM:

sqlite> PRAGMA auto_vacuum = NONE       ; -- 0, means disable auto vacuum
sqlite> PRAGMA auto_vacuum = INCREMENTAL; -- 1, means enable incremental vacuum
sqlite> PRAGMA auto_vacuum = FULL       ; -- 2, means enable auto vacuum

也可以从命令行中运行命令来检查auto-vacuum设置:

$ sqlite3 database_name "PRAGMA auto_vacuum;"

8.16 日期时间

8.16.1 说明

SQLite支持以下5个日期和时间函数:

序号 函数 说明
1 date(timestring, modifier, modifier, ...) 以YYYY-MM-DD格式返回日期.
2 time(timestring, modifier, modifier, ...) 以HH:MM:SS格式返回时间.
3 datetime(timestring, modifier, modifier, ...) 以YYYY-MM-DD HH:MM:SS格式返回.
4 julianday(timestring, modifier, modifier, ...) 返回从格林尼治时间的公元前4714年11月24日正午算起的天数.
5 strtime(format, timestring, modifier, modifier, ...) 根据第一个参数指定的格式字符串返回格式化的日期.

8.16.2 时间字符串timestring

timestring可以是采用下面任何一种格式

序号 timestring 例子
1 YYYY-MM-DD 2010-12-30
2 YYYY-MM-DD HH:MM 2010-12-30 12:10
3 YYYY-MM-DD HH:MM:SS.SSS 2010-12-30 12:10:04.100
4 MM-DD-YYYY HH:MM 12-30-2010 12:10
5 HH:MM 12:10
6 YYYY-MM-DDTHH:MM 2010-12-30 12:10
7 HH:MM:SS 12:10:04
8 YYYYMMDD HHMMSS 20101230 1210
9 now 2013-05-07

可以使用"T"作为分隔日期和时间的文字字符.

8.16.3 修饰符Modifier

timestring后边可以跟着0个或多个修饰符, 这将改变由上述一个函数返回的日期和时间.
修饰符应从左到右使用.
可在SQLite中使用的修饰符:

序号 modifier 说明
1 NNN days .
2 NNN hours .
3 NNN minutes .
4 NNN .NNNN seconds .
5 NNN months .
6 NNN years .
7 start of month .
8 start of year .
9 start of day .
10 weekday N .
11 unixpoch .
12 localtime .
13 utc .

8.16.4 格式化

SQLite提供了函数strftime()来格式化任何日期和时间.

序号 格式 说明
1 %d 一月中的第几天, 01~31
2 %f 带小数部分的秒,SS.SSS
3 %H 小时, 00~23
4 %j 一年中的第几天,001-366
5 %J 儒略日数,DDDD.DDDD
6 %m 月, 00~12
7 %M 分, 00~59
8 %s 从 1970-01-01 算起的秒数
9 %S 秒, 00~59
10 %w 一周中的第几天,0-6 (0 is Sunday)
11 %W 一年中的第几周,01-53
12 %Y 年, YYYY
13 %% %, 字符本身

8.16.5 例子

sqlite> select date('now'); --当前日期
date('now')
-----------
2022-09-19
sqlite>
sqlite> select date('now', 'start of month', '+1 month', '-1 day'); --当前月份的最后一天
date('now', 'start of month', '+1 month', '-1 day')
---------------------------------------------------
2022-09-30
sqlite>
sqlite> select datetime(1092941466, 'unixepoch'); --时间戳对应的日期和时间
datetime(1092941466, 'unixepoch')
---------------------------------
2004-08-19 18:51:06
sqlite> select datetime(1092941466, 'unixepoch', 'localtime'); --时间戳对应的本地时区的日期和时间
datetime(1092941466, 'unixepoch', 'localtime')
----------------------------------------------
2004-08-20 02:51:06
sqlite>
sqlite> select strftime('%s', 'now'); --返回当前时间的时间戳.
strftime('%s', 'now')
---------------------
1663572322
sqlite>
sqlite> select julianday('now') - julianday('2022-01-01'); -- 某日期到现在的天数.
julianday('now') - julianday('2022-01-01')
------------------------------------------
261.310867708176
sqlite>
sqlite> select strftime('%s', 'now') - strftime('%s', '2022-01-01 00:00:00'); --某日期时间到现在的秒数.
strftime('%s', 'now') - strftime('%s', '2022-01-01 00:00:00')
-------------------------------------------------------------
22577433
sqlite>
sqlite> select date('now', 'start of year', '+9 months', 'weekday 2'); --当年10月第1个星期二的日期
date('now', 'start of year', '+9 months', 'weekday 2')
------------------------------------------------------
2022-10-04
sqlite>
sqlite> select (julianday('now') - 2440587.5) * 86400.0; --从Unix纪元算起的时间(以秒为单位), 类似于strftime('%s', 'now'), 不同的是这里包括小数部分.
(julianday('now') - 2440587.5) * 86400.0
----------------------------------------
1663572897.68002
sqlite>
sqlite> select time('12:00', 'localtime'); -- utc->本地时间 转换.
time('12:00', 'localtime')
--------------------------
20:00:00
sqlite> select time('12:00', 'utc'); -- 本地时间->utc 转换.
time('12:00', 'utc')
--------------------
04:00:00
sqlite>
sqlite>

8.17 常用函数

函数 作用 null
COUNT 聚集函数, 计算数据库表中行数 -
MAX 聚合函数, 选择某列的最大值 -
MIN 聚合函数, 选择某列的最小值 -
AVG 聚合函数, 计算某列的平均值 -
SUM 聚合函数, 为一个数值列计算总合 -
RANDOM 返回介于(-9223372036854775808, +9223372036854775807)之间的伪随机数 -
ABS 返回数值参数的绝对值 -
UPPER 把字符串转为大写字母 -
LOWER 把字符串转为小写字母 -
LENGTH 返回字符串长度 -
sqlite_version 返回SQLite库的版本 -

例子:

sqlite> select * from grade;
gradeid     name
----------  ----------
1           grade_1
2           grade_2
4           grade_4
5           grade_5
sqlite> select count(*) from grade;
count(*)
----------
4
sqlite> select max(gradeid) from grade;
max(gradeid)
------------
5
sqlite> select min(gradeid) from grade;
min(gradeid)
------------
1
sqlite>
sqlite> select avg(gradeid) from grade;
avg(gradeid)
------------
3.0
sqlite>
sqlite> select sum(gradeid) from grade;
sum(gradeid)
------------
12
sqlite>
sqlite> select random() as 'RDM';
RDM
--------------------
-4450169040852162096
sqlite>
sqlite> select abs(5), abs(-15), abs(NULL), abs(0), abs('ABC');
abs(5)      abs(-15)    abs(NULL)   abs(0)      abs('ABC')
----------  ----------  ----------  ----------  ----------
5           15                      0           0.0
sqlite>
sqlite> select upper(name) from grade;
upper(name)
-----------
GRADE_1
GRADE_2
GRADE_4
GRADE_5
sqlite>
sqlite> select name, length(name) from grade;
name        length(name)
----------  ------------
grade_1     7
grade_2     7
grade_4     7
grade_5     7
sqlite>
sqlite> select sqlite_version() as 'vsn';
vsn
----------
3.27.2
sqlite>

9 其它操作

9.1 foreign key(外键)

SQLite从3.6.19开始支持foreign key约束.
以下例子说明foreign key的用法

--foreign key默认关闭, 需要打开
sqlite> PRAGMA foreign_keys;
0
sqlite> PRAGMA foreign_keys=ON;
sqlite> PRAGMA foreign_keys;
1


--先定义两个没有foreign key的表:
create table users(
    id 	 integer primary key autoincrement,
    name text    not null    unique   -- foreign key must be unique
);

create table projects(
    id 	 integer primary key autoincrement,
    proj text    not null    unique   -- foreign key must be unique
);

--接下来定义一个table, 包含两个foreign key,
create table works(
    id   integer primary key autoincrement,

    user_name text,
    proj_name text,

    --cascade表示对一个表的删除/修改会同步到其它表格
    foreign key(user_name) references users(name)    on delete cascade on update cascade,
    foreign key(proj_name) references projects(proj) on delete cascade on update cascade
);

--插入数据
insert into users(id, name) values(null, '张三');
insert into users(id, name) values(null, '李四');

insert into projects(id, proj) values(null, 'Project1');
insert into projects(id, proj) values(null, 'Project2');
insert into projects(id, proj) values(null, 'Project3');

insert into works(id, user_name, proj_name) values(null, '张三', 'Project1');
insert into works(id, user_name, proj_name) values(null, '张三', 'Project2');
insert into works(id, user_name, proj_name) values(null, '李四', 'Project2');
insert into works(id, user_name, proj_name) values(null, '李四', 'Project3');


sqlite> --查看
sqlite> .header on
sqlite> .mode column
sqlite> select * from works; --查看数据
id          user_name   proj_name
----------  ----------  ----------
1           张三          Project1
2           张三          Project2
3           李四          Project2
4           李四          Project3
sqlite>
sqlite> select * from projects;
id          proj
----------  ----------
1           Project1
2           Project2
3           Project3
sqlite>
sqlite> --Project2为Proj2.new
sqlite> update projects set proj='Proj2.new' where proj='Project2';
sqlite>
sqlite> select * from projects; --查看数据, projects表格中的Project2被修改了.
id          proj
----------  ----------
1           Project1
2           Proj2.new --projects表格数据修改成功.
3           Project3
sqlite>
sqlite> select * from works where proj_name like 'Proj%2%'; --查看数据, works表格中的Project2也被修改了.
id          user_name   proj_name
----------  ----------  ----------
2           张三          Proj2.new --Project2被修改为Proj2.new了
3           李四          Proj2.new --Project2被修改为Proj2.new了
sqlite>
sqlite> .q --退出

9.2 导入csv文件(.import)

10 SQLite接口

10.1 c/c++

10.2 Java

10.3 PHP

10.4 Perl

10.5 Python

posted @ 2021-12-02 13:51  编程驴子  阅读(239)  评论(0编辑  收藏  举报