SQLite3数据类型
SQLite 中的数据类型
1. SQLite 中的数据类型
大多数 SQL 数据库引擎(据我们所知,除 SQLite 之外的所有 SQL 数据库引擎)都使用静态、刚性类型。使用静态类型时,值的数据类型由其容器(存储值的特定列)决定。
SQLite 使用更通用的动态类型系统。在 SQLite 中,值的数据类型与值本身相关联,而不是与其容器相关联。SQLite 的动态类型系统与其他数据库引擎更常见的静态类型系统向后兼容,因为在静态类型数据库上运行的 SQL 语句在 SQLite 中的工作方式相同。但是,SQLite 中的动态类型允许它执行在传统的严格类型数据库中无法完成的事情。 灵活类型是SQLite 的一个功能,而不是错误。
更新:从 3.37.0 版(2021-11-27)开始, 对于喜欢此类功能的开发人员,SQLite 提供了执行严格类型强制的 STRICT 表。
2.存储类别和数据类型
SQLite 数据库中存储的每个值(或由数据库引擎操作的)都具有以下存储类别之一:
NULL . 该值为 NULL 值。
INTEGER . 该值是一个有符号整数,根据值的大小存储在 0、1、2、3、4、6 或 8 个字节中。
REAL . 该值是浮点值,存储为 8 字节 IEEE 浮点数。
TEXT . 该值是文本字符串,使用数据库编码(UTF-8、UTF-16BE 或 UTF-16LE)存储。
BLOB . 该值是一个数据块,按输入时的形式存储。
存储类别比数据类型更通用。例如,INTEGER 存储类别包括 7 种不同长度的整数数据类型。 这在磁盘上有所不同。 但是,一旦 INTEGER 值从磁盘读取到内存中进行处理,它们就会转换为最通用的数据类型(8 字节有符号整数)。因此,在大多数情况下,“存储类别”与“数据类型”没有区别,这两个术语可以互换使用。
SQLite 版本 3 数据库中的任何列(INTEGER PRIMARY KEY列除外)均可用于存储任何存储类别的值。
SQL 语句中的所有值(无论是嵌入在 SQL 语句文本中的文字还是绑定到 预编译 SQL 语句的参数 )都具有隐式存储类。在下述情况下,数据库引擎可能会在查询执行期间在数字存储类(INTEGER 和 REAL)和 TEXT 之间转换值。
2.1.布尔数据类型
SQLite 没有单独的布尔存储类。相反,布尔值存储为整数 0(假)和 1(真)。
从 3.23.0(2018-04-02)版本开始,SQLite 可以识别关键字“TRUE”和“FALSE”,但这些关键字实际上只是整数文字 1 和 0 的替代拼写。
2.2.日期和时间数据类型
SQLite 没有专门用于存储日期和/或时间的存储类。相反,SQLite 的内置日期和时间函数能够将日期和时间存储为 TEXT、REAL 或 INTEGER 值:
TEXT为 ISO8601 字符串(“YYYY-MM-DD HH:MM:SS.SSS”)。
REAL为儒略日数,根据外推公历,表示自公元前 4714 年 11 月 24 日格林威治中午以来的天数。
INTEGER为 Unix 时间,自 1970-01-01 00:00:00 UTC 以来的秒数。
应用程序可以选择以任何这些格式存储日期和时间,并使用内置的 日期和时间函数在格式之间自由转换。
3.类型亲和力
使用严格类型的 SQL 数据库引擎通常会尝试自动将值转换为适当的数据类型。考虑一下:
CREATE TABLE t1(a INT, b VARCHAR(10)); INSERT INTO t1(a,b) VALUES('123',456);
严格类型数据库会在插入之前将字符串“123”转换为整数 123,将整数 456 转换为字符串“456”。
为了最大限度地提高 SQLite 与其他数据库引擎之间的兼容性,并使上述示例在 SQLite 上也能像在其他 SQL 数据库引擎上一样工作,SQLite 支持列上的“类型亲和性”概念。列的类型亲和性是建议存储在该列中的数据的类型。这里的重要思想是类型是建议的,而不是必需的。任何列仍然可以存储任何类型的数据。只是有些列在可以选择的情况下会更倾向于使用一种存储类而不是另一种。列的首选存储类称为其“亲和性”。
SQLite 3 数据库中的每一列都被分配了下列类型亲和性之一:
TEXT
NUMERIC
INTEGER
REAL
BLOB
(历史记录:“BLOB”类型亲和力曾被称为“NONE”。但该术语很容易与“无亲和力”混淆,因此被重新命名。)
具有 TEXT 亲和性的列使用存储类 NULL、TEXT 或 BLOB 存储所有数据。如果将数值数据插入具有 TEXT 亲和性的列,则会将其转换为文本形式再进行存储。
具有 NUMERIC 亲和性的列可能包含使用所有五种存储类别的值。当将文本数据插入 NUMERIC 列时,如果文本是格式正确的整数或实数文字,则文本的存储类别将分别转换为 INTEGER 或 REAL(按优先顺序)。如果 TEXT 值是格式正确的整数文字,但太大而无法放入 64 位有符号整数中,则将其转换为 REAL。对于 TEXT 和 REAL 存储类别之间的转换,仅保留数字的前 15 位有效十进制数字。如果 TEXT 值不是格式正确的整数或实数文字,则该值将存储为 TEXT。就本段的目的而言,十六进制整数文字不被视为格式正确的,并存储为 TEXT。 (这样做是为了与 SQLite 3.8.6 2014-08-15之前的版本保持历史兼容性,在该版本中十六进制整数文字首次引入 SQLite。)如果将可以精确表示为整数的浮点值插入到具有 NUMERIC 亲和性的列中,则该值将转换为整数。不会尝试转换 NULL 或 BLOB 值。
字符串可能看起来像带有小数点和/或指数符号的浮点文字,但只要该值可以表示为整数,NUMERIC 亲和性就会将其转换为整数。因此,字符串“3.0e+5”在具有 NUMERIC 亲和性的列中存储为整数 300000,而不是浮点值 300000.0。
使用 INTEGER 亲和性的列与使用 NUMERIC 亲和性的列的行为相同。INTEGER 和 NUMERIC 亲和性之间的差异仅在CAST 表达式中明显:表达式“CAST(4.0 AS INT)”返回整数 4,而“CAST(4.0 AS NUMERIC)”将值保留为浮点数 4.0。
具有 REAL 亲和性的列的行为类似于具有 NUMERIC 亲和性的列,只是它会强制将整数值转换为浮点表示。(作为内部优化,存储在具有 REAL 亲和性的列中的没有小数部分的小浮点值将作为整数写入磁盘,以占用更少的空间,并在读出值时自动转换回浮点。此优化在 SQL 级别完全不可见,只能通过检查数据库文件的原始位来检测。)
具有亲和力 BLOB 的列不会优先选择一种存储类别,也不会尝试将数据从一种存储类别强制转换为另一种存储类别。
3.1.柱亲和力的测定
对于未声明为STRICT的表,列的亲和力由列的声明类型决定,并按照显示的顺序遵循以下规则:
如果声明的类型包含字符串“INT”,则其被分配 INTEGER 亲和力。
如果列的声明类型包含字符串“CHAR”、“CLOB”或“TEXT”中的任何一个,则该列具有 TEXT 亲和性。请注意,类型 VARCHAR 包含字符串“CHAR”,因此被分配了 TEXT 亲和性。
如果列的声明类型包含字符串“BLOB”或者未指定类型,则该列具有亲和力 BLOB。
如果列的声明类型包含任何字符串“REAL”、“FLOA”或“DOUB”,则该列具有 REAL 亲和性。
否则,亲和力为NUMERIC。
请注意,确定列亲和性的规则顺序很重要。声明类型为“CHARINT”的列将同时匹配规则 1 和 2,但第一个规则优先,因此列亲和性将为 INTEGER。
3.1.1.亲和性名称示例
下表显示了多少来自更传统的 SQL 实现的常见数据类型名称通过上一节的五条规则转换为亲和性。此表仅显示了 SQLite 将接受的数据类型名称的一小部分。请注意,类型名称后面括号中的数字参数(例如:“VARCHAR(255)”)将被 SQLite 忽略 - SQLite 不对字符串、BLOB 或数字值的长度施加任何长度限制(大型全局SQLITE_MAX_LENGTH限制除外)。
来自
CREATE TABLE 语句
或 CAST 表达式的 示例类型名称产生的亲和力 用于确定亲和力的规则 INT
整数
TINYINT
SMALLINT
MEDIUMINT
BIGINT
无符号大 INT
INT2
INT8整数 1 CHARACTER(20)
VARCHAR(255)
可变字符(255)
NCHAR(55)
本机字符(70)
NVARCHAR(100)
文本
CLOB文本 2 BLOB
没有指定数据类型大对象 3 实数
双
精度
浮点数真实的 4 数字
十进制(10,5)
布尔
日期
日期时间数字 5
请注意,由于“POINT”末尾有“INT”,声明的“FLOATING POINT”类型将具有 INTEGER 亲和性,而不是 REAL 亲和性。声明的“STRING”类型具有 NUMERIC 亲和性,而不是 TEXT 亲和性。
3.2.表达的亲和性
每个表列都有一个类型亲和力(BLOB、TEXT、INTEGER、REAL 或 NUMERIC 之一),但表达式不一定具有亲和力。
表达亲和力由以下规则决定:
如果操作数是列表,则 IN 或 NOT IN 运算符的右侧操作数没有亲和力,如果操作数是 SELECT,则其亲和力与结果集表达式的亲和力相同。
当表达式是对真实表的列的简单引用(不是VIEW或子查询)时,该表达式具有与表列相同的亲和力。
列名周围的括号将被忽略。因此,如果 X 和 YZ 是列名,则 (X) 和 (YZ) 也被视为列名,并且具有相应列的亲和性。
任何应用于列名的运算符(包括无操作的一元“+”运算符)都会将列名转换为始终没有亲和性的表达式。因此,即使 X 和 YZ 是列名,表达式 +X 和 +YZ 也不是列名,并且没有亲和性。
形式为“CAST( expr AS type )”的表达式具有与声明类型为“ type ”的列相同的亲和力。
COLLATE 运算符与其左侧操作数具有相同的亲和力。
否则,表达式就没有亲和力。
3.3.视图和子查询的列亲和性
VIEW或 FROM 子句子查询的“列”实际上是实现 VIEW 或子查询的SELECT语句的结果集中的表达式。因此,VIEW 或子查询的列的亲和性由上面的表达式亲和性规则决定。考虑一个例子:
创建表 t1(a INT,b TEXT,c REAL);创建视图 v1(x,y,z) 作为从 t1 选择 b、a+c、42,其中 b!=11;
v1.x 列的亲和力将与 t1.b (TEXT) 的亲和力相同,因为 v1.x 直接映射到 t1.b。但列 v1.y 和 v1.z 都没有亲和力,因为这些列映射到表达式 a+c 和 42,而表达式始终没有亲和力。
3.3.1.复合视图的列亲和性
当实现VIEW或 FROM 子句子查询的SELECT语句是复合 SELECT时,VIEW 或子查询的每一列的亲和力将是组成复合语句的各个 SELECT 语句之一的相应结果列的亲和力。但是,无法确定将使用哪个 SELECT 语句来确定亲和力。在查询评估期间的不同时间,可能会使用不同的组成 SELECT 语句来确定亲和力。不同版本的 SQLite 之间的选择可能会有所不同。在同一版本的 SQLite 中,不同查询之间的选择可能会发生变化。在同一查询的不同时间,选择可能会有所不同。因此,您永远无法确定在组成子查询中具有不同亲和力的复合 SELECT 的列将使用什么亲和力。
如果您关心结果的数据类型,最佳做法是避免在复合 SELECT 中混合亲和性。在复合 SELECT 中混合亲和性可能会导致令人惊讶且不直观的结果。例如,请参阅论坛帖子 02d7be94d7。
3.4.列亲和行为示例
以下 SQL 演示了 SQLite 如何在将值插入表中时使用列亲和性进行类型转换。
CREATE TABLE t1( t TEXT, -- text affinity by rule 2 nu NUMERIC, -- numeric affinity by rule 5 i INTEGER, -- integer affinity by rule 1 r REAL, -- real affinity by rule 4 no BLOB -- no affinity by rule 3 ); -- Values stored as TEXT, INTEGER, INTEGER, REAL, TEXT. INSERT INTO t1 VALUES('500.0', '500.0', '500.0', '500.0', '500.0'); SELECT typeof(t), typeof(nu), typeof(i), typeof(r), typeof(no) FROM t1; text|integer|integer|real|text -- Values stored as TEXT, INTEGER, INTEGER, REAL, REAL. DELETE FROM t1; INSERT INTO t1 VALUES(500.0, 500.0, 500.0, 500.0, 500.0); SELECT typeof(t), typeof(nu), typeof(i), typeof(r), typeof(no) FROM t1; text|integer|integer|real|real -- Values stored as TEXT, INTEGER, INTEGER, REAL, INTEGER. DELETE FROM t1; INSERT INTO t1 VALUES(500, 500, 500, 500, 500); SELECT typeof(t), typeof(nu), typeof(i), typeof(r), typeof(no) FROM t1; text|integer|integer|real|integer -- BLOBs are always stored as BLOBs regardless of column affinity. DELETE FROM t1; INSERT INTO t1 VALUES(x'0500', x'0500', x'0500', x'0500', x'0500'); SELECT typeof(t), typeof(nu), typeof(i), typeof(r), typeof(no) FROM t1; blob|blob|blob|blob|blob -- NULLs are also unaffected by affinity DELETE FROM t1; INSERT INTO t1 VALUES(NULL,NULL,NULL,NULL,NULL); SELECT typeof(t), typeof(nu), typeof(i), typeof(r), typeof(no) FROM t1; null|null|null|null|null
SQLite 版本 3 具有常用的 SQL 比较运算符集,包括“=”、“==”、“<”、“<=”、“>”、“>=”、“!=”、“”、“IN”、“NOT IN”、“BETWEEN”、“IS”和“IS NOT”。
4.1.排序顺序
比较结果取决于操作数的存储类别,遵循以下规则:
存储类别为 NULL 的值被认为小于任何其他值(包括另一个存储类别为 NULL 的值)。
INTEGER 或 REAL 值小于任何 TEXT 或 BLOB 值。当将 INTEGER 或 REAL 与另一个 INTEGER 或 REAL 进行比较时,将执行数值比较。
TEXT 值小于 BLOB 值。比较两个 TEXT 值时,将使用适当的排序顺序来确定结果。
比较两个 BLOB 值时,使用 memcmp() 确定结果。
4.2.比较之前的类型转换
SQLite 可能会在执行比较之前尝试在存储类 INTEGER、REAL 和/或 TEXT 之间转换值。在进行比较之前是否尝试进行任何转换取决于操作数的类型亲和性。
“应用亲和性”是指当且仅当转换不会丢失基本信息时,才将操作数转换为特定存储类。数值始终可以转换为文本。如果文本内容是格式正确的整数或实数文字,但不是十六进制整数文字,则可以将文本值转换为数值。只需将二进制 BLOB 内容解释为当前数据库编码中的文本字符串,即可将 BLOB 值转换为文本值。
在比较之前,根据以下规则按所示顺序将亲和性应用于比较运算符的操作数:
如果一个操作数具有 INTEGER、REAL 或 NUMERIC 亲和性,而另一个操作数具有 TEXT 或 BLOB 或没有亲和性,则 NUMERIC 亲和性将应用于其他操作数。
如果一个操作数具有 TEXT 亲和性而另一个操作数没有亲和性,则将 TEXT 亲和性应用于另一个操作数。
否则,将不应用任何亲和力并且两个操作数将按原样进行比较。
表达式“a BETWEEN b AND c”被视为两个单独的二进制比较“a >= b AND a <= c”,即使这意味着在每个比较中对“a”应用不同的亲和性。在形式为“x IN (SELECT y ...)”的比较中,数据类型转换被处理为比较实际上是“x=y”。表达式“a IN (x, y, z, ...)”等同于“a = +x OR a = +y OR a = +z OR ...”。换句话说,IN 运算符右侧的值(本例中的“x”、“y”和“z”值)被视为没有亲和性,即使它们恰好是列值或 CAST 表达式。
4.3.比较示例
CREATE TABLE t1( a TEXT, -- text affinity b NUMERIC, -- numeric affinity c BLOB, -- no affinity d -- no affinity ); -- Values will be stored as TEXT, INTEGER, TEXT, and INTEGER respectively INSERT INTO t1 VALUES('500', '500', '500', 500); SELECT typeof(a), typeof(b), typeof(c), typeof(d) FROM t1; text|integer|text|integer -- Because column "a" has text affinity, numeric values on the -- right-hand side of the comparisons are converted to text before -- the comparison occurs. SELECT a < 40, a < 60, a < 600 FROM t1; 0|1|1 -- Text affinity is applied to the right-hand operands but since -- they are already TEXT this is a no-op; no conversions occur. SELECT a < '40', a < '60', a < '600' FROM t1; 0|1|1 -- Column "b" has numeric affinity and so numeric affinity is applied -- to the operands on the right. Since the operands are already numeric, -- the application of affinity is a no-op; no conversions occur. All -- values are compared numerically. SELECT b < 40, b < 60, b < 600 FROM t1; 0|0|1 -- Numeric affinity is applied to operands on the right, converting them -- from text to integers. Then a numeric comparison occurs. SELECT b < '40', b < '60', b < '600' FROM t1; 0|0|1 -- No affinity conversions occur. Right-hand side values all have -- storage class INTEGER which are always less than the TEXT values -- on the left. SELECT c < 40, c < 60, c < 600 FROM t1; 0|0|0 -- No affinity conversions occur. Values are compared as TEXT. SELECT c < '40', c < '60', c < '600' FROM t1; 0|1|1 -- No affinity conversions occur. Right-hand side values all have -- storage class INTEGER which compare numerically with the INTEGER -- values on the left. SELECT d < 40, d < 60, d < 600 FROM t1; 0|0|1 -- No affinity conversions occur. INTEGER values on the left are -- always less than TEXT values on the right. SELECT d < '40', d < '60', d < '600' FROM t1;
如果比较结果为“a<40”且形式为“40>a”,则示例中的所有结果都是相同的。
5.操作符
数学运算符(+、-、*、/、%、<<、>>、& 和 |)将两个操作数都解释为数字。STRING 或 BLOB 操作数会自动转换为 REAL 或 INTEGER 值。如果 STRING 或 BLOB 看起来像实数(如果它有小数点或指数)或者该值超出了可以表示为 64 位有符号整数的范围,则它将转换为 REAL。否则,操作数将转换为 INTEGER。数学操作数的隐式类型转换与CAST 到 NUMERIC略有不同,因为看起来像实数但没有小数部分的字符串和 BLOB 值将保留为 REAL,而不是像CAST 到 NUMERIC那样转换为 INTEGER 。即使有损且不可逆,也会执行从 STRING 或 BLOB 到 REAL 或 INTEGER 的转换。某些数学运算符(%、<<、>>、& 和 |)需要 INTEGER 操作数。对于这些运算符,REAL 操作数转换为 INTEGER 的方式与CAST 转换为 INTEGER 的方式相同。<<、>>、& 和 | 运算符始终返回 INTEGER(或 NULL)结果,但 % 运算符根据其操作数的类型返回 INTEGER 或 REAL(或 NULL)。数学运算符上的 NULL 操作数会产生 NULL 结果。数学运算符上的操作数如果看起来不像数字且不是 NULL,则会转换为 0 或 0.0。除以零会得到 NULL 的结果。
6.排序、分组和复合 SELECT
当查询结果通过 ORDER BY 子句排序时,存储类型为 NULL 的值首先出现,然后是按数字顺序排列的 INTEGER 和 REAL 值,然后是按排序顺序排列的 TEXT 值,最后是按 memcmp() 顺序排列的 BLOB 值。排序前不会发生任何存储类型转换。
使用 GROUP BY 子句对值进行分组时,具有不同存储类别的值将被视为不同,但 INTEGER 和 REAL 值除外,如果它们在数值上相等,则被视为相等。GROUP BY 子句不会将任何亲和性应用于任何值。
复合 SELECT 运算符 UNION、INTERSECT 和 EXCEPT 在值之间执行隐式比较。对于与 UNION、INTERSECT 或 EXCEPT 相关的隐式比较,比较操作数不应用任何亲和性 - 值按原样进行比较。
7.整理序列
当 SQLite 比较两个字符串时,它会使用排序序列或排序函数(两个术语代表同一事物)来确定哪个字符串更大或两个字符串是否相等。SQLite 有三个内置排序函数:BINARY、NOCASE 和 RTRIM。
BINARY-使用 memcmp() 比较字符串数据,不管文本编码如何。
NOCASE - 与二进制类似,不同之处在于它使用 sqlite3_strnicmp()进行比较。因此,在进行比较之前,ASCII 的 26 个大写字符会被折叠为相应的小写字符。请注意,只有 ASCII 字符会进行大小写折叠。由于所需表的大小,SQLite 不会尝试进行完整的 UTF 大小写折叠。还请注意,出于比较目的,字符串中的任何 U+0000 字符都被视为字符串终止符。
RTRIM — 与二进制相同,但会忽略尾随的空格字符。
应用程序可以使用sqlite3_create_collation()接口注册额外的整理函数。
排序函数仅在比较字符串值时才有用。数值始终以数字方式进行比较,BLOB 始终使用 memcmp() 逐字节进行比较。
7.1.从 SQL 指定排序顺序
每个表的每个列都有一个关联的排序函数。如果没有明确定义排序函数,则排序函数默认为 BINARY。列定义 的 COLLATE 子句用于为列定义备选排序函数。
确定二进制比较运算符(=、<、>、<=、>=、!=、IS 和 IS NOT)使用哪个排序函数的规则如下:
如果任一操作数使用后缀COLLATE 运算符具有明确的排序函数分配,则使用明确的排序函数进行比较,且优先于左操作数的排序函数。
如果任一操作数是列,则将优先使用该列的排序函数,优先于左操作数。就上一句而言,前面带有一个或多个一元“+”运算符和/或 CAST 运算符的列名仍被视为列名。
否则,使用 BINARY 排序函数进行比较。
如果比较操作数的任何子表达式使用后缀COLLATE 运算符 ,则认为比较操作数具有显式排序函数分配(上面的规则 1)。因此,如果在比较表达式的任何地方使用 COLLATE 运算符,则无论该表达式中包含哪些表列,都将使用该运算符定义的排序函数进行字符串比较。如果比较中的任何地方出现两个或多个 COLLATE 运算符子表达式,则无论 COLLATE 运算符在表达式中的嵌套深度如何,也无论表达式如何用括号括起来,都将使用最左边的显式排序函数。
表达式“x BETWEEN y and z”在逻辑上等同于两个比较“x >= y AND x <= z”,并且对于排序函数而言,它们的作用就像两个单独的比较一样。表达式“x IN (SELECT y ...)”的处理方式与表达式“x = y”相同,用于确定排序顺序。用于形式为“x IN (y, z, ...)”的表达式的排序顺序是 x 的排序顺序。如果 IN 运算符需要明确的排序顺序,则应将其应用于左操作数,如下所示:“x COLLATE nocase IN (y,z, ...)”。
SELECT语句 中的 ORDER BY 子句的项 可以使用 COLLATE 运算符指定排序顺序,在这种情况下,将使用指定的排序函数进行排序。否则,如果 ORDER BY 子句排序的表达式是列,则将使用该列的排序顺序来确定排序顺序。如果表达式不是列并且没有 COLLATE 子句,则使用 BINARY 排序顺序。
7.2.排序规则示例
以下示例标识了用于确定各种 SQL 语句可能执行的文本比较结果的排序顺序。请注意,对于数字、blob 或 NULL 值,可能不需要进行文本比较,也不使用排序顺序。
CREATE TABLE t1( x INTEGER PRIMARY KEY, a, /* collating sequence BINARY */ b COLLATE BINARY, /* collating sequence BINARY */ c COLLATE RTRIM, /* collating sequence RTRIM */ d COLLATE NOCASE /* collating sequence NOCASE */ ); /* x a b c d */ INSERT INTO t1 VALUES(1,'abc','abc', 'abc ','abc'); INSERT INTO t1 VALUES(2,'abc','abc', 'abc', 'ABC'); INSERT INTO t1 VALUES(3,'abc','abc', 'abc ', 'Abc'); INSERT INTO t1 VALUES(4,'abc','abc ','ABC', 'abc'); /* Text comparison a=b is performed using the BINARY collating sequence. */ SELECT x FROM t1 WHERE a = b ORDER BY x; --result 1 2 3 /* Text comparison a=b is performed using the RTRIM collating sequence. */ SELECT x FROM t1 WHERE a = b COLLATE RTRIM ORDER BY x; --result 1 2 3 4 /* Text comparison d=a is performed using the NOCASE collating sequence. */ SELECT x FROM t1 WHERE d = a ORDER BY x; --result 1 2 3 4 /* Text comparison a=d is performed using the BINARY collating sequence. */ SELECT x FROM t1 WHERE a = d ORDER BY x; --result 1 4 /* Text comparison 'abc'=c is performed using the RTRIM collating sequence. */ SELECT x FROM t1 WHERE 'abc' = c ORDER BY x; --result 1 2 3 /* Text comparison c='abc' is performed using the RTRIM collating sequence. */ SELECT x FROM t1 WHERE c = 'abc' ORDER BY x; --result 1 2 3 /* Grouping is performed using the NOCASE collating sequence (Values ** 'abc', 'ABC', and 'Abc' are placed in the same group). */ SELECT count(*) FROM t1 GROUP BY d ORDER BY 1; --result 4 /* Grouping is performed using the BINARY collating sequence. 'abc' and ** 'ABC' and 'Abc' form different groups */ SELECT count(*) FROM t1 GROUP BY (d || '') ORDER BY 1; --result 1 1 2 /* Sorting or column c is performed using the RTRIM collating sequence. */ SELECT x FROM t1 ORDER BY c, x; --result 4 1 2 3 /* Sorting of (c||'') is performed using the BINARY collating sequence. */ SELECT x FROM t1 ORDER BY (c||''), x; --result 4 2 3 1 /* Sorting of column c is performed using the NOCASE collating sequence. */ SELECT x FROM t1 ORDER BY c COLLATE NOCASE, x; --result 2 4 3 1