小. 快速. 可靠.
选择任意三个.

Frequently Asked Questions

  1. How do I create an AUTOINCREMENT field?
  2. What datatypes does SQLite support?
  3. SQLite lets me insert a string into a database column of type integer!
  4. Why doesn't SQLite allow me to use '0' and '0.0' as the primary key on two different rows of the same table?
  5. Can multiple applications or multiple instances of the same application access a single database file at the same time?
  6. Is SQLite threadsafe?
  7. How do I list all tables/indices contained in an SQLite database
  8. Are there any known size limits to SQLite databases?
  9. What is the maximum size of a VARCHAR in SQLite?
  10. Does SQLite support a BLOB type?
  11. How do I add or delete columns from an existing table in SQLite.
  12. I deleted a lot of data but the database file did not get any smaller. Is this a bug?
  13. Can I use SQLite in my commercial product without paying royalties?
  14. How do I use a string literal that contains an embedded single-quote (') character?
  15. What is an SQLITE_SCHEMA error, and why am I getting one?
  16. Why does ROUND(9.95,1) return 9.9 instead of 10.0? Shouldn't 9.95 round up?
  17. I get some compiler warnings when I compile SQLite. Isn't this a problem? Doesn't it indicate poor code quality?
  18. Case-insensitive matching of Unicode characters does not work.
  19. INSERT is really slow - I can only do few dozen INSERTs per second
  20. I accidentally deleted some important information from my SQLite database. How can I recover it?
  21. What is an SQLITE_CORRUPT error? What does it mean for the database to be "malformed"? Why am I getting this error?
  22. Does SQLite support foreign keys?
  23. I get a compiler error if I use the SQLITE_OMIT_... compile-time options when building SQLite.
  24. My WHERE clause expression column1="column1" does not work. It causes every row of the table to be returned, not just the rows where column1 has the value "column1".
  25. How are the syntax diagrams (a.k.a. "railroad" diagrams) for SQLite generated?
  26. The SQL standard requires that a UNIQUE constraint be enforced even if one or more of the columns in the constraint are NULL, but SQLite does not do this. Isn't that a bug?
  27. What is the Export Control Classification Number (ECCN) for SQLite?
  28. My query does not return the column name that I expect. Is this a bug?

(1)如何创建一个AUTOINCREMENT字段?

简短答案:声明为INTEGER PRIMARY KEY的列将自动递增.

更长的答案:如果您将表的某列声明为INTEGER PRIMARY KEY ,则每当您在表的该列中插入NULL时,该NULL都会自动转换为一个整数,该整数比该列的最大值大1表中的所有其他行;如果表为空,则为1. 或者,如果正在使用最大的现有整数密钥9223372036854775807,则随机选择一个未使用的密钥值. 例如,假设您有一个这样的表:

CREATE TABLE t1(
  a INTEGER PRIMARY KEY,
  b INTEGER
);

有了这个表,语句

INSERT INTO t1 VALUES(NULL,123);

从逻辑上讲等同于说:

INSERT INTO t1 VALUES((SELECT max(a) FROM t1)+1,123);

There is a function named sqlite3_last_insert_rowid() which will return the integer key for the most recent insert operation.

请注意,整数键比插入之前表中的最大键大一. 新键在表中当前的所有键上都是唯一的,但它可能与先前从表中删除的键重叠. 要创建在表的整个生命周期中唯一的键,请将AUTOINCREMENT关键字添加到INTEGER PRIMARY KEY声明中. 这样,所选的密钥将比该表中曾经存在的最大密钥多一. 如果该表中先前已存在最大可能的密钥,则INSERT将失败,并显示SQLITE_FULL错误代码.

(2)SQLite支持哪些数据类型?

SQLite使用动态类型 . 内容可以存储为INTEGER,REAL,TEXT,BLOB或NULL.

(3)SQLite让我在整数类型的数据库列中插入一个字符串!

这是一个功能,而不是错误. SQLite使用动态类型 . 它不强制执行数据类型约束. 任何类型的数据都可以(通常)插入任何列中. 您可以将任意长度的字符串放入整数列,布尔列中的浮点数或字符列中的日期. 您在CREATE TABLE命令中分配给列的数据类型不限制可以在该列中放入哪些数据. 每列都可以容纳任意长度的字符串. (有一个例外: INTEGER PRIMARY KEY类型的列只能包含一个64位带符号整数.如果尝试将整数以外的任何内容放入INTEGER PRIMARY KEY列,则会导致错误.)

但是,SQLite确实使用列的声明类型来暗示您更喜欢该格式的值. 因此,例如,如果列的类型为INTEGER,而您尝试在该列中插入字符串,则SQLite会尝试将字符串转换为整数. 如果可以,它将插入整数. 如果没有,它将插入字符串. 此功能称为类型亲和力 .

(4)为什么SQLite不允许我在同一张表的两个不同行上使用" 0"和" 0.0"作为主键?

当您的主键是数字类型时,会发生此问题. 将主键的数据类型更改为TEXT,它将起作用.

每行必须具有唯一的主键. 对于具有数字类型的列,SQLite认为'0'和'0.0'是相同的值,因为它们在数值上彼此相等. (请参阅上一个问题.)因此,值不是唯一的.

(5)多个应用程序或同一应用程序的多个实例可以同时访问一个数据库文件吗?

多个进程可以同时打开同一个数据库. 多个进程可以同时执行SELECT. 但是,在任何时候,只有一个进程可以对数据库进行更改.

SQLite使用读取器/写入器锁来控制对数据库的访问. (在Win95 / 98 / ME中,它不支持读取器/写入器锁定,而是使用概率模拟.)但是请小心:如果数据库文件保存在NFS文件系统上,则该锁定机制可能无法正常工作. 这是因为fcntl()文件锁定在许多NFS实现中都被破坏了. 如果多个进程可能试图同时访问文件,则应避免将SQLite数据库文件放在NFS上. 在Windows上,Microsoft的文档说,如果您没有运行Share.exe守护程序,则锁定可能在FAT文件系统下不起作用. 拥有丰富Windows经验的人告诉我,网络文件的文件锁定非常容易出错,并且不可靠. 如果他们说的是真的,那么在两台或更多台Windows计算机之间共享SQLite数据库可能会导致意外问题.

We are aware of no other embedded SQL database engine that supports as much concurrency as SQLite. SQLite allows multiple processes to have the database file open at once, and for multiple processes to read the database at once. When any process wants to write, it must lock the entire database file for the duration of its update. But that normally only takes a few milliseconds. Other processes just wait on the writer to finish then continue about their business. Other embedded SQL database engines typically only allow a single process to connect to the database at once.

但是,客户端/服务器数据库引擎(例如PostgreSQL,MySQL或Oracle)通常支持更高级别的并发性,并允许多个进程同时写入同一数据库. 在客户端/服务器数据库中,这是可能的,因为始终只有一个受良好控制的服务器进程可用于协调访问. 如果您的应用程序需要大量并发,那么您应该考虑使用客户端/服务器数据库. 但是经验表明,大多数应用程序所需的并发性比其设计人员想象的要少得多.

当SQLite尝试访问被另一个进程锁定的文件时,默认行为是返回SQLITE_BUSY. 您可以使用sqlite3_busy_handler()sqlite3_busy_timeout() API函数从C代码调整此行为.

(6)SQLite线程安全吗?

线程是邪恶的 . 避免他们.

SQLite是线程安全的. 因为许多用户选择忽略上一段中的建议,所以我们做出了这一让步. 但是,为了确保线程安全,必须在SQLite_THREADSAFE预处理器宏设置为1的情况下编译SQLite.Windows和Linux发行版中的预编译二进制文件都采用这种方式进行编译. 如果不确定要链接的SQLite库是否编译为线程安全的,则可以调用sqlite3_threadsafe()接口进行查找.

SQLite是线程安全的,因为它使用互斥锁来序列化对常见数据结构的访问. 但是,获取和释放这些互斥锁的工作会使SQLite速度稍慢. 因此,如果您不需要SQLite具有线程安全性,则应禁用互斥锁以实现最佳性能. 有关其他信息,请参见线程模式文档.

在Unix下,您不应跨fork()系统调用将打开的SQLite数据库携带到子进程中.

(7)如何列出SQLite数据库中包含的所有表/索引

如果您正在运行sqlite3命令行访问程序,则可以键入" .tables "以获取所有表的列表. 或者,您可以键入" .schema "以查看完整的数据库架构,包括所有表和索引. 这些命令中的任何一个都可以跟随一个LIKE模式,该模式将限制显示的表.

在C / C ++程序(或使用Tcl / Ruby / Perl / Python绑定的脚本)中,可以通过在名为" SQLITE_MASTER "的特殊表上执行SELECT来访问表名和索引名. 每个SQLite数据库都有一个SQLITE_MASTER表,该表定义了数据库的架构. SQLITE_MASTER表如下所示:

CREATE TABLE sqlite_master (
  type TEXT,
  name TEXT,
  tbl_name TEXT,
  rootpage INTEGER,
  sql TEXT
);

对于表, 类型字段将始终为"表" , 名称字段将为表的名称. 因此,要获取数据库中所有表的列表,请使用以下SELECT命令:

SELECT name FROM sqlite_master
WHERE type='table'
ORDER BY name;

对于索引, type等于'index' , name是索引的名称, tbl_name是索引所属的表的名称. 对于表和索引, sql字段都是创建表或索引的原始CREATE TABLE或CREATE INDEX语句的文本. 对于自动创建的索引(用于实现PRIMARY KEY或UNIQUE约束), sql字段为NULL.

无法使用UPDATE,INSERT或DELETE修改SQLITE_MASTER表(在特殊情况下除外). SQLITE_MASTER表由诸如CREATE TABLE,CREATE INDEX,DROP TABLE和DROP INDEX之类的命令自动更新.

临时表不会出现在SQLITE_MASTER表中. 临时表及其索引和触发器出现在另一个名为SQLITE_TEMP_MASTER的特殊表中. SQLITE_TEMP_MASTER的工作方式与SQLITE_MASTER相同,只是它仅对创建临时表的应用程序可见. 要获取所有表的列表(永久表和临时表),可以使用类似于以下命令:

SELECT name FROM 
   (SELECT * FROM sqlite_master UNION ALL
    SELECT * FROM sqlite_temp_master)
WHERE type='table'
ORDER BY name

(8)SQLite数据库是否存在已知的大小限制?

有关SQLite限制的完整讨论,请参见limits.html .

(9)SQLite中VARCHAR的最大大小是多少?

SQLite不强制VARCHAR的长度. 您可以声明VARCHAR(10),SQLite乐于在此存储一个5亿个字符串. 它将保留所有5亿个字符的完整性. 您的内容永远不会被截断. )" to be the same as "TEXT", regardless of the value of . 无论的值如何,SQLite都将" VARCHAR( )"的列类型与" TEXT"相同.

