SELECT
SQL:SQLite可辨识的语言
【置顶】
SELECT(选择)
select-stmt:
隐藏
common-table-expression:
展示
compound-operator:
展示
expr:
展示
literal-value:
展示
raise-function:
展示
type-name:
展示
signed-number:
展示
join-clause:
展示
join-constraint:
展示
join-operator:
展示
ordering-term:
展示
result-column:
展示
table-or-subquery:
展示
SELECT 语句用于查询数据库,其结果为零行或更多行数据,其中每行具有固定数量的列。 SELECT 语句不会对数据库进行任何更改。
上面的“select-stmt”语法图尝试在单个图中尽可能多地显示 SELECT 语句语法,因为有些读者觉得这很有帮助。不同的是,下面的“因子选择标记”是一种替代的语法图,表示相同的语法,但试图将语法分解为更小的块。
factored-select-stmt:
展示
common-table-expression:
展示
select-stmt:
展示
join-clause:
展示
join-constraint:
展示
join-operator:
展示
result-column:
展示
table-or-subquery:
展示
compound-operator:
展示
expr:
展示
literal-value:
展示
raise-function:
展示
select-stmt:
展示
join-clause:
展示
join-constraint:
展示
join-operator:
展示
result-column:
展示
table-or-subquery:
展示
type-name:
展示
signed-number:
展示
ordering-term:
展示
select-core:
展示
join-clause:
展示
join-constraint:
展示
join-operator:
展示
result-column:
展示
table-or-subquery:
展示
select-stmt:
展示
请注意,通过语法图的路径在实践中是不允许的。
- 在有 WITH 子句的复合 SELECT 语句中,VALUES 子句可以是第一个元素,但是仅由一个 VALUES 子句组成的简单 SELECT 语句不能以 WITH 子句开头。
- WITH 子句必须出现在复合 SELECT 语句的第一个 SELECT 语句中,它不能遵循复合操作符。
这些和其他类似的语法限制在文中有所描述。
SELECT 语句是 SQL 语言中最复杂的命令。为了使描述更容易理解,下面的一些段落将 SELECT 语句返回的数据描述为一系列步骤的方式。需要记住,这纯粹是说明性的 - 实际上 SQLite 和任何其他 SQL 引擎都不需要遵循这个或任何其他特定的过程。
简单的选择处理过程
SELECT 语句的核心是下面的 select-core 和 simple-select-stmt 语法图所示的“简单 SELECT ”。实际上,大多数 SELECT 语句都是简单 SELECT 语句。
simple-select-stmt:
隐藏
common-table-expression:
展示
select-stmt:
展示
compound-operator:
展示
join-clause:
展示
join-constraint:
展示
join-operator:
展示
result-column:
展示
table-or-subquery:
展示
expr:
展示
literal-value:
展示
raise-function:
展示
select-stmt:
展示
compound-operator:
展示
join-clause:
展示
join-constraint:
展示
join-operator:
展示
result-column:
展示
table-or-subquery:
展示
type-name:
展示
signed-number:
展示
ordering-term:
展示
select-core:
隐藏
join-clause:
展示
join-constraint:
展示
join-operator:
展示
result-column:
展示
table-or-subquery:
展示
select-stmt:
展示
compound-operator:
展示
生成一个简单的 SELECT 语句的结果可以在下面的描述中用一个四步过程来呈现:
- FROM 子句处理:确定简单 SELECT 的输入数据。输入数据可以是隐含的单行,包含0列(如果没有 FROM 子句的话)或由 FROM 子句确定。
- WHERE 子句处理:使用 WHERE 子句表达式来筛选输入数据。
- GROUP BY,HAVING 和结果表达式处理:通过任何 GROUP BY 子句聚合数据,并计算筛选输入数据集的行的结果集表达式来计算结果行集合。
- DISTINCT / ALL 关键字处理:如果使用 “SELECT DISTINCT” 查询,则从结果行集合中删除重复行。
有两种简单的 SELECT 语句 —— 聚合和非聚合查询。如果一个简单的 SELECT 语句在结果集中包含 GROUP BY 子句、一个或多个聚合函数,则它是一个聚合查询。否则,如果一个简单的SELECT 不包含集合函数或 GROUP BY 子句,则它是一个非集合查询。
1.确定输入数据( FROM 子句处理)。
一个简单的 SELECT 查询使用的输入数据是一组N
行,每行M
列。
如果从简单的 SELECT 语句中省略 FROM
子句,那么输入数据成为隐式的单行零列宽(即N
= 1且M
= 0)。
如果指定了 FROM 子句,则简单 SELECT 查询操作的数据来自 FROM 关键字后面指定的一个、多个表或子查询(括号中的 SELECT 语句)。在简单 SELECT 语句中的 FROM 子句后面的表或子查询中指定的子查询被处理,就好像它是一个包含通过执行子查询语句返回的数据的表。子查询的每一列都具有子查询语句中相应表达式的排序顺序和亲和性。
如果 FROM 子句中只有一个表或子查询,那么 SELECT 语句使用的输入数据就是指定表的内容。如果 FROM 子句中有多个表或子查询,那么所有表和/或子查询的内容都会连接到一个数据集中的表,以供简单的 SELECT 语句操作。数据的组合方式取决于其用于将表或子查询连接在一起的特定连接运算符和连接约束。
SQLite 中的所有连接均基于左侧和右侧数据集的笛卡尔积。笛卡尔乘积数据集的列依次是左侧数据集的所有列,后面是右侧数据集的所有列。笛卡尔产品数据集中有一行通过组合左侧和右侧数据集中的每一行的唯一组合而形成。换句话说,如果左边的数据集包含 Nleft
列的 Mleft
列和右边的 Nright
列的 Mright
列的数据集,那么笛卡尔乘积是 Nleft×Nright
行的数据集,每行包含 Mleft + Mright
列。
如果连接运算符是“CROSS JOIN”,“INNER JOIN”,“JOIN”或逗号(“,”),并且没有 ON 或 USING 子句,那么连接的结果就是左边的笛卡尔乘积和右手数据集。如果连接运算符具有ON或USING子句,则按照以下要点处理这些子句:
- 如果存在 ON 子句,则 ON 表达式将作为布尔表达式针对笛卡儿积的每一行进行评估。表中只包含表达式为 true 的行。
- 如果存在 USING 子句,那么指定的每个列名都必须存在于数据集中的表中,以连接运算符的左侧和右侧。对于每对命名列,表达式 “lhs.X = rhs.X” 将作为布尔表达式针对笛卡儿积的每一行进行评估,其结果只包含所有这些表达式评估为 true 的行。当比较值作为 USING 子句的结果时,适用于处理亲和度,归类序列和 NULL 值的常规规则。出于排序顺序和关联优先顺序的目的,连接算子左侧的数据集中的列被认为是位于比较运算符(=)的左侧。
对于由 USING 子句标识的每对列,省略连接的数据集中的表中来自右侧数据集的列。这是 USING 子句与其等效 ON 约束之间唯一的区别。
- 如果 NATURAL 关键字位于连接运算符中,则隐式 USING 子句将添加到连接约束中。隐含的 USING 子句包含出现在左侧和右侧输入数据集中的每个列名称。如果左侧和右侧输入数据集没有共同的列名称,则 NATURAL 关键字对连接结果没有影响。 USING 或 ON 子句可能不会添加到指定 NATURAL 关键字的联接中。
- 如果连接操作符是 “LEFT JOIN” 或 “LEFT OUTER JOIN” ,那么在应用 ON 或 USING 过滤条件后,将为原始左侧输入数据集中的每行添加一行额外的行,用于对应复合数据集中的所有行(如果有的话)。添加的行通常包含从右侧输入数据集复制的值的列中包含的 NULL 值。
当两个以上的表作为 FROM 子句的一部分连接在一起时,连接操作按从左到右的顺序进行处理。换句话说, FROM 子句(A join-op-1 B join-op-2 C)变形为((A join-op-1 B)join-op-2 C)。
附注:特殊处理 CROSS JOIN 。
2. WHERE 子句的筛选功能。
如果指定了 WHERE 子句,则将 WHERE 表达式视为布尔表达式,并针对输入数据中的每一行进行求值。在继续之前,只有 WHERE 子句表达式求值为 true 的行才包含在数据集。如果WHERE 子句的计算结果为 false 或 NULL ,则从结果中排除行。
对于 JOIN 或 INNER JOIN 或 CROSS JOIN, WHERE 子句中的约束表达式和 ON 子句中的约束表达式之间没有区别。但是,对于 LEFT JOIN 或 LEFT OUTER JOIN,差别则显得非常重要。在 LEFT JOIN 中,在 ON 子句处理之后,WHERE 子句处理之前,会为右侧表添加额外的NULL行。因此,ON 子句中诸如 “left.x = right.y” 形式的约束将允许通过右表中添加的所有 NULL 行。但如果 WHERE 子句中有相同的约束,则 “right.y”中的 NULL 将阻止表达式 “left.x = right.y” 为真,并因此在输出中排除该行。
3.一组结果行的生成。
一旦来自 FROM 子句的输入数据已经被 WHERE 子句表达式(如果有的话)筛选,简单 SELECT 的结果行集就会被计算出来。具体如何完成取决于简单的 SELECT 是聚合还是非聚合查询,以及是否指定了 GROUP BY 子句。
SELECT 和 FROM 关键字之间的表达式列表被称为结果表达式列表。如果结果表达式是特殊表达式“*”,那么输入数据中的所有列将替代该表达式。如果表达式是 FROM 子句中后跟“.*”的表或子查询的别名,则来自命名表或子查询的所有列将替代单个表达式。在结果表达式列表以外的任何情况中应使用“*”或 “alias.*” 表达式是错误的,在没有 FROM 子句的简单 SELECT 查询中使用“*” 或 “alias.*”表达式也是错误的。
由简单的 SELECT 语句返回的行数中的列数等于替换 * 和 alias.* 表达式后结果表达式列表中的表达式数量。每个结果行都是通过评估结果表达式列表中相对于单行输入数据的表达式来计算的,或是在聚合查询中相对于一组行来计算。
- 如果 SELECT 语句为
非聚合查询
,则结果表达式列表中的每个表达式都对 WHERE 子句筛选的数据集里的每一行进行求值。
- 如果SELECT语句为
不含 GROUP BY
子句的聚合查询
,则结果集里的每个聚合表达式将在整个数据集中被评估一次。结果集里的每个非集合表达式都会针对数据集的任意选定行进行一次评估。每个非聚合表达式都使用相同的任意选择的行。或者,如果数据集包含零行,则将针对完全由 NULL 值组成的行评估每个非聚合表达式。
通过评估结果集里的聚合和非聚合表达式创建的单行结果集数据,可以形成不带 GROUP BY 子句的聚合查询的结果。即使输入数据为零行,没有 GROUP BY 子句的聚合查询总是只返回一行数据。
- 如果SELECT语句是
具有 GROUP BY
子句的聚合查询
,则对数据集的每一行进行评估,指定为 GROUP BY 子句一部分的每个表达式。然后根据结果将每行分配给一个“组”; 评估GROUP BY 表达式的结果相同的行被赋值给同一组。为了对行进行分组,NULL 值被认为是相等的。在计算 GROUP BY 子句中的表达式时,适用于选择用于比较文本值的归类序列的常用规则。GROUP BY 子句中的表达式不包含
必须是结果中出现的表达式。 GROUP BY 子句中的表达式可能不是聚合表达式。如果指定了 HAVING 子句,那么对于每个行组,它将作为布尔表达式计算一次。如果评估 HAVING 子句的结果为假,则该组将被丢弃。如果 HAVING 子句是一个聚合表达式,它将在组中的所有行上进行评估。如果 HAVING 子句是非集合表达式,那么它将根据组中任意选择的行进行评估。HAVING 表达式可能引用不在结果中的值,甚至集合函数。然后对每组行中的每个表达式计算一次结果集。如果表达式是一个聚合表达式,它将在组中的所有行上进行评估。除此以外,它将根据组内的单个任意选择的行进行评估。如果结果集中有多个非聚集表达式,则对同一行计算所有这些表达式。每组输入数据集行对结果行集贡献一行。根据与 DISTINCT 关键字相关的过滤条件,具有 GROUP BY
子句的聚合查询
返回的行数与通过将 GROUP BY 和 HAVING 子句应用于过滤后的输入数据集所产生的行数组相同。
- 如果 ORDER BY 表达式是一个常量整数K,则该表达式将被视为结果集的第K列的别名(列从1开始从左到右编号)。
- 如果ORDER BY表达式是与其中一个输出列的别名相对应的标识符,则该表达式将被视为该列的别名。
- 否则,如果ORDER BY表达式是任何其他表达式,则会对其进行求值并返回用于排序输出行的值。如果SELECT语句是一个简单的SELECT,那么一个ORDER BY可以包含任意的表达式。但是,如果SELECT是复合SELECT,那么非输出列的别名的ORDER BY表达式必须与用作输出列的表达式完全相同。
为了对行进行排序,值的比较方式与比较表达式相同。用于比较两个文本值的排序顺序的方式如下:
1.如果使用后缀COLLATE运算符为ORDER BY表达式分配归类序列,则使用指定的归类序列。
2.否则,如果ORDER BY表达式是已使用后缀COLLATE运算符分配了归类序列的表达式的别名,则将使用分配给别名表达式的归类序列。
3.否则,如果ORDER BY表达式是作为列的表达式的列或别名,则使用该列的默认归类序列。
4.否则,使用BINARY整理序列。
在复合SELECT语句中,所有ORDER BY表达式都将作为复合结果列的别名进行处理。如果一个ORDER BY表达式不是一个整数别名,那么SQLite搜索复合集里最左边的SELECT,以得到匹配上面第二个或第三个规则的结果列。如果找到匹配项,则停止搜索,并将该表达式作为已匹配的结果列的别名进行处理。否则,尝试右边的下一个SELECT,依此类推。如果在任何组成SELECT的结果列中找不到匹配的表达式,则为错误。ORDER BY子句的每个术语都是单独处理的,并且可以与复合集里不同SELECT语句的结果列进行匹配。
LIMIT子句
LIMIT子句用于放置整个SELECT语句返回的行数的上限。
在复合SELECT中,只有最后一个或最右侧的简单SELECT可以包含LIMIT子句。在复合SELECT中,LIMIT子句适用于整个复合集,而不仅仅是最终的SELECT。如果最右边的简单SELECT是一个VALUES子句,则不允许LIMIT子句。
任何标量表达式都可以在 LIMIT 子句中使用,只要它计算为一个整数或一个可以无损地转换为整数的值。如果表达式求值为 NULL 值或任何其他不能无损地转换为整数的值,则返回错误。如果LIMIT表达式求值为负值,那么返回的行数没有上限。否则,SELECT 仅返回结果集的前N行,其中N是 LIMIT 表达式求值的值。或者,如果 SELECT 语句返回少于 N 行而没有 LIMIT 子句,则返回整个结果集。
附加到可能遵循 LIMIT 子句的可选 OFFSET 子句的表达式还必须转变为整数或可以无损地转换为整数的值。如果表达式具有 OFFSET 子句,则前面的M行将从 SELECT 语句返回的结果集里省略,并返回N个行,其中M和N分别是 OFFSET 和 LIMIT 子句求值的值。或者,如果 SELECT 没有 LIMIT 子句将返回少于M + N行,则跳过前M行,并返回其余行(如果有)。如果OFFSET 子句的计算结果为负值,则结果与计算结果相同,都为0。
LIMIT 子句可以指定两个由逗号分隔的标量表达式,而不是单独的 OFFSET 子句。在这种情况下,第一个表达式用作 OFFSET 表达式,第二个表达式用作 LIMIT 表达式。这是不合理的,因为当使用 OFFSET 子句时,两个表达式中的第二个是 OFFSET ,第一个是 LIMIT 。这种偏移和极限的反转是有意的 - 它最大限度地提高了与其他SQL数据库系统的兼容性。但是,为避免混淆,强烈建议程序员使用带 “OFFSET” 关键字的 LIMIT 子句的形式,并避免使用有带逗号分隔的偏移量的 LIMIT 子句。
VALUES 子句
语句 “VALUES(expr-list
)”与 “SELECT expr-list
” 意思相同。语句 “VALUES(expr-list-1
),...,(expr-list-N
)”意思与 “SELECT expr-list-1
UNION ALL ... UNION ALL SELECT expr-list-N
”相同,只是复合中的 SELECT 语句的数量受 SQLITE_LIMIT_COMPOUND_SELECT 限制,而 VALUES 子句中的行数没有任何限制。
使用语法图中未显示的 VALUES 子句有如下限制:
- ORDER BY 后面不能有 VALUES 子句。
- VALUES 子句后不能有 LIMIT。
WITH子句
SELECT 语句可以有选择地出现在单个 WITH 子句之前,该子句定义一个或多个在 SELECT 语句中使用的公用表表达式。
FROM 子句中的表值函数
包含隐藏列的虚拟表可以像 FROM 子句中的表值函数一样使用。表值函数的参数成为虚拟表的 HIDDEN 列上的约束。其他信息可以在虚拟表格文档中找到。
SQLite is in the Public Domain.