本文讨论如何通过“键”关联数据表,并通过连接查询关联表的数据,还介绍了如何使用视图定义查询模板,以及如何将查询结果保存到数据表,并通过索引提高数据查询效率。
关系型数据库中,表之间的关系可以通过“键”定义,下面的代码将创建三个相互关联的数据表。
create table t10(f1 text not null unique,f2 integer); create table t11(f1 text not null references t10(f1),f2 text unique,f3 text); create table t12(f1 text not null references t11(f2),f2 text,f3 real ,f4 real);
代码中创建了三个数据表,可以当作超市用户与销售的极简模型。其中:
实际应用中,销售数据结构要复杂得多,如还需要商品信息表,库存数据等等。
下面的代码会在这三个表中添加一些数据。
insert into t10(f1,f2) values('user01',100), ('user02',100),('user03',100),('user04',100),('user05',100); insert into t11(f1,f2,f3) values('user01','s001','2026-09-01 15:30:35'), ('user03','s002','2026-09-01 15:33:15'), ('user03','s003','2026-09-01 15:39:29'), ('user05','s004','2026-09-01 15:45:55'), ('user05','s005','2026-09-01 16:01:16'); insert into t12(f1,f2,f3,f4) values('s001','m901',10,5), ('s001','m902',15,1),('s002','m995',6,9), ('s003','m911',3,15),('s003','m951',29,3), ('s003','m902',15,3),('s004','m930',5,2), ('s005','m915',9,1),('s005','m902',15,1);
执行语句后,t10、t11、t12表的数据如下图所示。
关联表时,主表中的关联字段一般是主键或唯一键,而子表中的关联字段则定义为外键,并指定引用的主表和字段。需要统一浏览关联表的数据时,可以使用连接查询。
执行连接查询时,需要明确连接的表和关联的字段,如下面的代码,首先对t10表和t11表进行连接查询。
select * from t10 join t11 on t10.f1=t11.f1;
查询结果如下图所示。
代码中,连接操作的语法为“<左表> join <右表> on <关联字段>”,本例,<左表>为t10,<右表>为t11,而<关联字段>则设置为两个表的f1字段,可以看到,查询结果中只包含f1字段在两个表中都存在的记录。如果需要显示完整的t10表(左表)信息,可以使用左连接(left join),如下面的代码。
select * from t10 left join t11 on t10.f1=t11.f1;
查询结果如下图所示,可以看到,在t11表中没有销售记录的user02和user04也会显示,只是在t11表中对应的字段数据会显示为空值(null)。
在“<左表> join <右表> on <关联字段>”语法中,如果在两个表中的关联字段名相同,也可以使用“<左表> join <右表> using(<关联字段>)”语法,如下面的代码。
select * from t10 join t11 using(f1);
查询结果如下图所示,可以看到,使用using()指定关联字段时,只会显示一次关联字段数据。
连接操作时,也可以通过表名或表的别名指定需要显示的字段,并可以设置字段别名,如下面的代码。
select X.f1 as 用户, X.f2 as 积分, Y.f2 as 单号, Y.f3 as 时间 from t10 as X join t11 as Y using(f1);
本例,首先将t10表别名设置为X,将t11表别名设置为X,然后通过X和Y指定显示的字段。查询结果如下图所示。
当查询语句越来越复杂时,可以将查询定义为视图(View),然后通过调用视图进一步查询数据;这里,视图可以看作是查询模板。
下面的代码,会将t10、t11、t12三个表的数据进行连接查询,并定义为v_user_sale视图。
create view v_user_sale as select X.f1 as 用户, X.f2 as 积分, Y.f2 as 单号, Y.f3 as 时间, Z.f2 as 商品代码, Z.f3 as 单价, Z.f4 as 数量, Z.f3*Z.f4 as 小计 from t10 as X left join t11 as Y using(f1) left join t12 as Z on Y.f2=Z.f1;
创建视图使用了“create view <视图名称> as <子查询>”语法。本例,在子查询中通过两次左连接(left join)将t10、t11、t12表进行关联,可以显示所有的用户及销售信息;此外,还通过t12表(Z表)的f3和f4字段相乘得到了每单中每种商品的金额“小计”。下面的代码,直接使用视图名称进行查询。
select * from v_user_sale;
通过视图进一步查询数据时,和查询表数据相同,可以设置查询条件,并进行排序、分组统计等操作。如下面的代码可以统计每位用户的消费金额合计。
select 用户,total(小计) as 消费合计 from v_user_sale group by 用户;
请注意,代码中计算合计时使用了total()函数,这样可以确保每位用户的“消费合计”都是数值,如user02和user04用户的消费合计为0.0,如果使用sum()函数,这两位用户的消费合计会显示为null。
如果不再需要某个视图,可以通过drop view语句删除,语法如下:
drop view <视图名称>
此外,视图只是查询模板,其数据并不是持久化的,每次调用时都会从真正的数据表中查询。如果需要保存视图查询数据,可以将其保存到数据表,这样就可以处理不同时间点或版本的视图数据,如统计汇总某个时间段的数据。下面的代码,可以将v_user_sale视图的查询结果保存到t_user_sale_1表中。
create table t_user_sale_1 as select * from v_user_sale;
对数据表的某一列添加索引,可以更加高效地处理此列数据,默认情况下,在显式定义为主键和唯一键的字段会自动添加索引。在sqlite_master系统表中,可以查询已存在的索引,如下面的代码。
select * from sqlite_master where type='index';
在sqlite_master表中,type字段为'index'值的即为已存在的索引。
前面将v_user_sale查询结果保存为t_user_sale_1表时,并没有指定索引字段,如果需要通过用户名分析数据,则可以在"用户"字段添加索引,如下面的代码。
create index ind_user_1 on t_user_sale_1(用户);
代码会在t_user_sale_1表的"用户"字段添加名为ind_user_1的索引。再次通过sqlite_master表查询索引结果如下图所示。
创建索引的语法如下:
create index <索引名> on <表名>(<字段名>)
删除索引的语法如下:
drop index <索引名>
如“drop index ind_user_1;”语句,可以删除刚刚创建的ind_user_1索引。
此外,表中的数据变动以后,还可以使用reindex语句重建数据索引,其中,可以通过表名重建指定数据表的全部索引,也可以通过索引名重建指定的数据索引,如下面的代码会创建ind_sale_1索引,并调用reindex语法重建数据索引,最后会统计各种商品的销售数量。
create index ind_sale_1 on t_user_sale_1(商品代码); reindex ind_sale_1; select 商品代码,total(数量) as 销售数量 from t_user_sale_1 group by 商品代码;
代码执行结果如下图所示。
请注意,查询结果中"商品代码"为空的记录是因为有用户没有消费记录,所有其记录中的商品代码为空;如果不需要显示"商品代码"为空的汇总结果,添加查询条件即可,如下面的代码。
select 商品代码,total(数量) as 销售数量 from t_user_sale_1 group by 商品代码 having 商品代码 is not null;