(10)SQLite是否支持BLOB类型?

SQLite允许您将BLOB数据存储在任何列中,即使声明为容纳其他类型的列也是如此. BLOB甚至可以用作主键.

(11)如何在SQLite中的现有表中添加或删除列.

SQLite具有有限的ALTER TABLE支持,可用于将列添加到表的末尾或更改表的名称. 如果要对表的结构进行更复杂的更改,则必须重新创建表. 您可以将现有数据保存到临时表,删除旧表,创建新表,然后将数据从临时表复制回.

例如,假设您有一个名为" t1"的表,其列名为" a"," b"和" c",并且您想从该表中删除列" c". 以下步骤说明了如何完成此操作:

BEGIN TRANSACTION;
CREATE TEMPORARY TABLE t1_backup(a,b);
INSERT INTO t1_backup SELECT a,b FROM t1;
DROP TABLE t1;
CREATE TABLE t1(a,b);
INSERT INTO t1 SELECT a,b FROM t1_backup;
DROP TABLE t1_backup;
COMMIT;

(12)我删除了很多数据,但是数据库文件没有变小. 这是错误吗?

不能.当您从SQLite数据库中删除信息时,未使用的磁盘空间将添加到内部"自由列表",并在下次您插入数据时重新使用. 磁盘空间不会丢失. 但它们都不会返回操作系统.

