SELECT
SELECT
从表或视图中检索行。
语法
1 [ WITH [ RECURSIVE1 ] with_query [, ...] ]
2 SELECT [ALL | DISTINCT [ON (expression [, ...])]]
3 * | expression[[AS] output_name] [, ...]
4 [FROM from_item [, ...]]
5 [WHERE condition]
6 [GROUP BY grouping_element [, ...]]
7 [HAVING condition [, ...]]
8 [WINDOW window_name AS (window_definition) [, ...] ]
9 [{UNION | INTERSECT | EXCEPT} [ALL | DISTINCT] select]
10 [ORDER BY expression [ASC | DESC | USING operator] [NULLS {FIRST | LAST}] [, ...]]
11 [LIMIT {count | ALL}]
12 [OFFSET start [ ROW | ROWS ] ]
13 [FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY]
14 [FOR {UPDATE | NO KEY UPDATE | SHARE | KEY SHARE} [OF table_name [, ...]] [NOWAIT] [...]]
15
16 TABLE { [ ONLY ] table_name [ * ] | with_query_name }
17
18 ```
19
20 其中`with_query:`是:
21
22 ``` sql
23 with_query_name [( column_name [, ...] )] AS ( select | values | insert | update | delete )
24 ```
25
26 其中`from_item`可以是以下之一:
27
28 ``` sql
29 [ONLY] table_name [ * ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
30 ( select ) [ AS ] alias [( column_alias [, ...] ) ]
31 with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
32 function_name ( [ argument [, ...] ] )
33 [ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
34 function_name ( [ argument [, ...] ] ) [ AS ] alias ( column_definition [, ...] )
35 function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )
36 ROWS FROM( function_name ( [ argument [, ...] ] ) [ AS ( column_definition [, ...] ) ] [, ...] )
37 [ WITH ORDINALITY ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ]
38 from_item [ NATURAL ] join_type from_item
39 [ ON join_condition | USING ( join_column [, ...] ) ]
40 ```
41
42 其中`grouping_element`可以是以下之一:
43
44 ``` sql
45 ()
46 expression
47 ROLLUP (expression [,...])
48 CUBE (expression [,...])
49 GROUPING SETS ((grouping_element [, ...]))
50 ```
51
52 其中`window_definition`是:
53
54 ``` sql
55 [existing_window_name]
56 [PARTITION BY expression [, ...]]
57 [ORDER BY expression [ASC | DESC | USING operator]
58 [NULLS {FIRST | LAST}] [, ...]]
59 [{ RANGE | ROWS} frame_start
60 | {RANGE | ROWS} BETWEEN frame_start AND frame_end]
61 ```
62
63
64 其中`frame_start`和`frame_end`可以是以下之一:
65
66 ``` sql
67 UNBOUNDED PRECEDING
68 value
69 PRECEDING
70 CURRENT ROW
71 value
72 FOLLOWING
73 UNBOUNDED FOLLOWING
74 ```
75
76
77
78
79## 描述
80
81`SELECT`从零个或多个表中检索行。 `SELECT`的一般处理如下:
82
83
84 1. `WITH`子句中的所有查询均被计算。 这些可以有效地用作可以在`FROM`列表中引用的临时表。
85
86 2. 将计算`FROM`列表中的所有元素。(`FROM`列表中的每个元素都是真实表或虚拟表。) 如果`FROM`列表中指定了多个元素,则它们将交叉连接在一起。
87
88 3. 如果指定了`WHERE`子句,则从输出中排除所有不满足该条件的行。
89
90 4. 如果指定了`GROUP BY`子句,或者存在聚合函数调用,则将输出组合为与一个或多个值匹配的行组,并计算聚合函数的结果。如果存在`HAVING`子句,它将排除不满足给定条件的组。
91
92 5. 实际的输出行是使用`SELECT`输出表达式为每个选定的行或行组计算的。
93
94 6. `SELECT DISTINCT`从结果中消除重复的行。 `SELECT DISTINCT ON`消除与所有指定表达式匹配的行。`SELECT ALL`(默认)将返回所有候选行,包括重复项。
95
96 7. 如果指定了窗口表达式(和可选的`WINDOW`子句),则根据位置(行)或基于值的(范围)窗口框架来组织输出。
97
98 8. 使用每个选定行的`SELECT`输出表达式来计算实际的输出行。
99
100 9. 使用运算符`UNION`,`INTERSECT`和`EXCEPT`,可以组合多个`SELECT`语句的输出以形成单个结果集。
101
102 `UNION`运算符返回一个或两个结果集中的所有行。
103
104 `INTERSECT`运算符返回完全位于两个结果集中的所有行。
105
106 `EXCEPT`运算符返回第一个结果集中的行,而不是第二个结果集中的行。
107
108 在所有三种情况下,除非指定了`ALL`,否则将消除重复的行。
109
110 可以添加噪声字`DISTINCT`来明确指定消除重复行。
111
112 请注意,`DISTINCT`是此处的默认行为,即使`ALL`是`SELECT`本身的默认行为。
113
114 10. 如果指定了`ORDER BY`子句,则返回的行将以指定的顺序排序。如果未给出`ORDER BY`,则以系统最先找到的顺序返回行。
115
116 11. 如果指定了`LIMIT`(或`FETCH FIRST`)或`OFFSET`子句,则`SELECT`语句仅返回结果行的子集。
117
118 12. 如果指定了`FOR UPDATE`,`FOR NO KEY UPDATE`,`FOR SHARE`或`FOR KEY SHARE`,则`SELECT`语句将锁定整个表以防止并发更新。
119
120 必须对`SELECT`命令中使用的每一列都具有`SELECT`权限。 使用`FOR NO KEY UPDATE`,`FOR UPDATE`,`FOR SHARE`或`FOR KEY SHARE`也需要`UPDATE`权限(对于这样选择的每个表的至少一列)。
121
122
123
124## 参数
125
126该SQL命令参数说明见下
127
128 * **WITH子句**
129
130 可选的`WITH`子句允许您指定一个或多个子查询,这些子查询可以在主查询中按名称引用。 子查询在主查询期间有效地充当临时表或视图。每个子查询可以是`SELECT`,`INSERT`,`UPDATE`或`DELETE`语句。在用`WITH`编写数据修改语句(`INSERT`,`UPDATE`或`DELETE`)时,通常会包含`RETURNING`子句。它是`RETURNING`的输出,而不是该语句修改的基础表,形成了由主查询读取的临时表。如果省略`RETURNING`,则该语句仍将执行,但是不会产生任何输出,因此主查询无法将其引用为表。
131
132 对于包含`WITH`子句的`SELECT`命令,该子句最多可以包含一个用于修改表数据的子句(`INSERT`,`UPDATE`或`DELETE`命令)。
133
134 必须为`WITH`子句中的每个查询指定一个无schema限定的`with_query_name`。(可选)可以指定列名列表;如果省略列名列表,则从子查询中推断出名称。主查询和`WITH`查询都(理论上)同时执行。
135
136 如果指定了`RECURSIVE`,则它允许`SELECT`子查询按名称引用自己。 这样的子查询具有一般形式
137
138 ``` sql
139 non_recursive_term UNION [ALL | DISTINCT] recursive_term
140 ```
141
142 递归自引用出现在`UNION`的右侧。 每个查询仅允许一个递归自引用。不支持递归数据修改语句,但是您可以在数据修改语句中使用递归`SELECT`查询的结果。
143
144 如果指定了`RECURSIVE`关键字,则无需对`WITH`查询进行排序:一个查询可以引用列表中后面的另一个查询。但是,不支持循环引用或相互递归。
145
146 如果没有`RECURSIVE`关键字, 则`WITH`查询只能引用`WITH`列表中较早的同级`WITH`查询。
147
148 `WITH RECURSIVE`限制。不支持这些项目:
149
150 - 一个递归`WITH`子句,在`recursive_term`中包含以下内容。
151
152 - 具有自引用的子查询
153
154 - `DISTINCT` 子句
155
156 - `GROUP BY` 子句
157
158 - 窗口函数
159
160 - 递归`WITH`子句,其中`with_query_name`是集合操作的一部分。
161
162
163 以下是集合操作限制的示例。 该查询返回错误,因为集合操作`UNION`包含对表`foo`的引用。
164
165 ``` sql
166 WITH RECURSIVE foo(i) AS (
167 SELECT 1
168 UNION ALL
169 SELECT i+1 FROM (SELECT * FROM foo UNION SELECT 0) bar
170 )
171 SELECT * FROM foo LIMIT 5;
172 ```
173
174
175
176 由于集合操作`UNION`没有对CTE `foo`的引用,因此允许此递归CTE。
177
178 ``` sql
179 WITH RECURSIVE foo(i) AS (
180 SELECT 1
181 UNION ALL
182 SELECT i+1 FROM (SELECT * FROM bar UNION SELECT 0) bar, foo
183 WHERE foo.i = bar.a
184 )
185 SELECT * FROM foo LIMIT 5;
186 ```
187
188
189 `WITH`查询的一个关键属性是,即使主查询多次引用它们,一次执行主查询也只会对它们进行一次评估。特别是,无论主查询是读取全部输出还是输出任何内容,都保证数据修改语句仅执行一次。
190
191 主查询和`WITH`查询都(理论上)同时执行。这意味着,除了通过读取其`RETURNING`输出之外,不能从查询的其他部分看到`WITH`中的数据修改语句的效果。如果两个这样的数据修改语句试图修改同一行,则结果不确定。
192
193
194
195
196 * **SELECT列表**
197
198 `SELECT`列表(在关键字`SELECT`和`FROM`之间)指定用于形成`SELECT`语句输出行的表达式。表达式可以(通常)引用`FROM`子句中计算的列。
199
200 `SELECT`列表中的`expression`可以是常量值,列引用,运算符调用,函数调用,聚合表达式,窗口表达式,标量子查询等。可以将许多结构体归类为表达式,但不遵循任何常规语法规则。 这些通常具有函数或运算符的语义。有关SQL值表达式和函数调用的信息,请参阅*PalopgMPP数据库管理员指南*中的“查询数据”。
201
202 就像在表中一样,`SELECT`的每个输出列都有一个名称。 在简单的`SELECT`中,此名称仅用于标记要显示的列,但是当`SELECT`是较大查询的子查询时,该名称在较大查询中被视为由该子查询生成的虚拟表的列名。要指定用于输出列的名称,请在该列的表达式之后写入`AS` `output_name`。(您可以省略`AS`,但只有在所需的输出名称与任何SQL关键字都不匹配时才可以使用。为防止将来可能再添加关键字,您始终可以写`AS`或在输出名称中用双引号。)如果不指定列名称,PalopgMPP数据库自动选择一个名称。 如果列的表达式是简单的列引用,则所选名称与该列的名称相同。在更复杂的情况下,可以使用函数或类型名称,或者系统可能会依赖生成的名称(例如`?column?`或`columnN`)。
203
204 输出列的名称可用于引用`ORDER BY`和`GROUP BY`子句中的列的值, 但不能用于`WHERE`或`HAVING`子句中。在那里,必须写出表达式。
205
206 可以将`*`而不是表达式写到输出列表,作为所选行的所有列的简写。 另外,您可以编写`table_name.*`作为仅来自该表的列的简写。在这种情况下,无法使用`AS`指定新名称。 输出列名称将与表列名称相同。
207
208
209
210 * **DISTINCT子句**
211
212 如果指定了`SELECT DISTINCT`,则将从结果集中删除所有重复的行(每组重复项中保留一行)。 `SELECT ALL`则相反:所有行都保留;这是默认值。
213
214
215 `SELECT DISTINCT ON ( expression [, ...] )`仅保留给定表达式等于的每组行的第一行。 使用与`ORDER BY`相同的规则来解释`DISTINCT ON`表达式(请参见上文)。 请注意,除非使用`ORDER BY`来确保所需的行最先出现,否则每个集合的“第一行”都是不可预测的。
216
217 例如:
218
219 ``` sql
220 SELECT DISTINCT ON (location) location, time, report
221 FROM weather_reports
222 ORDER BY location, time DESC;
223 ```
224
225 检索每个位置的最新天气报告。 但是,如果我们没有使用`ORDER BY`强制每个位置的时间值按降序排列,那么我们将从每个位置不可预测的时间获得报告。
226
227
228 `DISTINCT ON`表达式必须与最左边的`ORDER BY`表达式匹配。 `ORDER BY`子句通常将包含附加表达式,这些表达式确定每个`DISTINCT ON`组中所需的行优先级。
229
230
231
232 * **FROM子句**
233
234 `FROM`子句为`SELECT`指定一个或多个源表。 如果指定了多个源,则结果为所有源的笛卡尔乘积(交叉连接)。但通常会添加限定条件(通过`WHERE`),以将返回的行限制为笛卡尔乘积的一小部分。
235
236 `FROM`子句可以包含以下元素:
237
238
239 `table_name`
240 : 现有表或视图的名称(可以有schema修饰)。 如果指定`ONLY`,则仅扫描该表。如果未指定`ONLY`,则扫描该表及其所有子表(如果有)。
241
242 `alias`
243 : 包含别名的`FROM`项目的替代名称。 别名用于简洁起见或用于消除自连接的歧义(多次扫描同一张表)。提供别名后,它将完全隐藏表或函数的实际名称。例如,在给定`FROM foo AS f`的情况下,`SELECT`的其余部分必须将此`FROM`项目引用为`f`而不是`foo`。如果写入了别名,则还可以写入列别名列表以为表的一个或多个列提供替代名称。
244
245 `select`
246 : 子`SELECT`可以出现在`FROM`子句中。 这就像在单个`SELECT`命令期间将其输出创建为临时表一样。请注意,子`SELECT`必须用括号括起来,并且必须为其提供别名。 `VALUES`命令也可以在这里使用。
247
248 `with_query_name`
249 : 通过指定其`with_query_name`在`FROM`子句中引用`with_query`,就像该名称是表名一样。`with_query_name`不能包含schema限定符。 可以使用与表相同的方式提供别名。`with_query`隐藏用于主查询目的的同名表。 如有必要,可以通过使用schema限定表名来引用相同名称的表。
250
251 `function_name`
252 : 函数调用可以出现在`FROM`子句中。 (这对于返回结果集的函数特别有用,但是可以使用任何函数。)这就像在单个`SELECT`命令期间将其输出创建为临时表一样。 也可以使用别名。
253
254 如果编写了别名,则还可以编写列别名列表,以为函数的复合返回类型的一个或多个属性提供替代名称。
255
256 如果已将函数定义为返回记录数据类型,则必须存在别名或关键字`AS`,然后是形式为`(column_name data_type [, ... ] )`的列定义列表。列定义列表必须匹配该函数返回的实际列数和类型。
257
258 `join_type`
259 : 以下之一:
260
261 * **\[INNER\] JOIN**
262
263 * **LEFT \[OUTER\] JOIN**
264
265 * **RIGHT \[OUTER\] JOIN**
266
267 * **FULL \[OUTER\] JOIN**
268
269 * **CROSS JOIN**
270
271 对于`INNER`和`OUTER`连接类型,必须指定一个连接条件, 即恰好是`NATURAL`,`ON join_condition`或`USING (join_column[, ...])`之一。 含义如下。 对于`CROSS JOIN`,这些子句都不会出现。
272
273 JOIN子句结合了两个`FROM`项,为方便起见,我们将其称为“表”, 尽管实际上它们可以是任何类型的`FROM`项。如有必要,请使用括号确定嵌套顺序。 在没有括号的情况下,`JOIN`从左到右嵌套。无论如何,`JOIN`的绑定比逗号分隔`FROM`列表项的绑定更紧密。
274
275 `CROSS JOIN`和`INNER JOIN`产生一个简单的笛卡尔积,与在`FROM`的顶层列出两个表所获得的结果相同,但受连接条件(如果有)的限制。`CROSS JOIN`等效于`INNER JOIN ON` `(TRUE)`,即,没有行被限定删除。
276
277 这些连接类型只是一种符号上的方便,因为它们无法执行普通`FROM`和`WHERE`无法完成的工作。
278
279 `LEFT OUTER JOIN`返回合格的笛卡尔乘积中的所有行(即,所有通过其连接条件的组合行),加上左表中没有通过右表连接条件的每行的一个副本。通过为右侧列插入空值,此左侧行将扩展为连接表的整个宽度。请注意,在确定哪些行具有匹配项时,仅考虑`JOIN`子句自身的条件。之后应用外部条件。
280
281 相反,`RIGHT OUTER JOIN`返回所有已连接的行,并为每个不匹配的右手行加上一行(在左边扩展为空)。这只是一种符号上的便利,因为您可以通过切换左右表将其转换为`LEFT OUTER JOIN`。
282
283 `FULL OUTER JOIN`返回所有连接的行,再加上一行,用于每行不匹配的左表行(在右边扩展为空),再加上每行不匹配的右表行(扩展在左边为空)。
284
285 ON `join_condition`
286 : `join_condition`是一个表达式,其结果为`boolean`类型的值(类似于`WHERE`子句),该值指定连接中的哪些行被视为匹配。
287
288 USING (`join_column` \[, ...\])
289 : `USING ( a, b, ... )`形式的子句是`ON left_table.a = right_table.a AND left_table.b = right_table.b ...`的简写。同样,`USING`意味着连接输出中将仅包括每对等效列中的一对,而不是两者。
290
291 NATURAL
292 : `NATURAL`是`USING`列表的简写形式,该列表提到两个表中具有相同名称的所有列。如果没有公用的列名,则`NATURAL`等效于`ON TRUE`。
293
294
295
296 * **WHERE子句**
297
298 可选的`WHERE`子句具有一般形式:
299
300 ``` sql
301 WHERE condition
302 ```
303
304 `condition`是任何计算结果为`boolean`型结果的表达式。 任何不满足此条件的行将从输出中删除。如果用一行的实际值替换其中的变量引用后,该表达式返回真,则该行符合条件。
305
306
307
308 * **GROUP BY子句**
309
310 可选的`GROUP BY`子句具有一般形式:
311
312 ``` sql
313 GROUP BY grouping_element[, ...]
314 ```
315
316 其中`grouping_element`可以是以下之一:
317
318 ``` sql
319 ()
320 expression
321 ROLLUP (expression [,...])
322 CUBE (expression [,...])
323 GROUPING SETS ((grouping_element [, ...]))
324 ```
325
326 `GROUP BY`将所有共享有相同值的分组表达式的所有选定行压缩为单行。`expression`可以是输入列名称,也可以是输出列(`SELECT`列表项)的名称或序号,或者是由输入列值组成的任意表达式。如有歧义,`GROUP BY`名称将被解释为输入列名称,而不是输出列名称。
327
328 汇总函数(如果有的话)在组成每个组的所有行中进行计算,从而为每个组生成单独的值。 (如果有聚合函数但没有`GROUP BY`子句,则该查询被视为具有包含所有选定行的单个组。)可以通过将`FILTER`子句附加到聚合函数调用来进一步过滤提供给每个聚合函数的行集。如果存在`FILTER`子句,则只有与之匹配的那些行才包含在该聚合函数的输入中。
329
330 如果存在`GROUP BY`或任何聚合函数,则`SELECT`列表表达式不能引用未分组的列,除非是在聚合函数内,或者当未分组的列在函数上依赖于分组的列时,否则对于未分组的列将会返回不止一个的可能的值。如果分组的列(或其子集)是包含未分组的列的表的主键,则存在函数依赖。
331
332 请记住,在评估`HAVING`子句或`SELECT`列表中的任何“标量”表达式之前,将评估所有聚合函数。
333
334
335 PalopgMPP数据库具有以下附加的OLAP分组扩展(通常称为*supergroups*):
336
337 ROLLUP
338 : `ROLLUP`分组是对`GROUP BY`子句的扩展,该子句创建聚合部分和,该部分和从最详细的级别汇总到总计,并遵循分组列(或表达式)的列表。`ROLLUP`提取分组列的有序列表,计算在`GROUP BY`子句中指定的标准聚合值,然后逐步创建更高级别的部分和,从列表的右向左移动。最后,它创建了一个总计。 可以将`ROLLUP`分组视为一系列分组集。 例如:
339
340 ``` sql
341 GROUP BY ROLLUP (a,b,c)
342 ```
343
344 等效于:
345
346 ``` sql
347 GROUP BY GROUPING SETS( (a,b,c), (a,b), (a), () )
348 ```
349
350 请注意,`ROLLUP`的`n`个元素转换为`n + 1`个分组集。 同样,在`ROLLUP`中指定分组表达式的顺序也很重要。
351
352 CUBE
353 : `CUBE`分组是对`GROUP BY`子句的扩展,它为分组列(或表达式)的给定列表的所有可能组合创建部分和。在多维分析方面,`CUBE`生成可以为具有指定维的多维数据集计算的所有部分和。 例如:
354
355 ``` sql
356 GROUP BY CUBE (a,b,c)
357 ```
358
359 等效于:
360
361 ``` sql
362 GROUP BY GROUPING SETS( (a,b,c), (a,b), (a,c), (b,c), (a),
363 (b), (c), () )
364 ```
365
366 注意,`CUBE`的`n`个元素转换为2n个分组集。 考虑在需要交叉表报告的任何情况下使用`CUBE`。`CUBE`通常最适合使用多个维度列而不是表示单个维度不同级别的列的查询。例如,通常要求的交叉列表可能需要月份,州和产品的所有组合的部分和。
367 GROUPING SETS
368 : 可以使用`GROUP BY`子句中的`GROUPING SETS`表达式有选择地指定要创建的组集。这样就可以在多个维度上进行精确指定,而无需计算整个`ROLLUP`或`CUBE`。
369
370 例如:
371
372 ``` sql
373 GROUP BY GROUPING SETS( (a,c), (a,b) )
374 ```
375
376 如果使用分组扩展子句`ROLLUP`,`CUBE`或`GROUPING SETS`,则要面临两个问题。首先,如何确定哪些结果行是部分和,然后确定给定部分和的确切聚合级别。或者,如何区分包含存储的`NULL`值和由`ROLLUP`或`CUBE`创建的“NULL”值的结果行。 其次,当在`GROUP BY`子句中指定重复的分组集时,如何确定哪些结果行是重复的?可以在`SELECT`列表中使用两个附加的分组函数来帮助解决此问题:
377
378 * **grouping(column \[, ...\])** — 可以将`grouping`函数应用于一个或多个分组属性,以将超聚合的行与常规的分组的行区分开。这有助于将代表超级汇总行中所有值的集合的“NULL”与常规行中的`NULL`值区分开。此函数中的每个参数都产生一个位 - `1`或`0`, 其中`1`表示结果行是超级聚合的,而`0`表示结果行来自常规分组。`grouping`函数通过将这些位视为二进制数然后将其转换为以10为基的整数来返回整数。
379
380 * **group_id()** — 对于包含重复分组集的分组扩展查询,`group_id`函数用于标识输出中的重复行。所有唯一分组集输出的唯一行的group_id值为0。对于每个检测到的重复分组集,`group_id`函数分配的group_id编号大于0。特定重复分组集中的所有输出行均由相同的group_id编号标识。
381
382
383
384 * **WINDOW子句**
385
386 可选的`WINDOW`子句指定出现在查询的`SELECT`列表或`ORDER BY`子句中的窗口函数的行为。这些函数可以在其`OVER`子句中按名称引用`WINDOW`子句条目。但是,`WINDOW`子句条目不必在任何地方引用。 如果查询中未使用它,则将其忽略。可以根本不使用任何`WINDOW`子句来使用窗口函数,因为窗口函数调用可以直接在其`OVER`子句中指定其窗口定义.但是,当多个窗口函数需要相同的窗口定义时,`WINDOW`子句将保存键入内容。
387
388 例如:
389
390 ``` sql
391 SELECT vendor, rank() OVER (mywindow) FROM sale
392 GROUP BY vendor
393 WINDOW mywindow AS (ORDER BY sum(prc*qty));
394 ```
395
396 `WINDOW`子句具有以下一般形式:
397
398 ``` sql
399 WINDOW window_name AS (window_definition)
400 ```
401
402 其中`window_name`是可以从`OVER`子句或后续窗口定义中引用的名称, 而`window_definition`为:
403
404 ``` sql
405 [existing_window_name]
406 [PARTITION BY expression [, ...]]
407 [ORDER BY expression [ASC | DESC | USING operator] [NULLS {FIRST | LAST}] [, ...] ]
408 [frame_clause]
409 ```
410
411 `existing_window_name`
412 : 如果指定了`existing_window_name`,则它必须引用`WINDOW`列表中的较早条目;新窗口将复制该条目的分区子句以及其排序子句(如果有)。新窗口不能指定自己的`PARTITION BY`子句,只有复制的窗口没有该子句时,它才能指定`ORDER BY`。 新窗口始终使用其自己的frame子句;复制的窗口不得指定frame子句。
413
414 PARTITION BY
415 : `PARTITION BY`子句根据指定表达式的唯一值将结果集组织为逻辑组。 `PARTITION BY`子句的元素的解释方式与`GROUP BY`子句的元素几乎相同,不同之处在于它们始终是简单表达式,而不是输出列的名称或编号。另一个区别是这些表达式可以包含聚合函数调用,这在常规`GROUP BY`子句中是不允许的。 在此处允许使用它们,因为窗口在分组和聚合之后发生。
416
417 与窗口函数一起使用时,这些函数将分别应用于每个分区。
418
419 例如,如果在`PARTITION BY`之后加上列名,则结果集将按该列的不同值进行分区。 如果省略,则将整个结果集视为一个分区。
420
421 同样,`ORDER BY`列表中的元素的解释方式与`ORDER BY`子句中的元素几乎相同,不同之处在于,始终将表达式视为简单表达式,而不使用输出列的名称或编号。
422
423 ORDER BY
424 : `ORDER BY`子句的元素定义如何对结果集的每个分区中的行进行排序。 如果省略,则以最有效的顺序返回行,并且行可能会有所不同。**注意:**缺少一致顺序(例如`time`)的数据类型的列不是在窗口规范的`ORDER BY`子句中使用的良好候选对象。带有或不带有时区的时间缺乏连贯的排序,因为加法和减法没有预期的效果。 例如,以下条件通常不成立:`x::time < x::time + '2 hour'::interval`
425
426 `frame_clause`
427 : 可选的`frame_clause`定义依赖于框架的窗口函数的窗口框架(并非全部如此)。窗口框架是查询的每一行(称为当前行)的一组相关行。
428
429 `frame_clause`可以是以下之一
430
431 ``` sql
432 { RANGE | ROWS } frame_start
433 { RANGE | ROWS } BETWEEN frame_start AND frame_end
434 ```
435
436 其中`frame_start`和`frame_end`可以是以下之一:
437
438 - `UNBOUNDED PRECEDING`
439
440 - `value PRECEDING `
441
442 - `CURRENT ROW`
443
444 - `value FOLLOWING `
445
446 - `UNBOUNDED FOLLOWING`
447
448 如果省略`frame_end`,则默认为`CURRENT ROW`。 限制条件是`frame_start`不能为`UNBOUNDED FOLLOWING`, `frame_end`不能为`UNBOUNDED PRECEDING`,并且`frame_end`选择不能在上述列表中出现在`frame_start`选择之前 — 例如,`RANGE BETWEEN CURRENT ROW AND value PRECEDING`是不允许的。
449
450 默认的框架选项是`RANGE UNBOUNDED PRECEDING`,与`RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`之间的范围相同;它将框架设置为从分区开始到当前行的最后一个对等方的所有行(`ORDER BY`的行认为与当前行等效,如果没有`ORDER BY`则为所有行)。 通常,`UNBOUNDED PRECEDING`表示框架以分区的第一行开始, 类似地`UNBOUNDED FOLLOWING`表示框架以分区的最后一行结束(与`RANGE`或`ROWS`模式无关)。
451
452 在`ROWS`模式下,`CURRENT ROW`表示框架以当前行开始或结束;但是在`RANGE`模式下,这意味着框架以`ORDER BY`顺序中当前行的第一个或最后一个对等点开始或结束。
453
454 当前仅在`ROWS`模式下允许`value` `PRECEDING`和`value` `FOLLOWING`情况。 它们指示框架以当前行之前或之后许多行的行开始或结束。
455
456 `value`必须是不包含任何变量,聚合函数或窗口函数的整数表达式。该值不能为null或负数;但它可以为零,从而选择当前行本身。
457
458 请注意,如果`ORDER BY`排序不能唯一地对行进行排序,则`ROWS`选项可能会产生不可预测的结果。`RANGE`选项旨在确保以相同的方式对待在`ORDER BY`顺序中为对等的行;所有对等行将在同一框架中。
459
460 使用`ROWS`或`RANGE`子句来表示窗口的边界。 窗口边界可以是一个分区的一行,多行或所有行。可以用偏移当前行值的数据值范围(`RANGE`)或偏移当前行的行数(`ROWS`)来表示窗口的边界。使用`RANGE`子句时,还必须使用`ORDER BY`子句。 这是因为为生成窗口而执行的计算需要对值进行排序。 此外,`ORDER BY`子句不能包含多个表达式,并且该表达式必须导致日期或数字值。使用`ROWS`或`RANGE`子句时,如果仅指定起始行,则当前行将用作窗口中的最后一行。
461
462 **PRECEDING** — `PRECEDING`子句使用当前行作为参考点定义窗口的第一行。 起始行以当前行之前的行数表示。例如,对于`ROWS`框架,`5 PRECEDING`设置窗口从当前行之前的第五行开始。对于`RANGE`框架,它将窗口设置为从第一行开始,其排序列值在给定顺序比当前行的顺序高5。如果指定的顺序按日期升序,则它将是当前行之前5天内的第一行。 `UNBOUNDED PRECEDING`将窗口中的第一行设置为分区中的第一行。
463
464 **BETWEEN** — `BETWEEN`子句使用当前行作为参考点定义窗口的第一行和最后一行。第一行和最后一行分别用当前行之前和之后的行数表示。例如,`BETWEEN 3 PRECEDING AND 5 FOLLOWING`将窗口设置为从当前行之前的第三行开始,到当前行之后的第五行结束。使用`BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING`,可以将窗口中的第一行和最后一行分别设置为分区的第一行和最后一行。如果未指定`ROW`或`RANGE`子句,则等效于默认行为。
465
466 **FOLLOWING** — FOLLOWING子句使用当前行作为参考点定义窗口的最后一行。 最后一行以当前行之后的行数表示。例如,对于`ROWS`框架,`5 FOLLOWING`将窗口设置为在当前行之后的第五行结束。在`RANGE`框架的情况下,它将窗口设置为最后一行的末尾,其排序列值在给定顺序的当前行后5个。如果指定的顺序按日期升序,则它将是当前行之后5天内的最后一行。 使用`UNBOUNDED FOLLOWING`将窗口中的最后一行设置为分区中的最后一行。
467
468 如果未指定`ROW`或`RANGE`子句,并且使用`ORDER BY`, 则窗口绑定从分区的第一行(`UNBOUNDED PRECEDING`)开始,到当前行(`CURRENT ROW`)结束。 如果未指定`ORDER BY`,则窗口从分区的第一行开始(`UNBOUNDED PRECEDING`),然后从分区的最后一行结束(`UNBOUNDED FOLLOWING`)。
469
470
471
472 * **HAVING子句**
473
474 可选的`HAVING`子句具有以下一般形式:
475
476 ``` sql
477 HAVING condition
478 ```
479
480 其中`condition`与为`WHERE`子句指定的条件相同。 `HAVING`去除不满足条件的组行。`HAVING`与`WHERE`不同:`WHERE`在应用`GROUP BY`之前过滤单个行,而`HAVING`过滤`GROUP BY`创建的组行。`condition`中引用的每个列都必须明确引用一个分组列,除非该引用出现在聚合函数中或未分组的列在函数上依赖于分组列。
481
482 即使没有`GROUP BY`子句,`HAVING`的存在也会将查询转换为分组查询。 这与查询包含聚合函数但不包含`GROUP BY`子句的情况相同。所有选定的行都被视为形成一个单一的组,并且`SELECT`列表和`HAVING`子句只能引用聚合函数中的表列。如果`HAVING`条件为true,则此类查询将返回单行;如果条件不是true,则将返回零行。
483
484
485
486 * **UNION子句**
487
488 `UNION`子句具有以下一般形式:
489
490 ``` sql
491 select_statement UNION [ALL | DISTINCT] select_statement
492 ```
493
494 其中`select_statement`是不带`ORDER BY`,`LIMIT`, `FOR NO KEY UPDATE`,`FOR UPDATE`,`FOR SHARE`或`FOR KEY SHARE`子句的任何`SELECT`语句。 (如果将`ORDER BY`和`LIMIT`括在圆括号中,则可以将其附加到子查询表达式。不带圆括号,这些子句将应用于`UNION`的结果,而不是其右侧输入表达式。)
495
496 `UNION`运算符计算所涉及的`SELECT`语句返回的行的集合并集。 如果行出现在至少一个结果集中,则在两个结果集中的行并集中。表示`UNION`的直接操作数的两个`SELECT`语句必须产生相同数量的列,并且对应的列必须具有兼容的数据类型。
497
498 除非指定了`ALL`选项,否则`UNION`的结果不包含任何重复的行。 `ALL`防止重复项的消除。 (因此,`UNION ALL`通常比`UNION`快得多;请尽可能使用`ALL`。) 可以编写`DISTINCT`来明确指定消除重复行的默认行为。
499
500 除非括号中另有说明,否则同一`SELECT`语句中的多个`UNION`运算符从左到右求值。
501
502 当前,不能为`UNION`结果或`UNION`的任何输入指定`FOR NO KEY UPDATE`, `FOR UPDATE`,`FOR SHARE`和`FOR KEY SHARE`。
503
504
505
506 * **INTERSECT子句**
507
508 `INTERSECT`子句具有以下一般形式:
509
510 ``` sql
511 select_statement INTERSECT [ALL | DISTINCT] select_statement
512 ```
513
514 其中`select_statement`是不带`ORDER BY`,`LIMIT`, `FOR NO KEY UPDATE`,`FOR UPDATE`, `FOR SHARE`或`FOR KEY SHARE`子句的任何SELECT语句。
515
516 `INTERSECT`运算符计算所涉及的`SELECT`语句返回的行的交集。 如果一行出现在两个结果集中,则该行位于两个结果集中的交集。
517
518 除非指定`ALL`选项,否则`INTERSECT`的结果不包含任何重复的行。使用`ALL`,在左表中具有`m`个重复项且在右表中具有`n`个重复项的行将在结果集中出现min(`m`,`n`)次。可以编写`DISTINCT`来明确指定消除重复行的默认行为。
519
520 除非括号中另有规定,否则同一`SELECT`语句中的多个`INTERSECT`运算符从左到右求值。`INTERSECT`的优先级比`UNION`高。 即,`A UNION B INTERSECT C`等同于`A UNION (B INTERSECT C)`。
521
522 当前,不能为`INTERSECT`结果或`INTERSECT`的任何输入指定`FOR NO KEY UPDATE`, `FOR UPDATE`,`FOR SHARE`和`FOR KEY SHARE`。
523
524
525
526 * **EXCEPT子句**
527
528 `EXCEPT`子句具有以下一般形式:
529
530 ``` sql
531 select_statement EXCEPT [ALL | DISTINCT] select_statement
532 ```
533
534 其中`select_statement`是不带`ORDER BY`,`LIMIT`,`FOR NO KEY UPDATE`, `FOR UPDATE`,`FOR SHARE`或`FOR KEY SHARE`子句的任何`SELECT`语句。
535
536 `EXCEPT`运算符计算在左`SELECT`语句的结果但不在右`SELECT`的结果的行集。
537
538 除非指定了`ALL`选项,否则`EXCEPT`的结果将不包含任何重复的行。使用`ALL`,在左表中具有`m`个重复项且在右表中具有`n`个重复项的行将在结果集中出现max(`m-n`,0)次。可以编写`DISTINCT`来明确指定消除重复行的默认行为。
539
540 除非括号中另有规定,否则同一`SELECT`语句中的多个`EXCEPT`运算符从左到右求值。 `EXCEPT`与`UNION`优先级相同。
541
542 当前,不能为`EXCEPT`结果或`EXCEPT`的任何输入指定`FOR NO KEY UPDATE`, `FOR UPDATE`,`FOR SHARE`和`FOR KEY SHARE`。
543
544
545
546 * **ORDER BY子句**
547
548 可选的`ORDER BY`子句具有以下一般形式:
549
550 ``` sql
551 ORDER BY expression [ASC | DESC | USING operator] [NULLS {FIRST | LAST}] [,...]
552
553 ```
554
555 其中`expression`可以是输出列(`SELECT`列表项)的名称或序号, 也可以是由输入列值组成的任意表达式。
556
557 `ORDER BY`子句使结果行根据指定的表达式排序。 如果两行最左边的表达式相等,则根据下一个表达式对它们进行比较,依此类推。如果所有指定的表达式相等,则将根据实现的顺序返回它们。
558
559 序号是指输出列的序数位置(从左到右)。 通过此特性,可以基于没有唯一名称的列来定义顺序。这绝对不是必须的,因为始终可以使用`AS`子句为输出列分配名称。
560
561 还可以在`ORDER BY`子句中使用任意表达式,包括未出现在`SELECT`输出列表中的列。 因此,以下语句是有效的:
562
563 ``` sql
564 SELECT name FROM distributors ORDER BY code;
565 ```
566
567 此特性的局限性在于,应用于`UNION`,`INTERSECT`或`EXCEPT`子句结果的`ORDER BY`子句只能指定输出列名称或序号,而不能指定表达式。
568
569 如果`ORDER BY`表达式是一个与输出列名和输入列名都匹配的简单名称,则`ORDER BY`将其解释为输出列名。 这与`GROUP BY`在相同情况下所做的选择相反。 这两个语句的不一致行为与SQL标准兼容。
570
571 可以选择在`ORDER BY`子句中的任何表达式之后添加关键字`ASC`(升序)或`DESC`(降序)。 如果未指定,则默认采用`ASC`。或者,可以在`USING`子句中指定特定的排序运算符名称。 `ASC`通常等效于`USING <`,而`DESC`通常等效于`USING >`。 (但是,用户定义数据类型的创建者可以准确定义默认的排序顺序,并且它可能与其他名称的运算符相对应。)
572
573 如果指定了`NULLS LAST`,则空值将在所有非空值之后排序; 如果指定了`NULLS FIRST`,则空值将在所有非空值之前排序。如果都未指定,则默认行为是在指定或隐含`ASC`时为`NULLS LAST`, 而在指定`DESC`时为`NULLS FIRST`(因此,默认值表示空值大于非空值)。 指定`USING`时,默认的空值排序取决于运算符是小于运算符还是大于运算符。
574
575 请注意,排序选项仅适用于它们遵循的表达式。 例如,`ORDER BY x, y DESC`的含义与`ORDER BY x DESC,y DESC`的含义不同。
576
577 字符串数据是根据创建数据库时建立的特定于语言环境的排序顺序进行排序的。
578
579 字符串数据是根据应用于要排序的列的排序规则进行排序的。 可以根据需要通过在`expression`中包含`COLLATE`子句来覆盖它,例如`ORDER BY mycolumn COLLATE "en_US"`。 有关定义排序规则的信息,请参见`CREATE COLLATION`。
580
581
582
583 * **LIMIT子句**
584
585 `LIMIT`子句包含两个独立的子句:
586
587 ``` sql
588 LIMIT {count | ALL}
589 OFFSET start
590 ```
591
592 其中`count`指定要返回的最大行数,而`start`指定在开始返回行之前要跳过的行数。如果同时指定了两者,则在开始对要返回的`count`行进行计数之前,将跳过起始行。
593
594 如果`count`表达式的计算结果为NULL,则将其视为`LIMIT ALL`,即无限制。如果`start`计算为NULL,则将其与`OFFSET 0`相同。
595
596
597 SQL:2008引入了不同的语法来实现相同的结果,PalopgMPP数据库也支持该语法。 它是:
598
599 ``` sql
600 OFFSET start [ ROW | ROWS ]
601 FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY
602 ```
603
604 在这种语法中,标准要求`start`或`count`值是文字常量,参数或变量名;作为PalopgMPP数据库扩展,可以使用其他表达式,但通常需要将其括在括号中以避免歧义。如果在`FETCH`子句中省略了`count`,则其默认值为1。`ROW`和`ROWS`以及`FIRST`和`NEXT`是不影响这些子句效果的干扰词。根据标准,如果两者都存在,则`OFFSET`子句必须位于`FETCH`子句之前。 但PalopgMPP数据库允许使用任何顺序。
605
606 使用`LIMIT`时,最好使用`ORDER BY`子句将结果行强制为唯一的顺序。 否则,您将获得查询行的不可预测的子集 - 可能会要求以第十到第二十行,但以什么顺序要求第十到第二十行? 除非您指定`ORDER Y`,否则您不知道该如何排序。
607
608 查询优化器在生成查询计划时会考虑`LIMIT`,因此根据`LIMIT`和`OFFSET`的使用方式,您很可能会获得不同的计划(产生不同的行顺序)。因此,除非使用`ORDER BY`强制执行可预测的结果顺序,否则使用不同的`LIMIT/OFFSET`值选择查询结果的不同子集将产生不一致的结果。这不是缺陷;这是一个正常的结果,即除非使用`ORDER BY`强制该顺序,否则SQL不会保证以任何特定顺序传递查询结果。
609
610
611
612 * **Locking子句**
613
614 `FOR UPDATE`,`FOR NO KEY UPDATE`,`FOR SHARE`和`FOR KEY SHARE`是锁定子句;它们会影响`SELECT`如何锁定从表中获取的行。
615
616 锁定子句具有一般形式
617
618 ``` sql
619 FOR lock_strength [OF table_name [ , ... ] ] [ NOWAIT ]
620 ```
621
622
623 其中`lock_strength`可以是以下之一
624
625 ``` sql
626 UPDATE
627 NO KEY UPDATE
628 SHARE
629 KEY SHARE
630 ```
631
632
633
634 注意:默认情况下,PalopgMPP数据库获取对表的`EXCLUSIVE`锁,以对堆表进行`DELETE`和`UPDATE`操作。启用全局死锁检测器后,堆表上`DELETE`和`UPDATE`操作的锁定模式为`ROW EXCLUSIVE`。通过将sc_enable_global_deadlock_detector配置参数设置为true来启用全局死锁检测器。
635
636
637 为防止该操作等待其他事务提交,请使用`NOWAIT`选项。 使用`NOWAIT`,如果无法立即锁定选定的行,该语句将报告错误,而不是等待。请注意,`NOWAIT`仅适用于行级锁 - 所需的`ROW SHARE`表级锁仍以常规方式获取。如果需要不等待就获取表级锁,则可以先将LOCK与`NOWAIT`选项一起使用。
638
639 如果在锁定子句中命名了特定的表,则仅锁定来自那些表的行;其他使用`SELECT`的表则像往常一样简单地读取。没有表列表的锁定子句会影响该语句中使用的所有表。如果将锁定子句应用于视图或子查询,则它将影响视图或子查询中使用的所有表。但是,这些子句不适用于主查询引用的`WITH`查询。如果希望在`WITH`查询中发生行锁定,请在`WITH`查询中指定一个锁定子句。
640
641 如果有必要为不同的表指定不同的锁定行为,则可以编写多个锁定子句。如果同一表被两个以上的锁定子句提及(或隐式影响),则将其视为仅由最强的一个子表指定。同样,如果在影响该表的任何子句中指定了表,则该表将作为`NOWAIT`处理。
642
643 在无法用单独的表行清楚地标识返回的行的上下文中,不能使用锁定子句;例如,它们不能与聚合一起使用。
644
645 当锁定子句出现在`SELECT`查询的顶层时,被锁定的行与查询返回的行完全相同。 对于连接查询,锁定的行是那些促成返回连接行的行。此外,查询快照中满足查询条件的行将被锁定,尽管这些行在快照后对其进行更新并且不再满足查询条件不会返回。如果使用`LIMIT`,则一旦返回了足够的行以满足限制,锁定就会停止(但请注意,被`OFFSET`跳过的行将被锁定)。同样,如果在游标的查询中使用锁定子句,则仅锁定实际被游标读取或跳过的行。
646
647
648 当sub-`SELECT`中出现locking子句时,被锁定的行就是该子查询返回给外部查询的行。这可能涉及的行数少于单独检查子查询所建议的行数,因为外部查询的条件可用于优化子查询的执行。
649
650 例如,
651
652 ``` sql
653 SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss WHERE col1 = 5;
654 ```
655
656 将仅锁定`col1 = 5`的行,即使该条件在文本上不在子查询中。
657
658
659
660 `SELECT`命令可能以`READ COMMITTED`事务隔离级别运行,并且使用`ORDER BY`和锁定子句可以使行无序返回。这是因为`ORDER BY`首先被应用。 该命令对结果进行排序,但随后可能会阻止尝试获得对一个或多个行的锁定。一旦`SELECT`解除阻塞,某些排序列值可能已被修改,从而导致这些行看起来是乱序的(尽管就原始列值而言,它们是有序的)。
661
662 例如,可以通过在子查询中放置`FOR UPDATE/SHARE`子句来解决此问题。
663
664 ``` sql
665 SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1;
666 ```
667
668 请注意,这将导致锁定`mytable`的所有行,而顶层的`FOR UPDATE`将仅锁定实际返回的行。这可能会导致明显的性能差异,特别是如果将`ORDER BY`与`LIMIT`或其他限制结合使用。 因此,仅当期望并发更新排序列并且需要严格排序的结果时才建议使用此技术。
669
670
671 在`REPEATABLE READ`或`SERIALIZABLE`事务隔离级别,这将导致序列化失败(`SQLSTATE`为`40001`),因此在这些隔离级别下,不可能乱序接收行。
672
673
674## 示例
675
676连接表`films`与表`distributors`:
677
678 ``` sql
679 SELECT f.title, f.did, d.name, f.date_prod, f.kind FROM
680 distributors d, films f WHERE f.did = d.did
681 ```
682
683 将表films的`length`列求和并将结果按`kind`分组:
684
685 ``` sql
686 SELECT kind, sum(length) AS total FROM films GROUP BY kind;
687 ```
688
689 将表films的`length`列求和并将结果按`kind`分组并显示总和小于5小时的组:
690
691 ``` sql
692 SELECT kind, sum(length) AS total FROM films GROUP BY kind
693 HAVING sum(length) < interval '5 hours';
694 ```
695
696 计算电影`kind`和`distributor`的所有销售部分和与总和。
697
698 ``` sql
699 SELECT kind, distributor, sum(prc*qty) FROM sales
700 GROUP BY ROLLUP(kind, distributor)
701 ORDER BY 1,2,3;
702 ```
703
704 根据总销量计算电影发行商的排名:
705
706 ``` sql
707 SELECT distributor, sum(prc*qty),
708 rank() OVER (ORDER BY sum(prc*qty) DESC)
709 FROM sale
710 GROUP BY distributor ORDER BY 2 DESC;
711 ```
712
713 以下两个示例是根据第二列(`name`)的内容对单个结果进行排序的相同方法:
714
715 ``` sql
716 SELECT * FROM distributors ORDER BY name;
717 SELECT * FROM distributors ORDER BY 2;
718 ```
719
720 下一个示例说明如何获取表`distributors`和`actors`的并集,将结果限制为每个表中以字母`W`开头的行。只需要不同的行,因此关键字`ALL`被省略:
721
722 ``` sql
723 SELECT distributors.name FROM distributors WHERE
724 distributors.name LIKE 'W%' UNION SELECT actors.name FROM
725 actors WHERE actors.name LIKE 'W%';
726 ```
727
728 此示例说明如何在`FROM`子句中使用函数,无论是否包含列定义列表:
729
730 ``` sql
731 CREATE FUNCTION distributors(int) RETURNS SETOF distributors
732 AS $$ SELECT * FROM distributors WHERE did = $1; $$ LANGUAGE
733 SQL;
734 SELECT * FROM distributors(111);
735
736 CREATE FUNCTION distributors_2(int) RETURNS SETOF record AS
737 $$ SELECT * FROM distributors WHERE did = $1; $$ LANGUAGE
738 SQL;
739 SELECT * FROM distributors_2(111) AS (dist_id int, dist_name
740 text);
741 ```
742
743 此示例使用一个简单的`WITH`子句:
744
745 ``` sql
746 WITH test AS (
747 SELECT random() as x FROM generate_series(1, 3)
748 )
749 SELECT * FROM test
750 UNION ALL
751 SELECT * FROM test;
752 ```
753
754 本示例使用`WITH`子句仅显示最高销售区域中的每产品销售总额。
755
756 ``` sql
757 WITH regional_sales AS
758 SELECT region, SUM(amount) AS total_sales
759 FROM orders
760 GROUP BY region
761 ), top_regions AS (
762 SELECT region
763 FROM regional_sales
764 WHERE total_sales > (SELECT SUM(total_sales) FROM
765 regional_sales)
766 )
767 SELECT region, product, SUM(quantity) AS product_units,
768 SUM(amount) AS product_sales
769 FROM orders
770 WHERE region IN (SELECT region FROM top_regions)
771 GROUP BY region, product;
772 ```
773
774 该示例可能编写不包含`WITH`子句,但需要两级嵌套的sub-`SELECT`语句。
775
776 本示例使用`WITH RECURSIVE`子句从仅显示直接下属的表中查找员工Mary的所有下属(直接或间接)及其间接级别:
777
778 ``` sql
779 WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS (
780 SELECT 1, employee_name, manager_name
781 FROM employee
782 WHERE manager_name = 'Mary'
783 UNION ALL
784 SELECT er.distance + 1, e.employee_name, e.manager_name
785 FROM employee_recursive er, employee e
786 WHERE er.employee_name = e.manager_name
787 )
788 SELECT distance, employee_name FROM employee_recursive;
789 ```
790
791 递归查询的典型形式:初始条件,后跟`UNION [ALL]`,然后是查询的递归部分。确保查询的递归部分最终不会返回任何元组,否则查询将无限期地循环。
792
793
794兼容性说明
795: `SELECT`语句与SQL标准兼容,但是有一些扩展和某些缺少的功能。
796
797 * **省略FROM子句**
798
799 PalopgMPP数据库允许省略`FROM`子句。 它可以直接用于计算简单表达式的结果。例如:
800
801 ``` sql
802 SELECT 2+2;
803 ```
804
805 其他一些SQL数据库无法做到这一点,除非引入一个虚拟的单行表来执行`SELECT`。
806
807
808 请注意,如果未指定`FROM`子句,则查询无法引用任何数据库表。 例如,以下查询无效:
809
810 ``` sql
811 SELECT distributors.* WHERE distributors.name = 'Westward';
812 ```
813
814 在较早的版本中,将服务器配置参数`add_missing_from`设置为true允许PalopgMPP数据库为查询所引用的每个表向查询的`FROM`子句添加隐式条目。这个不再允许。
815
816
817
818
819 * **省略AS关键字**
820
821 在SQL标准中,只要新列名是有效的列名(即与任何保留关键字不同),就可以在输出列名之前省略可选关键字`AS`。PalopgMPP数据库的限制更为严格:如果新列名完全匹配任何关键字(保留与否),则要求使用`AS`。推荐的做法是使用`AS`或双引号输出列名,以防止与将来添加关键字的任何可能的冲突。
822
823 在`FROM`项中,SQL标准和PalopgMPP数据库都允许在作为未保留关键字的别名之前省略`AS`。但是由于语法上的歧义,这对于输出列名称是不切实际的。
824
825
826
827 * **ONLY和Inheritance**
828
829
830 使用`ONLY`时,SQL标准要求在表名前后加上括号,例如:
831
832 ``` sql
833 SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE ...
834 ```
835
836 PalopgMPP数据库认为这些括号是可选的。
837
838
839 PalopgMPP数据库允许编写尾随`*`来明确指定包括子表的non-`ONLY`行为。 该标准不允许这样做。这些要点同样适用于所有支持`ONLY`选项的SQL命令。
840
841
842
843 * **Namespace可以用于GROUP BY和ORDER BY**
844
845 在SQL-92标准中,`ORDER BY`子句只能使用输出列名称或序号,而`GROUP BY`子句只能使用基于输入列名称的表达式。PalopgMPP数据库扩展了这些子句中的每一个,以允许其他选择(但是如果有歧义,它将使用标准的解释)。PalopgMPP数据库还允许两个子句都指定任意表达式。请注意,出现在表达式中的名称始终被视为输入列名称,而不是输出列名称。
846
847 SQL:1999及更高版本使用的定义略有不同,但并不完全与SQL-92向上兼容。但是,在大多数情况下,PalopgMPP数据库以与SQL:1999相同的方式解释`ORDER BY`或`GROUP BY`表达式。
848
849
850
851 * **函数依赖**
852
853 仅当表的主键包含在`GROUP BY`列表中时,PalopgMPP数据库才能识别函数依赖(允许从`GROUP BY`省略列)。SQL标准指定了应识别的其他条件。
854
855
856
857 * **LIMIT和OFFSET**
858
859 子句`LIMIT`和`OFFSET`是PalopgMPP数据库特定的语法,也由MySQL使用。如上所述,SQL:2008标准引入了子句`OFFSET .. FETCH {FIRST | NEXT} ...`来实现相同的功能。 IBM DB2也使用此语法。(Oracle应用程序经常使用一种变通办法来实现这些子句的效果,该变通办法涉及自动生成的`rownum`列,PalopgMPP数据库中不提供该列。)
860
861 * **FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE和FOR KEY SHARE**
862
863 尽管`FOR UPDATE`出现在SQL标准中,但该标准仅允许将它作为`DECLARE CURSOR`的选项。PalopgMPP数据库允许在任何`SELECT`查询以及sub-`SELECT`中使用它,但这是一个扩展。`FOR NO KEY UPDATE`,`FOR SHARE`和`FOR KEY SHARE`变体以及`NOWAIT`选项未出现在标准中。
864
865
866
867 * **WITH中的数据修改语句**
868
869 PalopgMPP数据库允许将`INSERT`,`UPDATE`和`DELETE`用作`WITH`查询。 在SQL标准中不允许。
870
871
872
873 * **非标准子句**
874
875 在SQL标准中未定义`DISTINCT ON`子句。
876
877
878
879 * **STABLE和VOLATILE函数的限制**
880
881 为防止数据在PalopgMPP数据库中的各个executor之间变得不同步,如果分类为`STABLE`或`VOLATILE`的任何函数包含SQL或以任何方式修改了数据库,则不能在executor数据库级别执行该函数。有关更多信息,请参见`CREATE FUNCTION`。
882
883
884
885
886相关SQL命令
887: ` EXPLAIN `
888
889
890## 查询
891
892前面的章节解释了如何创建表、如何用数据填充它们 以及如何操纵那些数据。现在我们终于可以讨论如何从数据库中检索数据了。
893
894
895### 概述
896
897从数据库中检索数据的过程或命令叫做*查询*。在 SQL里`SELECT`命令用于指定查询。
898
899`SELECT`命令的一般语法是
900
901``` sql
902[WITH with_queries] SELECT select_list FROM table_expression [sort_specification]
下面几个小节描述选择列表、表表达式和排序声明的细节。WITH查询等高级特性将在最后讨论。
一个简单类型的查询的形式:
1SELECT * FROM table1;
假设有一个表叫做table1,这条命令将table1中检索所有行和所有用户定义的列(检索的方法取决于客户端应用。例如,ssql程序将在屏幕上显示一个ASCII 形式的表格, 而客户端库将提供函数来从检索结果中抽取单个值)。 选择列表声明*意味着所有表表达式提供的列。
一个选择列表也可以选择可用列的一个子集或者在使用它们之前对列进行计算。例如,如果table1有叫做a、b和c的列(可能还有其他),那么你可以用下面的查询:
1SELECT a, b + c FROM table1;
(假设b和c都是数字数据类型)。参阅选择列表章节获取更多细节。
FROM table1是一种非常简单的表表达式:它只读取了一个表。通常,表表达式可以是基本表、连接和子查询组成的复杂结构。但你也可以省略整个表表达式而把SELECT命令当做一个计算器:
1SELECT 3 * 4;
如果选择列表里的表达式返回变化的结果,那么这就更有用了。例如,你可以用这种方法调用函数:
1SELECT random();
表表达式
表表达式 计算一个表。该表表达式包含一个FROM子句,该子句后面可以根据需要选用WHERE、GROUP BY和HAVING子句。最简单的表表达式只是引用磁盘上的一个表,一个所谓的基本表,但是我们可以用更复杂的表表达式以多种方法修改或组合基本表。
表表达式里可选的WHERE、GROUP BY和HAVING子句指定一系列对源自FROM子句的表的转换操作。所有这些转换最后生成一个虚拟表,它提供行传递给选择列表计算查询的输出行。
FROM子句
FROM子句 从一个用逗号分隔的表引用列表中的一个或更多个其它表中生成一个表。
1FROM table_reference [, table_reference [, ...]]
表引用可以是一个表名字(可能有模式限定)或者是一个生成的表,例如子查询、一个JOIN结构或者这些东西的复杂组合。如果在FROM子句中引用了多于一个表,那么它们被交叉连接(即构造它们的行的笛卡尔积,见下文)。FROM列表的结果是一个中间的虚拟表,该表可以进行由WHERE、GROUP BY和HAVING子句指定的转换,并最后生成全局的表表达式结果。
如果一个表引用是一个简单的表名字并且它是表继承层次中的父表,那么该表引用将产生该表和它的后代表中的行,除非你在该表名字前面放上ONLY关键字。但是,这种引用只会产生出现在该命名表中的列在子表中增加的列都会被忽略。
除了在表名前写ONLY,你可以在表名后面写上*来显式地指定要包括所有的后代表。没有实际的理由再继续使用这种语法,因为搜索后代表现在总是默认行为。不过,为了保持与旧版本的兼容性,仍然支持这种语法。
连接表
一个连接表是根据特定的连接类型的规则从两个其它表(真实表或生成表)中派生的表。目前支持内连接、外连接和交叉连接。一个连接表的一般语法是:
1T1 join_type T2 [ join_condition ]
所有类型的连接都可以被链在一起或者嵌套:T1和T2都可以是连接表。在JOIN子句周围可以使用圆括号来控制连接顺序。如果不使用圆括号,JOIN子句会从左至右嵌套。
连接类型
cross连接
: 对来自于 T1 和 T2 的行的每一种可能的组合(即笛卡尔积),连接表将包含这样一行:它由所有 T1 里面的列后面跟着所有 T2 里面的列构成。如果两个表分别有
N 和 M 行,连接表将有 N * M 行。
1``` sql
2T1 CROSS JOIN T2
3```
4
5`FROM T1` CROSS JOIN *`T2`*等效于`FROM T1` INNER JOIN *`T2`* ON TRUE(见下文)。它也等效于`FROM T1`,*`T2`*。
6
7**注意**
8
9当多于两个表出现时,后一种等效并不严格成立,因为`JOIN`比逗号绑得更紧。例如`FROM T1` CROSS JOIN *`T2`* INNER JOIN *`T3`* ON *`condition`*和`FROM T1`,*`T2`* INNER JOIN *`T3`* ON *`condition`*并不完全相同,因为第一种情况中的*`condition`*可以引用*`T1`*,但在第二种情况中却不行。
条件连接
: INNER和OUTER对所有连接形式都是可选的。INNER是缺省;LEFT、RIGHT和FULL指示一个外连接。
1``` sql
2T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 ON boolean_expression
3T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 USING ( join column list )
4T1 NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2
5```
6
7*连接条件*在`ON`或`USING`子句中指定, 或者用关键字`NATURAL`隐含地指定。连接条件决定来自两个源表中的哪些行是“匹配”的,这些我们将在后文详细解释。
8
9可能的条件连接类型是:
10
11`INNER JOIN`
12: 对于 T1 的每一行 R1,生成的连接表都有一行对应 T2 中的每一个满足和 R1 的连接条件的行。
13
14`LEFT OUTER JOIN`
15: 首先,执行一次内连接。然后,为 T1 中每一个无法在连接条件上匹配 T2 里任何一行的行返回一个连接行,该连接行中 T2的列用空值补齐。因此,生成的连接表里为来自 T1 的每一行都至少包含一行。
16
17`RIGHT OUTER JOIN`
18: 首先,执行一次内连接。然后,为 T2 中每一个无法在连接条件上匹配 T1 里任何一行的行返回一个连接行,该连接行中 T1的列用空值补齐。因此,生成的连接表里为来自 T2 的每一行都至少包含一行。
19
20`FULL OUTER JOIN`
21: 首先,执行一次内连接。然后,为 T1 中每一个无法在连接条件上匹配 T2 里任何一行的行返回一个连接行,该连接行中 T2的列用空值补齐。同样,为 T2 中每一个无法在连接条件上匹配 T1 里任何一行的行返回一个连接行,该连接行中T1 的列用空值补齐。
22
23
24`ON`子句是最常见的连接条件的形式:它接收一个和`WHERE`子句里用的一样的布尔值表达式。
25
26如果两个分别来自 *`T1`* 和 *`T2`* 的行在`ON`表达式上运算的结果为真,那么它们就算是匹配的行。
27
28`USING`是个缩写符号,它允许你利用特殊的情况:连接的两端都具有相同的连接列名。它接受共享列名的一个逗号分隔列表,并且为其中每一个共享列构造一个包含等值比较的连接条件。例如用`USING (a, b)`连接*`T1`*和*`T2`*会产生连接条件`ON T1`.a = *`T2`*.a AND *`T1`*.b = *`T2`*.b。
29
30更进一步,`JOIN USING`的输出会废除冗余列:不需要把匹配上的列都打印出来,因为它们必须具有相等的值。不过`JOIN ON`会先产生来自 *`T1`* 的所有列,后面跟上所有来自 *`T2`* 的列;而`JOIN USING`会先为列出的每一个列对产生一个输出列,然后先跟上来自 *`T1`* 的剩余列,最后跟上来自 *`T2`* 的剩余列。
31
32
33
34最后,`NATURAL`是`USING`的缩写形式:它形成一个`USING`列表,该列表由那些在两个表里都出现了的列名组成。和`USING`一样,这些列只在输出表里出现一次。如果不存在公共列,`NATURAL JOIN`的行为将和`JOIN ... ON TRUE`一样产生交叉集连接。
35
36
37
38**注意**
39
40`USING`对于连接关系中的列改变是相当安全的,因为只有被列出的列会被组合成连接条件。`NATURAL`的风险更大,因为如果其中一个关系的模式改变会导致出现一个新的匹配列名,就会导致连接将新列也组合成连接条件。
为了解释这些问题,假设我们有一个表t1:
1 num | name
2-----+------
3 1 | a
4 2 | b
5 3 | c
和t2表:
1 num | value
2-----+-------
3 1 | xxx
4 3 | yyy
5 5 | zzz
然后我们用不同的连接方式可以获得各种结果:
1=> SELECT * FROM t1 CROSS JOIN t2;
2 num | name | num | value
3-----+------+-----+-------
4 1 | a | 1 | xxx
5 1 | a | 3 | yyy
6 1 | a | 5 | zzz
7 2 | b | 1 | xxx
8 2 | b | 3 | yyy
9 2 | b | 5 | zzz
10 3 | c | 1 | xxx
11 3 | c | 3 | yyy
12 3 | c | 5 | zzz
13(9 rows)
14
15=> SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num;
16 num | name | num | value
17-----+------+-----+-------
18 1 | a | 1 | xxx
19 3 | c | 3 | yyy
20(2 rows)
21
22=> SELECT * FROM t1 INNER JOIN t2 USING (num);
23 num | name | value
24-----+------+-------
25 1 | a | xxx
26 3 | c | yyy
27(2 rows)
28
29=> SELECT * FROM t1 NATURAL INNER JOIN t2;
30 num | name | value
31-----+------+-------
32 1 | a | xxx
33 3 | c | yyy
34(2 rows)
35
36=> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num;
37 num | name | num | value
38-----+------+-----+-------
39 1 | a | 1 | xxx
40 2 | b | |
41 3 | c | 3 | yyy
42(3 rows)
43
44=> SELECT * FROM t1 LEFT JOIN t2 USING (num);
45 num | name | value
46-----+------+-------
47 1 | a | xxx
48 2 | b |
49 3 | c | yyy
50(3 rows)
51
52=> SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num;
53 num | name | num | value
54-----+------+-----+-------
55 1 | a | 1 | xxx
56 3 | c | 3 | yyy
57 | | 5 | zzz
58(3 rows)
59
60=> SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num;
61 num | name | num | value
62-----+------+-----+-------
63 1 | a | 1 | xxx
64 2 | b | |
65 3 | c | 3 | yyy
66 | | 5 | zzz
67(4 rows)
用ON指定的连接条件也可以包含与连接不直接相关的条件。这种功能可能对某些查询很有用,但是需要我们仔细想清楚。例如:
1=> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx';
2 num | name | num | value
3-----+------+-----+-------
4 1 | a | 1 | xxx
5 2 | b | |
6 3 | c | |
7(3 rows)
注意
把限制放在WHERE子句中会产生不同的结果:
1=> SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num WHERE t2.value = 'xxx';
2 num | name | num | value
3-----+------+-----+-------
4 1 | a | 1 | xxx
5(1 row)
这是因为放在ON子句中的一个约束在连接之前被处理,而放在WHERE子句中的一个约束是在连接之后被处理。这对内连接没有关系,但是对于外连接会带来麻烦。
表和列别名
你可以给一个表或复杂的表引用指定一个临时的名字,用于剩下的查询中引用那些派生的表。这被叫做表别名。
要创建一个表别名,我们可以写:
1FROM table_reference AS alias
或者
1FROM table_reference alias
AS关键字是可选的。别名可以是任意标识符。
表别名的典型应用是给长表名赋予比较短的标识符, 好让连接子句更易读。例如:
1SELECT * FROM some_very_long_table_name s JOIN another_fairly_long_name a ON s.id = a.num;
到这里,别名成为当前查询的表引用的新名称 — 我们不再能够用该表最初的名字引用它了。因此,下面的用法是不合法的:
1SELECT * FROM my_table AS m WHERE my_table.a > 5; -- 错误
表别名主要用于简化符号,但是当把一个表连接到它自身时必须使用别名,例如:
1SELECT * FROM people AS mother JOIN people AS child ON mother.id = child.mother_id;
此外,如果一个表引用是一个子查询,则必须要使用一个别名(见子查询章节)。
圆括弧用于解决歧义。在下面的例子中,第一个语句将把别名b赋给my_table的第二个实例,但是第二个语句把别名赋给连接的结果:
1SELECT * FROM my_table AS a CROSS JOIN my_table AS b ...
2SELECT * FROM (my_table AS a CROSS JOIN my_table) AS b ...
另外一种给表指定别名的形式是给表的列赋予临时名字,就像给表本身指定别名一样:
1FROM table_reference [AS] alias ( column1 [, column2 [, ...]] )
如果指定的列别名比表里实际的列少,那么剩下的列就没有被重命名。这种语法对于自连接或子查询特别有用。
如果用这些形式中的任何一种给一个JOIN子句的输出附加了一个别名, 那么该别名就在JOIN的作用下隐去了其原始的名字。例如:
1SELECT a.* FROM my_table AS a JOIN your_table AS b ON ...
是合法 SQL,但是:
1SELECT a.* FROM (my_table AS a JOIN your_table AS b ON ...) AS c
是不合法的:表别名a在别名c外面是看不到的。
子查询
子查询指定了一个派生表,它必须被包围在圆括弧里并且必须被赋予一个表别名(参阅表和列别名章节)。例如:
1FROM (SELECT * FROM table1) AS alias_name
这个例子等效于FROM table1 AS alias_name。更有趣的情况是在子查询里面有分组或聚集的时候,子查询不能被简化为一个简单的连接。
一个子查询也可以是一个VALUES列表:
1FROM (VALUES ('anne', 'smith'), ('bob', 'jones'), ('joe', 'blow'))
2 AS names(first, last)
再次的,这里要求一个表别名。为VALUES列表中的列分配别名是可选的,但是选择这样做是一个好习惯。更多信息可参见VALUES列表。
表函数
表函数是那些生成一个行集合的函数,这个集合可以是由基本数据类型(标量类型)组成,也可以是由复合数据类型(表行)组成。它们的用法类似一个表、视图或者在查询的FROM子句里的子查询。表函数返回的列可以像一个表列、视图或者子查询那样被包含在SELECT、JOIN或WHERE子句里。
也可以使用ROWS FROM语法将平行列返回的结果组合成表函数; 这种情况下结果行的数量是最大一个函数结果的数量,较小的结果会用空值来填充。
1function_call [WITH ORDINALITY] [[AS] table_alias [(column_alias [, ... ])]]
2ROWS FROM( function_call [, ... ] ) [WITH ORDINALITY] [[AS] table_alias [(column_alias [, ... ])]]
如果指定了WITH ORDINALITY子句,一个额外的 bigint类型的列将会被增加到函数的结果列中。这个列对函数结果集的行进行编号,编号从 1 开始(这是对 SQL 标准语法 UNNEST ... WITH ORDINALITY的一般化)。默认情 况下,序数列被称为ordinality,但也可以通过使用一个 AS子句给它分配一个不同的列名。
调用特殊的表函数UNNEST可以使用任意数量的数组参数, 它会返回对应的列数,就好像在每一个参数上单独调用UNNEST(数组函数和操作符)并且使用ROWS FROM结构把它们组合起来。
1UNNEST( array_expression [, ... ] ) [WITH ORDINALITY] [[AS] table_alias [(column_alias [, ... ])]]
如果没有指定table_alias,该函数名将被用作 表名。在ROWS FROM()结构的情况中,会使用第一个函数名。
如果没有提供列的别名,那么对于一个返回基数据类型的函数,列名也与该函数 名相同。对于一个返回组合类型的函数,结果列会从该类型的属性得到名称。
例子:
1CREATE TABLE foo (fooid int, foosubid int, fooname text);
2
3CREATE FUNCTION getfoo(int) RETURNS SETOF foo AS $$
4 SELECT * FROM foo WHERE fooid = $1;
5$$ LANGUAGE SQL;
6
7SELECT * FROM getfoo(1) AS t1;
8
9SELECT * FROM foo
10 WHERE foosubid IN (
11 SELECT foosubid
12 FROM getfoo(foo.fooid) z
13 WHERE z.fooid = foo.fooid
14 );
15
16CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1);
17
18SELECT * FROM vw_getfoo;
有时侯,定义一个能够根据它们被调用方式返回不同列集合的表函数是很有用的。为了支持这些,表函数可以被声明为返回伪类型record。
如果在查询里使用这样的函数,那么我们必须在查询中指定所预期的行结构,这样系统才知道如何分析和规划该查询。这种语法是这样的:
1function_call [AS] alias (column_definition [, ... ])
2function_call AS [alias] (column_definition [, ... ])
3ROWS FROM( ... function_call AS (column_definition [, ... ]) [, ... ] )
在没有使用ROWS FROM()语法时, column_definition 列表会取代无法附着在FROM项上的列别名列表,列定义中的名称就起到列别名的作用。 在使用ROWS FROM()语法时, 可以为每一个成员函数单独附着一个 column_definition 列表;或者在只有一个成员函数并且没有WITH ORDINALITY子句的情况下,可以在 ROWS FROM()后面写一个
column_definition 列表来取代一个列别名列表。
考虑下面的例子:
1SELECT *
2 FROM dblink('dbname=mydb', 'SELECT proname, prosrc FROM pg_proc')
3 AS t1(proname name, prosrc text)
4 WHERE proname LIKE 'bytea%';
dblink函数(dblink模块的一部分)执行一个远程的查询。它被声明为返回record,因为它可能会被用于任何类型的查询。
实际的列集必须在调用它的查询中指定,这样解析器才知道类似*这样的东西应该扩展成什么样子。
LATERAL子查询
可以在出现于FROM中的子查询前放置关键字LATERAL。这允许它们引用前面的FROM项提供的列(如果没有LATERAL,每一个子查询将被独立计算,并且因此不能被其他FROM项交叉引用)。
出现在FROM中的表函数的前面也可以被放上关键字LATERAL,但对于函数该关键字是可选的,在任何情况下函数的参数都可以包含对前面的FROM项提供的列的引用。
一个LATERAL项可以出现在FROM列表顶层,或者出现在一个JOIN树中。在后一种情况下,如果它出现在JOIN的右部,那么它也可以引用在JOIN左部的任何项。
如果一个FROM项包含LATERAL交叉引用,计算过程如下:对于提供交叉引用列的FROM项的每一行,或者多个提供这些列的多个FROM项的行集合,LATERAL项将被使用该行或者行集中的列值进行计算。得到的结果行将和它们被计算出来的行进行正常的连接。对于来自这些列的源表的每一行或行集,该过程将重复。
LATERAL的一个简单例子:
1SELECT * FROM foo, LATERAL (SELECT * FROM bar WHERE bar.id = foo.bar_id) ss;
这不是非常有用,因为它和一种更简单的形式得到的结果完全一样:
1SELECT * FROM foo, bar WHERE bar.id = foo.bar_id;
在必须要使用交叉引用列来计算那些即将要被连接的行时,LATERAL是最有用的。一种常用的应用是为一个返回集合的函数提供一个参数值。例如,假设vertices(polygon)返回一个多边形的顶点集合,我们可以这样标识存储在一个表中的多边形中靠近的顶点:
1SELECT p1.id, p2.id, v1, v2
2FROM polygons p1, polygons p2,
3 LATERAL vertices(p1.poly) v1,
4 LATERAL vertices(p2.poly) v2
5WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;
这个查询也可以被写成:
1SELECT p1.id, p2.id, v1, v2
2FROM polygons p1 CROSS JOIN LATERAL vertices(p1.poly) v1,
3 polygons p2 CROSS JOIN LATERAL vertices(p2.poly) v2
4WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;
或者写成其他几种等价的公式(正如以上提到的,LATERAL关键字在这个例子中并不是必不可少的,但是我们在这里使用它是为了使表述更清晰)。
有时候也会很特别地把LEFT JOIN放在一个LATERAL子查询的前面,这样即使LATERAL子查询对源行不产生行,源行也会出现在结果中。例如,如果get_product_names()返回一个制造商制造的产品的名字,但是某些制造商在我们的表中目前没有制造产品,我们可以找出哪些制造商是这样:
1SELECT m.name
2FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true
3WHERE pname IS NULL;
WHERE子句
WHERE 子句的语法是
1WHERE search_condition
这里的search_condition是任意返回一个boolean类型值的值表达式(参阅值表达式章节)。
在完成对FROM子句的处理之后,生成的虚拟表的每一行都会对根据搜索条件进行检查。
如果该条件的结果是真,那么该行被保留在输出表中;否则(也就是说,如果结果是假或空)就把它抛弃。搜索条件通常至少要引用一些在FROM子句里生成的列;虽然这不是必须的,但如果不引用这些列,那么WHERE子句就没什么用了。
注意
内连接的连接条件既可以写在WHERE子句也可以写在JOIN子句里。例如,这些表表达式是等效的:
1FROM a, b WHERE a.id = b.id AND b.val > 5
和:
1FROM a INNER JOIN b ON (a.id = b.id) WHERE b.val > 5
或者可能还有:
1FROM a NATURAL JOIN b WHERE b.val > 5
你想用哪个只是一个风格问题。FROM子句里的JOIN语法可能不那么容易移植到其它SQL数据库管理系统中。
对于外部连接而言没有选择:它们必须在FROM子句中完成。
外部连接的ON或USING子句不等于WHERE条件,因为它导致最终结果中行的增加(对那些不匹配的输入行)和减少。
这里是一些WHERE子句的例子:
1SELECT ... FROM fdt WHERE c1 > 5
2
3SELECT ... FROM fdt WHERE c1 IN (1, 2, 3)
4
5SELECT ... FROM fdt WHERE c1 IN (SELECT c1 FROM t2)
6
7SELECT ... FROM fdt WHERE c1 IN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10)
8
9SELECT ... FROM fdt WHERE c1 BETWEEN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) AND 100
10
11SELECT ... FROM fdt WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1)
在上面的例子里,fdt是从FROM子句中派生的表。
那些不符合WHERE子句的搜索条件的行会被从fdt中删除。请注意我们把标量子查询当做一个值表达式来用。
和任何其它查询一样,子查询里可以使用复杂的表表达式。同时还请注意fdt在子查询中也被引用。只有在c1也是作为子查询输入表的生成表的列时,才必须把c1限定成fdt.c1。但限定列名字可以增加语句的清晰度,即使有时候不是必须的。这个例子展示了一个外层查询的列名范围如何扩展到它的内层查询。
GROUP BY和HAVING子句
在通过了WHERE过滤器之后,生成的输入表可以使用GROUP BY子句进行分组,然后用HAVING子句删除一些分组行。
1SELECT select_list
2 FROM ...
3 [WHERE ...]
4 GROUP BY grouping_column_reference [, grouping_column_reference]...
GROUP BY子句被用来把表中在所列出的列上具有相同值的行分组在一起。这些列的列出顺序并没有什么关系。其效果是把每组具有相同值的行组合为一个组行,它代表该组里的所有行。这样就可以删除输出里的重复和/或计算应用于这些组的聚集。例如:
1=> SELECT * FROM test1;
2 x | y
3---+---
4 a | 3
5 c | 2
6 b | 5
7 a | 1
8(4 rows)
9
10=> SELECT x FROM test1 GROUP BY x;
11 x
12
13 a
14 b
15 c
16(3 rows)
在第二个查询里,我们不能写成SELECT * FROM test1 GROUP BY x,因为列y里没有哪个值可以和每个组相关联起来。被分组的列可以在选择列表中引用是因为它们在每个组都有单一的值。
通常,如果一个表被分了组,那么没有在GROUP BY中列出的列都不能被引用,除非在聚集表达式中被引用。 一个用聚集表达式的例子是:
1=> SELECT x, sum(y) FROM test1 GROUP BY x;
2 x | sum
3---+-----
4 a | 4
5 b | 5
6 c | 2
7(3 rows)
这里的sum是一个聚集函数,它在整个组上计算出一个单一值。有关可用的聚集函数的更多信息可以在聚集函数章节。
提示
没有聚集表达式的分组实际上计算了一个列中可区分值的集合。我们也可以用DISTINCT子句实现(参阅 DISTINCT章节)。
这里是另外一个例子:它计算每种产品的总销售额(而不是所有产品的总销售额):
1SELECT product_id, p.name, (sum(s.units) * p.price) AS sales
2 FROM products p LEFT JOIN sales s USING (product_id)
3 GROUP BY product_id, p.name, p.price;
在这个例子里,列product_id、p.name和p.price必须在GROUP BY子句里,因为它们都在查询的选择列表里被引用到(但见下文)。列s.units不必在GROUP BY列表里,因为它只是在一个聚集表达式(sum(...))里使用,它代表一组产品的销售额。对于每种产品,这个查询都返回一个该产品的所有销售额的总和行。
如果产品表被建立起来,例如product_id是主键,那么在上面的例子中用product_id来分组就够了,因为名称和价格都是函数依赖于产品ID,并且关于为每个产品ID分组返回哪个名称和价格值就不会有歧义。
在严格的 SQL 里,GROUP BY只能对源表的列进行分组,但PalopgSQL把这个扩展为也允许GROUP BY去根据选择列表中的列分组。也允许对值表达式进行分组,而不仅是简单的列名。
如果一个表已经用GROUP BY子句分了组,然后你又只对其中的某些组感兴趣,那么就可以用HAVING子句,它很象WHERE子句,用于从结果中删除一些组。其语法是:
1SELECT select_list FROM ... [WHERE ...] GROUP BY ... HAVING boolean_expression
在HAVING子句中的表达式可以引用分组的表达式和未分组的表达式(后者必须涉及一个聚集函数)。
例子:
1=> SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3;
2 x | sum
3---+-----
4 a | 4
5 b | 5
6(2 rows)
7
8=> SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c';
9 x | sum
10---+-----
11 a | 4
12 b | 5
13(2 rows)
再次,一个更现实的例子:
1SELECT product_id, p.name, (sum(s.units) * (p.price - p.cost)) AS profit
2 FROM products p LEFT JOIN sales s USING (product_id)
3 WHERE s.date > CURRENT_DATE - INTERVAL '4 weeks'
4 GROUP BY product_id, p.name, p.price, p.cost
5 HAVING sum(p.price * s.units) > 5000;
在上面的例子里,WHERE子句用那些非分组的列选择数据行(表达式只是对那些最近四周发生的销售为真)。而HAVING子句限制输出为总销售收入超过5000的组。请注意聚集表达式不需要在查询中的所有地方都一样。
如果一个查询包含聚集函数调用,但是没有GROUP BY子句,分组仍然会发生:结果是一个单一行(或者根本就没有行,如果该单一行被HAVING所消除)。它包含一个HAVING子句时也是这样,即使没有任何聚集函数调用或者GROUP BY子句。
GROUPING SETS、CUBE和ROLLUP
使用分组集的概念可以实现比上述更加复杂的分组操作。由 FROM和WHERE子句选出的数据被按照每一个指定的分组集单独分组,按照简单GROUP BY子句对每一个分组计算聚集,然后返回结果。例如:
1=> SELECT * FROM items_sold;
2 brand | size | sales
3-------+------+-------
4 Foo | L | 10
5 Foo | M | 20
6 Bar | M | 15
7 Bar | L | 5
8(4 rows)
9
10=> SELECT brand, size, sum(sales) FROM items_sold GROUP BY GROUPING SETS ((brand), (size), ());
11 brand | size | sum
12-------+------+-----
13 Foo | | 30
14 Bar | | 20
15 | L | 15
16 | M | 35
17 | | 50
18(5 rows)
GROUPING SETS的每一个子列表可以指定一个或者多个列或者表达式, 它们将按照直接出现在GROUP BY子句中同样的方式被解释。一个空的分组集表示所有的行都要被聚集到一个单一分组(即使没有输入行存在也会被输出)中,这就像前面所说的没有GROUP BY子句的聚集函数的情况一样。
对于分组列或表达式没有出现在其中的分组集的结果行,对分组列或表达式的引用会 被空值所替代。要区分一个特定的输出行来自于哪个分组,请见分组操作章节。
PalopgSQL 中提供了一种简化方法来指定两种常用类型的分组集。下面形式的子句
1ROLLUP ( e1, e2, e3, ... )
表示给定的表达式列表及其所有前缀(包括空列表),因此它等效于
1GROUPING SETS (
2 ( e1, e2, e3, ... ),
3 ...
4 ( e1, e2 ),
5 ( e1 ),
6 ( )
7)
这通常被用来分析历史数据,例如按部门、区和公司范围计算的总薪水。
下面形式的子句
1CUBE ( e1, e2, ... )
表示给定的列表及其可能的子集(即幂集)。因此
1CUBE ( a, b, c )
等效于
1GROUPING SETS (
2 ( a, b, c ),
3 ( a, b ),
4 ( a, c ),
5 ( a ),
6 ( b, c ),
7 ( b ),
8 ( c ),
9 ( )
10)
CUBE或ROLLUP子句中的元素可以是表达式或者 圆括号中的元素子列表。在后一种情况中,对于生成分组集的目的来说,子列表被当做单一单元来对待。例如:
1CUBE ( (a, b), (c, d) )
等效于
1GROUPING SETS (
2 ( a, b, c, d ),
3 ( a, b ),
4 ( c, d ),
5 ( )
6)
并且
1ROLLUP ( a, (b, c), d )
等效于
1GROUPING SETS (
2 ( a, b, c, d ),
3 ( a, b, c ),
4 ( a ),
5 ( )
6)
CUBE和ROLLUP可以被直接用在 GROUP BY子句中,也可以被嵌套在一个 GROUPING SETS子句中。如果一个GROUPING SETS子句被嵌套在另一个同类子句中, 效果和把内层子句的所有元素直接写在外层子句中一样。
如果在一个GROUP BY子句中指定了多个分组项,那么最终的 分组集列表是这些项的叉积。例如:
1GROUP BY a, CUBE (b, c), GROUPING SETS ((d), (e))
等效于
1GROUP BY GROUPING SETS (
2 (a, b, c, d), (a, b, c, e),
3 (a, b, d), (a, b, e),
4 (a, c, d), (a, c, e),
5 (a, d), (a, e)
6)
注意
在表达式中,结构(a, b)通常被识别为一个 a 行构造器章节。在GROUP BY子句中,这不会在表达式的顶层应用,并且 (a, b)会按照上面所说的被解析为一个表达式的列表。如果出于某种原因你在分组表达式中需要一个行构造器,请使用ROW(a, b)。
窗口函数处理
如果查询包含任何窗口函数,这些函数将在任何分组、聚集和HAVING过滤被执行之后被计算。也就是说如果查询使用了任何聚集、GROUP BY或HAVING,则窗口函数看到的行是分组行而不是来自于FROM/WHERE的原始表行。
当多个窗口函数被使用,所有在窗口定义中有句法上等效的PARTITION BY和ORDER BY子句的窗口函数被保证在数据上的同一趟扫描中计算。因此它们将会看到相同的排序顺序,即使ORDER BY没有唯一地决定一个顺序。但是,对于具有不同PARTITION BY或ORDER BY定义的函数的计算没有这种保证(在这种情况中,在多个窗口函数计算之间通常要求一个排序步骤,并且并不保证保留行的顺序,即使它的ORDER BY把这些行视为等效的)。
目前,窗口函数总是要求排序好的数据,并且这样查询的输出总是被根据窗口函数的PARTITION BY/ORDER BY子句的一个或者另一个排序。但是,我们不推荐依赖于此。如果你希望确保结果以特定的方式排序,请显式使用顶层的ORDER BY子句。
选择列表
如前面的小节说明的那样, 在SELECT命令里的表表达式构造了一个中间的虚拟表,方法可能有组合表、视图、消除行、分组等等。这个表最后被选择列表传递下去处理。选择列表判断中间表的哪个列是实际输出。
选择列表项
最简单的选择列表类型是*,它发出表表达式生成的所有列。否则,一个选择列表是一个逗号分隔的值表达式的列表(和在值表达式里定义的一样)。
例如,它可能是一个列名的列表:
1SELECT a, b, c FROM ...
列名字a、b和c要么是在FROM子句里引用的表中列的实际名字,要么是像表和列别名章节 里解释的那样的别名。在选择列表里可用的名字空间和在WHERE子句里的一样,除非你使用了分组,这时候它和HAVING子句一样。
如果超过一个表有同样的列名,那么你还必须给出表名字,如:
1SELECT tbl1.a, tbl2.a, tbl1.b FROM ...
在使用多个表时,要求一个特定表的所有列也是有用的:
1SELECT tbl1.*, tbl2.a FROM ...
如果将任意值表达式用于选择列表,那么它在概念上向返回的表中增加了一个新的虚拟列。 值表达式为结果的每一行进行一次计算,对任何列引用替换行的值。
不过选择列表中的这个表达式并非一定要引用来自FROM子句中表表达式里面的列,例如它也可以是任意常量算术表达式。
列标签
选择列表中的项可以被赋予名字,用于进一步的处理。 例如为了在一个ORDER BY子句中使用或者为了客户端应用显示。例如:
1SELECT a AS value, b + c AS sum FROM ...
如果没有使用AS指定输出列名,那么系统会分配一个缺省的列名。对于简单的列引用,它是被引用列的名字。对于函数调用,它是函数的名字。对于复杂表达式,系统会生成一个通用的名字。
只有在新列无法匹配任何PalopgSQL关键字时,AS关键字是可选的。为了避免一个关键字的意外匹配,你可以使用双引号来修饰列名。例如,VALUE是一个关键字,所以下面的语句不会工作:
1SELECT a value, b + c AS sum FROM ...
但是这个可以:
1SELECT a "value", b + c AS sum FROM ...
为了防止未来可能的关键字增加,我们推荐总是写AS或者用双引号修饰输出列名。
注意
输出列的命名和在FROM子句里的命名是不一样的(参阅表和列别名章节)。
它实际上允许你对同一个列命名两次,但是在选择列表中分配的名字是要传递下去的名字。
DISTINCT
在处理完选择列表之后,结果表可以可选的删除重复行。我们可以直接在SELECT后面写上DISTINCT关键字来指定:
1SELECT DISTINCT select_list ...
(如果不用DISTINCT你可以用ALL关键字来指定获得的所有行的缺省行为)。
显然,如果两行里至少有一个列有不同的值,那么我们认为它是可区分的。空值在这种比较中被认为是相同的。
另外,我们还可以用任意表达式来判断什么行可以被认为是可区分的:
1SELECT DISTINCT ON (expression [, expression ...]) select_list ...
这里expression是任意值表达式,它计算所有行。如果某个行集合里所有表达式的值是一样的,那么我们认为它们是重复的,因此只有第一行保留在输出中。请注意某个集合的“第一行”是不可预料的,除非你在足够多的列上对该查询排了序,保证到达DISTINCT过滤器的行的顺序是唯一的(DISTINCT ON处理是发生在ORDER BY排序后面的)。
DISTINCT ON子句不是 SQL 标准的一部分, 有时候有人认为它是一个糟糕的风格,因为它的结果是不可判定的。
如果有选择的使用GROUP BY和在FROM中的子查询,那么我们可以避免使用这个构造,
但是通常它是更方便的候选方法。
行排序
在一个查询生成一个输出表之后(在处理完选择列表之后),还可以选择性地对它进行排序。如果没有选择排序,那么行将以未指定的顺序返回。
这时候的实际顺序将取决于扫描和连接计划类型以及行在磁盘上的顺序,但是肯定不能依赖这些东西。一种特定的顺序只能在显式地选择了排序步骤之后才能被保证。
ORDER BY子句指定了排序顺序:
1SELECT select_list
2 FROM table_expression
3 ORDER BY sort_expression1 [ASC | DESC] [NULLS { FIRST | LAST }]
4 [, sort_expression2 [ASC | DESC] [NULLS { FIRST | LAST }] ...]
排序表达式可以是任何在查询的选择列表中合法的表达式。一个例子是:
1SELECT a, b FROM table1 ORDER BY a + b, c;
当多于一个表达式被指定,后面的值将被用于排序那些在前面值上相等的行。每一个表达式后可以选择性地放置一个ASC或DESC关键字来设置排序方向为升序或降序。ASC顺序是默认值。升序会把较小的值放在前面,而“较小”则由<操作符定义。相似地,降序则由>操作符定义。
NULLS FIRST和NULLS LAST选项将可以被用来决定在排序顺序中,空值是出现在非空值之前或者出现在非空值之后。默认情况下,排序时空值被认为比任何非空值都要大,即NULLS FIRST是DESC顺序的默认值,而不是NULLS LAST的默认值。
注意顺序选项是对每一个排序列独立考虑的。例如ORDER BY x, y DESC表示ORDER BY x ASC, y DESC,而和ORDER BY x DESC, y DESC不同。
一个sort_expression也可以是列标签或者一个输出列的编号,如:
1SELECT a + b AS sum, c FROM table1 ORDER BY sum;
2SELECT a, max(b) FROM table1 GROUP BY a ORDER BY 1;
两者都根据第一个输出列排序。注意一个输出列的名字必须孤立,即它不能被用在一个表达式中 — 例如,这是不正确的:
1SELECT a + b AS sum, c FROM table1 ORDER BY sum + c; -- 错误
该限制是为了减少混淆。如果一个ORDER BY项是一个单一名字并且匹配一个输出列名或者一个表表达式的列,仍然会出现混淆。在这种情况中输出列将被使用。只有在你使用AS来重命名一个输出列来匹配某些其他表列的名字时,这才会导致混淆。
ORDER BY可以被应用于UNION、INTERSECT或EXCEPT组合的结果,但是在这种情况中它只被允许根据输出列名或编号排序,而不能根据表达式排序。
事实上,PalopgSQL为表达式的数据类型使用默认B-tree操作符类来决定ASC和DESC的排序顺序。照惯例,数据类型将被建立,这样<和>操作符负责这个排序顺序,但是一个用户定义的数据类型的设计者可以选择做些不同的设置。
评价此篇文章
