首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >SQLite 也可以做复杂的查询,我不信--SQLite 五脏俱全系列 (4)

SQLite 也可以做复杂的查询,我不信--SQLite 五脏俱全系列 (4)

作者头像
AustinDatabases
发布2026-04-30 18:27:50
发布2026-04-30 18:27:50
790
举报
文章被收录于专栏:AustinDatabasesAustinDatabases

去年SQLlite的几个文章爆火,我都没有想到几万的阅读量。今年我们也新开一个系列叫SQLite知多少,我们继续深入到SQLite的使用问题的探究中.

我们此次选择的版本是3.45.3,这个版本在适应的系统的广泛性都要比新的版本要好,并且一些我们需要的核心技术的更新也都做了,BUG的FIX也做了。所以这个版本将作为我们的研究和使用的核心版本。

接上期,这期必须说说SQL的撰写和一些查询的SQL撰写的技巧了。在SQLite中一些SQL优化的理论可能会减弱,如我们经常在传统数据库中说明的,请不要使用 * select * form table 的方式来进行查询。

在SQLite中,基于SQL引擎的简单,写* 和写确切的字段并无太大的分别,SQLite中的查询都是短小精悍,而在SQLite 查询索引覆盖是一个加速查询的好方法,将一些固定的查询中的条件和字段都加载到索引中,有助于对频繁的查询提速,减少内存的占用和IO的调用。

另外在使用SQLite中查询的核心问题是,避免隐式转换。这里正确的做法

1 使用 SQLite 3.37以上的版本,并且在建表的时候使用 strict tables.

我们下面用一个练习来说明这个问题。我们建立两张表,一张是不进行任何的限制字段类型的普通表,一张是必须要进行严格控制的strict 表。

下面我们先建表

CREATE TABLE test (id INT, val INT); 普通表

CREATE TABLE test (id INT, val INT) strict; 字段类型限制的表

CREATE TABLE users ( user_id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, age INTEGER CHECK (age >= 0), balance REAL DEFAULT 0.0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) STRICT;

正确sqlite表建立的方式

代码语言:javascript
复制
sqlite> CREATE TABLE test (id INT, val INT);  

insert into test (id,val) values ('c','a');


CREATE TABLE test1 (id INT, val INT) strict;  

insert into test1 (id,val) values ('c','a');
insert into test1 (id,val) values (1,2);sqlite> sqlite> sqlite> sqlite> sqlite> sqlite> sqlite> Runtime error: cannot store TEXT value in INT column test1.id (19)

sqlite> 
sqlite> select * from test;
c|a
sqlite> select * from test1;
1|2
sqlite> 

从上面的案例,我们可以看到没有strict的表完全没有限制,int可以插入文字的信息。

代码语言:javascript
复制
sqlite> INSERT INTO users (username, age, balance) VALUES ('zhangsan', 25, 1000.50);
sqlite> INSERT INTO users (username, age, balance) VALUES ('rich_man', 45, 9999999.99);
sqlite> INSERT INTO users (username, age, balance) VALUES ('baby_lee', 0, 50.0);
sqlite> INSERT INTO users (username, age) VALUES ('minimalist', 30);
sqlite> select * from users;
1|zhangsan|25|1000.5|2026-03-03 03:40:52
2|rich_man|45|9999999.99|2026-03-03 03:41:06
3|baby_lee|0|50.0|2026-03-03 03:41:19
4|minimalist|30|0.0|2026-03-03 03:41:28


sqlite> INSERT INTO users (username, age, balance) 
VALUES ('zhangsan', 26, 1500.0)
ON CONFLICT(username) DO UPDATE SET 
    balance = excluded.balance,
    age = excluded.age;

上面是一个复杂的语句,当发现插入新的数据和当前记录中的姓名有冲突的情况下则将旧的记录更新,并且直接覆盖。

这里我们加入一个

那么有的时候,有同学说了,我想知道我的语句执行了多长时间,我怎么看

real time : 从你按下回车键到屏幕显示结果的实际等待时间 User Time: CPU 执行 SQLite 程序本身代码所花费的时间 Sys Time: CPU 替 SQLite 执行操作系统级别指令所花费的时间

代码语言:javascript
复制
sqlite> SELECT 
    CASE 
        WHEN age < 18 THEN '未成年'
        WHEN age BETWEEN 18 AND 35 THEN '青年'
        WHEN age BETWEEN 36 AND 60 THEN '中年'
        ELSE '老年'
    END AS age_group,
    COUNT(*) AS member_count,
    ROUND(AVG(balance), 2) AS avg_balance,
    SUM(balance) AS total_assets
FROM users
GROUP BY age_group
ORDER BY total_assets DESC;  
中年|1|9999999.99|9999999.99
青年|2|750.0|1500.0
未成年|1|50.0|50.0
Run Time: real 0.001 user 0.000172 sys 0.000114
sqlite> 
sqlite> 
sqlite> 
sqlite> 
sqlite> SELECT 
    username, 
    balance,
    -- 计算余额在全局的排名(1为最高)
    RANK() OVER (ORDER BY balance DESC) as balance_rank,
    -- 计算余额占总额的百分比
    ROUND(balance * 100.0 / SUM(balance) OVER(), 2) || '%' as wealth    _percent
FROM users;  
rich_man|9999999.99|1|99.98%
zhangsan|1500.0|2|0.01%
baby_lee|50.0|3|0.0%
minimalist|0.0|4|0.0%
Run Time: real 0.001 user 0.000523 sys 0.000000
sqlite> 
sqlite> 
sqlite> 
sqlite> SELECT user_id, username, age, balance
FROM users
WHERE username LIKE '%an%'  -- 包含 "an" 的用户名
  AND balance > 0
ORDER BY balance DESC, created_at ASC
LIMIT 2 OFFSET 0;      
2|rich_man|45|9999999.99
1|zhangsan|26|1500.0
Run Time: real 0.001 user 0.000204 sys 0.000000

上面的查询中,使用了关系型数据库中复杂的查询,如在查询中使用条件表达式,和逻辑分支。逻辑映射,虚拟列等方式。

代码语言:javascript
复制
sqlite> 
sqlite> 
sqlite> 
sqlite> SELECT 
    a.username AS user_a, 
    b.username AS user_b, 
    ABS(a.balance - b.balance) AS gap
FROM users a
JOIN users b ON a.user_id != b.user_id
ORDER BY gap ASC
LIMIT 1;   
baby_lee|minimalist|50.0
Run Time: real 0.000 user 0.000074 sys 0.000000
sqlite> 
sqlite> 
sqlite> 
sqlite> INSERT INTO users (username, age, balance)
WITH RECURSIVE cnt(x) AS (
    SELECT 1 
    UNION ALL 
    SELECT x + 1 FROM cnt WHERE x < 1000)
    SELECT 
    'robot_' || x, 
    (ABS(RANDOM()) % 80) + 1, -- 随机 1-80 岁
    ROUND(ABS(RANDOM()) % 10000 / 7.0, 2) -- 随机余额
FROM cnt;   
Run Time: real 0.003 user 0.000000 sys 0.002220
sqlite> 
sqlite> 
sqlite> 

上面的这句话是一个比较复杂的在SQLite中生成插入语句的SQL,这里我们说那个递归,插入1000条数据的方法。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AustinDatabases 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档