如果删除大量数据并希望收缩数据库文件,请运行VACUUM命令. VACUUM将从头开始重建数据库. 这将使数据库具有一个空的空闲列表和一个最小的文件. 但是请注意,VACUUM可能需要一些时间才能运行,并且在运行时它可能会使用的临时磁盘空间是原始文件的两倍.

使用VACUUM命令的替代方法是使用auto_vacuum pragma启用的自动真空模式.

(13)我可以在不支付特许权使用费的情况下在我的商业产品中使用SQLite吗?

是. SQLite在公共领域 . 不对代码的任何部分主张所有权. 您可以用它做任何您想做的事情.

(14)如何使用包含嵌入式单引号(')字符的字符串文字?

SQL标准指定通过在行中放置两个单引号来转义字符串中的单引号. 在这方面,SQL的工作方式类似于Pascal编程语言. 例:

    INSERT INTO xyz VALUES('5 O''clock');
  

(15) What is an SQLITE_SCHEMA error, and why am I getting one?

当准备好的SQL语句不再有效且无法执行时,将返回SQLITE_SCHEMA错误. 发生这种情况时,必须使用sqlite3_prepare() API从SQL重新编译该语句. 仅当使用sqlite3_prepare()sqlite3_step()接口运行SQL时,才会发生SQLITE_SCHEMA错误. 您将永远不会从sqlite3_exec()收到SQLITE_SCHEMA错误. 如果使用sqlite3_prepare_v2()而不是sqlite3_prepare()准备语句,也不会收到错误消息.

sqlite3_prepare_v2()接口创建一个准备好的语句 ,如果架构更改,该语句将自动重新编译自身. 处理SQLITE_SCHEMA错误的最简单方法是始终使用sqlite3_prepare_v2()而不是sqlite3_prepare() .

(16)为什么ROUND(9.95,1)返回9.9而不是10.0? 9.95不应该舍入吗?

SQLite使用二进制算术,并且在二进制中,无法用有限的位数写9.95. 在64位IEEE浮点数(SQLite使用的浮点数)中,最接近您的值是9.95.949999999999999999289457457239239814814128875732421875. 因此,当您键入" 9.95"时,SQLite会真正将数字理解为上面显示的更长的值. 该值取整.

在处理浮点二进制数时,总是会出现这种问题. 要记住的一般规则是,大多数具有十进制有限表示形式的小数(aka" base-10")都不具有二进制有限表示形式(aka" base-2"). 因此,使用可用的最接近的二进制数来近似它们. 该近似值通常非常接近,但是会略有偏差,在某些情况下,可能会使您的结果与预期的结果有所不同.

(17)编译SQLite时收到一些编译器警告. 这不是问题吗? 难道不是代码质量差吗?

SQLite中的质量保证是使用全面测试来完成的,而不是通过编译器警告或其他静态代码分析工具来完成的. 换句话说,我们验证SQLite确实得到了正确的答案,而不仅仅是它满足了样式约束. 大多数SQLite代码库纯粹用于测试. SQLite测试套件运行成千上万个单独的测试用例,并且其中许多测试用例已参数化,因此在每次发行之前,都要运行并评估涉及数十亿条SQL语句的亿万个测试的正确性. 开发人员使用代码覆盖率工具来验证是否测试了所有通过代码的路径. 每当在SQLite中发现错误时,都会编写新的测试用例来展示该错误,以便将来不会再次发现该错误.

在测试过程中,将使用特殊的工具编译SQLite库,该工具可以使测试脚本模拟各种故障,以验证SQLite是否可以正确恢复. 仔细跟踪内存分配,即使出现内存分配失败,也不会发生内存泄漏. 定制VFS层用于模拟操作系统崩溃和电源故障,以确保在这些事件中事务是原子的. 故意注入I / O错误的机制表明SQLite可以抵抗此类故障. (作为实验,请尝试在其他SQL数据库引擎上引发此类错误,然后看看会发生什么!)

我们还在Linux上使用Valgrind运行SQLite,并验证它没有发现任何问题.

有人说我们应该消除所有警告,因为良性警告会掩盖未来更改中可能出现的真实警告. 这是真的. 但是作为回应,开发人员注意到所有警告已经在用于SQLite开发的版本(各种版本的GCC,MSVC和clang)中已得到修复. 编译器警告通常仅由SQLite开发人员不使用自己的编译器或编译时选项引起.

(18)不区分大小写的Unicode字符匹配不起作用.

SQLite的默认配置仅支持不区分大小写的ASCII字符比较. 这样做的原因是,要进行完整的Unicode不区分大小写的比较和大小写转换,需要的表和逻辑将几乎是SQLite库的两倍. SQLite开发人员认为,需要完全Unicode大小写支持的任何应用程序可能已经具有必要的表和功能,因此SQLite不应占用空间来复制此功能.

默认情况下,SQLite不会提供完全的Unicode大小写支持,而是提供了链接外部Unicode比较和转换例程的功能. 应用程序可以重载内置的NOCASE整理序列(使用sqlite3_create_collat​​ion() )和内置的like()upper()lower()函数(使用sqlite3_create_function() ). SQLite源代码包括执行这些重载的" ICU"扩展. 或者,开发人员可以根据项目中已经包含的自己的Unicode感知比较例程编写自己的重载.

(19) INSERT is really slow - I can only do few dozen INSERTs per second

实际上,在普通台式计算机上,SQLite每秒可以轻松地执行50,000个或更多INSERT语句. 但是它每秒只能进行几十笔交易. 事务速度受磁盘驱动器转速的限制. 一个事务通常需要磁盘盘完整旋转两次,而在7200RPM磁盘驱动器上,这会将您限制为每秒大约60个事务.

事务处理速度受到磁盘驱动器速度的限制,因为(默认情况下)SQLite实际上会等待,直到数据真正安全地存储在磁盘表面上,然后事务处理才完成. 这样,即使您突然断电或操作系统崩溃,您的数据仍然是安全的. 有关详细信息,请阅读有关SQLite中的原子提交的信息. .

默认情况下,每个INSERT语句都是其自己的事务. 但是,如果用BEGIN ... COMMIT包围多个INSERT语句,则所有插入都被分组为一个事务. 提交事务所需的时间在所有随附的插入语句中摊销,因此每个插入语句的时间大大减少.

另一个选择是运行PRAGMA sync = OFF . 此命令将使SQLite不等待数据到达磁盘表面,这将使写入操作显得更快. 但是,如果您在事务处理过程中断电,则数据库文件可能会损坏.

(20)我不小心从SQLite数据库中删除了一些重要信息. 我该如何恢复?

如果您有数据库文件的备份副本,请从备份中恢复信息.

如果没有备份,恢复将非常困难. 您可能能够在原始数据库文件的二进制转储中找到部分字符串数据. 使用特殊工具也可以恢复数字数据,尽管据我们所知,尚无此类工具. 有时使用SQLITE_SECURE_DELETE选项编译SQLite,该选项将用零覆盖所有已删除的内容. 如果真是这样,那么恢复显然是不可能的. 如果由于删除了数据而运行了VACUUM,则恢复也是不可能的. 如果未使用SQLITE_SECURE_DELETE且尚未运行VACUUM,则某些已删除的内容可能仍在数据库文件的标记为可重复使用的区域中. 但是,同样,我们不知道可以帮助您恢复该数据的过程或工具.

(21)什么是SQLITE_CORRUPT错误? 数据库"格式错误"是什么意思? 为什么会出现此错误?

当SQLite检测到数据库文件的结构,格式或其他控制元素中的错误时,将返回SQLITE_CORRUPT错误.

没有外部帮助,SQLite不会破坏数据库文件. 如果您的应用程序在更新过程中崩溃,则您的数据是安全的. 即使您的操作系统崩溃或断电,该数据库也是安全的. SQLite的防撞性已被广泛研究和测试,数十亿用户的多年实际经验证明了这一点.

就是说,硬件或操作系统中的外部程序或错误可以通过很多事情来破坏数据库文件. 有关更多信息,请参见如何损坏SQLite数据库文件 .

您可以使用PRAGMA integrity_check对数据库完整性进行彻底但耗时的测试.

您可以使用PRAGMA quick_check对数据库完整性进行更快但不太彻底的测试.

根据数据库损坏的严重程度,您也许可以通过使用CLI将架构和内容转储到文件然后重新创建来恢复某些数据. 不幸的是,一旦矮胖从墙上掉下来,通常就不可能将他重新放在一起.

(22)SQLite是否支持外键?

3.6.19 (2009-10-14) 版本开始 ,SQLite支持外键约束 . 但是默认情况下,外键约束的执行是关闭的(为了向后兼容). 要启用外键约束实施,请运行PRAGMA foreign_keys = ON或使用-DSQLITE_DEFAULT_FOREIGN_KEYS = 1进行编译.

(23)如果在构建SQLite时使用SQLITE_OMIT _...编译时选项,则会出现编译器错误.

SQLITE_OMIT _...编译时选项仅在从规范源文件进行构建时起作用. 当你从SQLite的建立他们工作合并或预处理后的源文件.

可以建立一种特殊的合并方法 ,该方法可以与一组预定的SQLITE_OMIT _...选项一起使用. 有关说明,请参见SQLITE_OMIT _...文档 .

(24)我的WHERE子句表达式column1 =" column1"不起作用. 这将导致返回表的每一行,而不仅仅是返回column1值为" column1"的行.

在SQL的字符串文字中使用单引号而不是双引号. 这就是SQL标准的要求. 您的WHERE子句表达式应为: column1 ='column1'

SQL在包含特殊字符或关键字的标识符(列或表名)周围使用双引号. 因此,双引号是转义标识符名称的一种方法. 因此,当您说column1 =" column1"时 ,等效于column1 = column1 ,这显然总是正确的.

(25)如何生成SQLite的语法图(又称"铁路"图)?

该过程在http://wiki.tcl-lang.org/21708中进行了说明.

(26)SQL标准要求即使约束中的一个或多个列为NULL,也必须强制执行UNIQUE约束,但是SQLite不会这样做. 那不是错误吗?

也许您是指SQL92中的以下语句:
当且仅当表中没有两行在唯一列中具有相同的非空值时,才满足唯一约束.
该声明含糊不清,至少有两种可能的解释:
  1. 当且仅当表中没有两行具有相同的值并且唯一列中具有非空值时,才满足唯一约束.
  2. 当且仅当表中没有两行在不为null的唯一列的子集中具有相同的值时,才满足唯一约束.
SQLite遵循解释(1),PostgreSQL,MySQL,Oracle和Firebird也是如此. Informix和Microsoft SQL Server确实使用了解释(2),但是我们SQLite开发人员认为解释(1)是对该要求的最自然的理解,我们还希望最大程度地与其他SQL数据库引擎以及大多数其他数据库引擎兼容.数据库引擎也与(1)一起使用,因此SQLite就是这样做的.

(27)什么是SQLite的导出控制分类号(ECCN)?

在仔细检查了商务控制列表(CCL)之后,我们确信任何ECCN都没有描述核心的公共域SQLite源代码,因此ECCN应该报告为EAR99 .

上面的内容适用于核心公共域SQLite. 如果通过添加新代码扩展SQLite,或者将SQLite与应用程序静态链接,则在特定情况下可能会更改ECCN.

(28)我的查询未返回我期望的列名. 这是错误吗?

如果结果集的列由AS子句命名,则SQLite保证使用AS关键字右侧的标识符作为列名. 如果结果集不使用AS子句,则SQLite可以随意命名该列. 有关更多信息,请参见sqlite3_column_name()文档.

by  ICOPY.SITE