聚集表达式
一个聚集表达式代表一个聚集函数对一个查询选出的行的处理。 一个聚集函数把多个输入缩减为一个输出值, 比如给输入求和或平均。一个聚集表达式的语法是下列之一:
aggregate_name (expression)
aggregate_name (ALL expression)
aggregate_name (DISTINCT expression)
aggregate_name ( * )
这里 aggregate_name 是前面定义的聚集,(可能是全称), 而 expression 是一个本身不包含聚集表达式的任意值表达式。
第一种形式的聚集表达式为所有表达式生成非空值的输入行调用聚集。 (实际上,是否忽略空值由聚集函数决定 — 但是所有标准的聚集函数都忽略它们。) 第二种形式和第一种一样,因为 ALL 是缺省值。 第三种形式为所有输入行里找到表达式的所有唯一的非空值调用聚集。 最后一种形式为每个输入行(不管是空还是非空)调用一次聚集; 因为没有声明特定的输入值。通常它只是对 count() 聚集函数有用。
比如,count(*) 生成输入行的总数; count(f1) 生成 f1 为非空的输入行数; count(distinct f1) 生成 f1 唯一非空的行数。
预定义的聚集函数在 Section 9.15 里描述。 其它聚集函数可以由用户增加。
一个聚集表达式只能在 SELECT 命令的结果列表或者 HAVING 子句里出现。 禁止在其它子句里出现,比如 WHERE 里面,因为这些子句逻辑上在生成聚集结果之前计算。
如果一个聚集表达式出现在一个子查询里(参阅 Section 4.2.9 和 Section 9.16), 聚集通常是在子查询的行上进行计算。但是如果聚集的参数只包含外层查询的变量则有一个例外: 这个聚集会属于离他最近的外层查询,并且在该查询上进行计算。 该聚集表达式整体上属于它出现的子查询对外层查询的引用,其作用相当于子查询任何一次计算中的一个常量。 这个聚集表达式的有关只能出现在结果列或者 HAVING 子句的限制适用于聚集所属的查询层。
一个类型转换声明一个从一种数据类型到另外一种数据类型的转换。 PostgreSQL 接受两种等效的类型转换语法:
CAST ( expression AS type )
expression::type
CAST 语法遵循 SQL;:: 的语法是 PostgreSQL 传统用法。
如果对一个已知类型的值表达式应用转换,它代表一个运行时类型转换。 只有在定义了合适的类型转换操作的情况下,该转换才能成功。 请注意这一点和用于常量的转换略有区别,如 Section 4.1.2.5 所示。 一个应用于某个未修饰的字串文本的转换表示给一个字串文本数值赋予一个初始化类型, 因此它对于任何类型都会成功(如果字串文本的内容符合该数据类型的输入语法接受。)
如果对于一个值表达式生成的数值对某类型而言不存在混淆的情况, 那么我们可以省略明确的类型转换(比如,在给一个表字段赋值的时候); 在这样的情况下,系统将自动附加一个类型转换。 不过,自动转换只适用于那些系统表中标记着 "OK to apply implicitly" 的转换函数。 其它转换函数必须用明确的转换语法调用。 这些限制是为了避免一些怪异的转换被应用。
我们也可以用函数样的语法声明一个类型转换:
typename ( expression )
不过,这个方法只能用于那些名字同时也是有效函数名字的类型。 比如,double precision 就不能这么用, 但是等效的 float8 可以。同样,interval, time,和 timestamp 如果加了双引号也只能这么用, 因为存在语法冲突。因此,函数样的类型转换会导致不一致, 所以可能应该避免在新应用中这么用。 (函数样语法实际上就似乎一个函数调用。如果使用两种标准转换语法做运行时转换, 那么它将在内部调用一个已注册得函数执行转换。通常, 这种转换函数和它们得输出类型同名,但是这个要点可不是那些可以移植的程序可以依赖的东西。)
一个标量子查询是一个放在圆括弧里的普通 SELECT查询, 它只返回只有一个字段的一行。(参阅 Chapter 7 获取有关写查询的信息。) 该 SELECT 将被执行, 而其单个返回值将在周围的值表达式中使用。 把一个返回超过一行或者超过一列的查询用做标量查询是错误的。 (不过,在特定的执行中,子查询不返回行则不算错误;标量结果认为是NULL。) 该子查询可以引用周围查询的变量,那些变量也是在计算任意子查询的时候当做常量使用的。 又见 Section 9.16。
比如,下面的查询找出每个州中的最大人口数量的城市:
SELECT name, (SELECT max(pop) FROM cities WHERE cities.state = states.name)
FROM states;
一个数组构造器是一个表达式,它从它的成员元素上构造一个数组值。 一个简单的数组构造器由关键字 ARRAY,一个左方括弧 [, 一个或多个表达式(用逗号分隔)表示数组元素值,以及最后一个右方括弧 ]。 比如
SELECT ARRAY[1,2,3+4];
array
---------
{1,2,7}
(1 row)
数组元素类型是成员表达式的公共类型,使用和 UNION 或 CASE 构造一样的规则决定。 (参阅 Section 10.5)。
多维数组值可以通过嵌套数组构造器的方法来制作。 在内层构造器里,关键字 ARRAY 可以省略。比如,下面的两句生成同样的结果:
SELECT ARRAY[ARRAY[1,2], ARRAY[3,4]];
array
---------------
{{1,2},{3,4}}
(1 row)
SELECT ARRAY[[1,2],[3,4]];
array
---------------
{{1,2},{3,4}}
(1 row)
因为多维数组必须是方形,同层的内层构造器必须生成同维的子数组。
多维数组构造器元素可以是任何生成合适数组的东西,而不仅仅是一个子 ARRAY 构造。 比如:
CREATE TABLE arr(f1 int[], f2 int[]);
INSERT INTO arr VALUES (ARRAY[[1,2],[3,4]], ARRAY[[5,6],[7,8]]);
SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM arr;
array
------------------------------------------------
{{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}}
(1 row)
我们也可以从一个子查询的结果中构造一个数组。在这种形式下, 数组构造器是用关键字 ARRAY 后面跟着一个用圆括弧(不是方括弧)包围的子查询。 比如:
SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%');
?column?
-------------------------------------------------------------
{2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31}
(1 row)
子查询必须返回一个字段。生成的一维数组将为子查询里每行结果生成一个元素, 元素类型匹配子查询的输出字段。
用 ARRAY 建立的数组值的脚标总是从一开始。 有关数组的更多信息,参阅 Section 8.10。
一个行构造器是一个从提供给它的成员字段数值中制作行数值(也叫复合类型值)的表达式。 一个行构造器由关键字 ROW,一个左圆括弧, 零个或者多个用做行字段值的表达式(用逗号分隔),以及最后一个右圆括弧。比如,
SELECT ROW(1,2.5,'this is a test');
如果在列表里有多个表达式,那么关键字 ROW 是可选的。
缺省时,ROW 表达式创建的值是一个匿名的记录类型。如果必要,你可以把它转换成一个命名的复合类型 — 既可以是一个表的行类型,也可以是一个用 CREATE TYPE AS 创建的复合类型。 可能会需要一个明确的转换以避免歧义。比如:
CREATE TABLE mytable(f1 int, f2 float, f3 text);
CREATE FUNCTION getf1(mytable) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;
-- 因为只有一个 getf1() 存在,所以不需要类型转换
SELECT getf1(ROW(1,2.5,'this is a test'));
getf1
-------
1
(1 row)
CREATE TYPE myrowtype AS (f1 int, f2 text, f3 numeric);
CREATE FUNCTION getf1(myrowtype) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL;
-- 现在我们需要类型转换以表明调用哪个函数:
SELECT getf1(ROW(1,2.5,'this is a test'));
ERROR: function getf1(record) is not unique
SELECT getf1(ROW(1,2.5,'this is a test')::mytable);
getf1
-------
1
(1 row)
SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype));
getf1
-------
11
(1 row)
行构造器可以用于制作存储在复合类型表字段里面的复合类型值, 或者是传递给一个接受复合类型参数的函数。还有,我们也可以比较两个行数值或者用 IS NULL 或 IS NOT NULL 测试一个行数值,比如
SELECT ROW(1,2.5,'this is a test') = ROW(1, 3, 'not the same');
SELECT ROW(a, b, c) IS NOT NULL FROM table;
更多的细节,请参阅 Section 9.17。 行构造还可以用于连接子查询,这些在 Section 9.16 里面有详细讨论。
子表达式的计算顺序是没有定义的。特别要指出的是, 一个操作符或者函数的输入并不一定是按照从左向右的顺序或者以某种特定的顺序进行计算的。
另外,如果一个表达式的结果可以通过只判断它的一部分就可以得到, 那么其它子表达式就可以完全不计算了。比如,如果我们这么写
SELECT true OR somefunc();
那么 somefunc() 就(可能)根本不会被调用。 如果我们写下面的,也可能会是这样
SELECT somefunc() OR true;
请注意这里和某些编程语言里的从左向右"短路"是不一样的。
因此,拿那些有副作用的函数作为复杂表达式的一部分是不明智的选择。 在 WHERE 和 HAVING 子句里面依赖副作用或者是计算顺序是特别危险的, 因为这些子句都是作为生成一个执行规划的一部分进行了大量的再处理。 在这些子句里的布尔表达式(AND/OR/NOT 的组合)可以以布尔代数运算律允许的任意方式进行识别。
如果强制计算顺序非常重要,那么可以使用 CASE 构造(参阅 Section 9.13)。 比如,下面是一种视图避免在 WHERE 子句里被零除的不可信的方法:
SELECT ... WHERE x <> 0 AND y/x > 1.5;
但是下面这样的是安全的:
SELECT ... WHERE CASE WHEN x <> 0 THEN y/x > 1.5 ELSE false END;
用这种风格的 CASE 构造会阻止优化,因此应该只在必要的时候使用。 (在这个特殊的例子里,毫无疑问写成 y > 1.5*x 更好。)
分享到:
相关推荐
4. **索引表达式**:在这个版本中,用户可以基于表达式的值创建索引,这在优化查询性能方面特别有用,特别是对于复杂的WHERE子句。 5. **JSON支持**:虽然不是9.0.1版本特有的,但9.0开始提供对JSON数据类型的支持...
- **窗口函数**:“WindowFunctions”部分介绍了窗口函数的使用方法,这是一种能够基于一组有序的行来计算聚合值的强大工具。 - **继承**:“Inheritance”部分讨论了PostgreSQL中的继承机制,这是一种允许表之间...
PostgreSQL 函数 ... 它返回包含该值的行的表、列和ctid ,以及在正则表达式搜索的情况下的值本身。 搜索可以限于表和/或模式的阵列。 可选择通过发出raise info消息来报告进度。 汉明重量 返回字节
8. **数据类型**:PostgreSQL拥有丰富的数据类型,包括数字、货币、字符、比特流、字节流、时间、布尔值、枚举、几何类型、网络地址、全文检索、UUID、XML、JSON、数组等,甚至支持自定义复合类型和范围类型。...
4. **Token & Value**:Token 包含类型和值两部分。 5. **yyparse**:语法分析器的主要函数,根据文法定义生成抽象语法树。 6. **ParserTree**:最终生成的解析树。 #### 七、总结 通过对 PostgreSQL 解析器内核的...
- **表达式**: 支持各种算术、逻辑和字符串表达式。 ##### 7. Conditional Statements - **IF-THEN**: 基本条件语句。 - **IF-THEN-ELSE**: 增加了其他情况处理。 - **IF-THEN-ELSIF**: 支持多个条件分支。 - **...
CASE表达式用于根据条件返回不同的值。DB2与GreenPlum/PostgreSQL在这方面的实现相似,但在语法和功能上可能存在细微差异。 #### 2.6 列函数 列函数用于对表中的列执行聚合操作,如SUM、AVG等。DB2与GreenPlum/...
* 数据类型:包括整数、字符串、日期时间、布尔值等基本数据类型。 * 表达式:包括算术运算符、比较运算符、逻辑运算符和字符串操作符等。 索引与查询优化 * 索引:包括B-tree索引、哈希索引和GiST索引等类型。 * ...
### PostgreSQL Developer's Guide 2015 - 关键知识点概览 #### 1. 开始使用 PostgreSQL **1.1 写查询语句使用 psql** - **psql**: PostgreSQL 的命令行工具,用于执行 SQL 查询。 - **常用操作**: 通过 `SELECT`...
2. **Pcre**:Nginx使用Pcre来解析正则表达式。 3. **Zlib**:提供压缩和解压缩功能。 4. **OpenSSL**:提供加密功能。 ##### GCC编译环境安装 ```bash $ yum install -y gcc gcc-c++ ``` ##### Pcre安装 ```bash ...
该库为MySQL和PostgreSQL提供了一组Doctrine DQL函数。 可用功能: DATE(expr) -提取日期或日期时间表达式的日期部分。 TIME(expr) -提取提供的表达式的时间部分。 TIMESTAMP(expr) -将表达式转换为TIMESTAMP。 ...
pax-on-postgresql这个程序是在一个叫做信息特殊练习 2 的课程...where子句的条件表达式由and连接,属性值比较运算符为=。执行本次使用的PostgreSQL版本为9.3.5。具体而言,更改了以下部分。postgresql-9.3.5 /src/bac
8. **索引表达式**:除了基于列的索引,PostgreSQL还支持基于表达式的索引,这使得能够为复杂的查询条件创建索引。 9. **连接优化**:优化JOIN操作是查询优化的关键。使用合适的JOIN类型(如INNER JOIN、LEFT JOIN...
- **值表达式**: 如何使用不同的值表达式来构建 SQL 语句。 - **数据定义**: 创建、修改和删除表结构等操作。 - **数据操作**: 插入、更新和删除数据的方法。 - **查询**: 如何编写复杂的查询语句。 - **数据类型**:...
在SQL语法部分,手册详细解释了PostgreSQL的词法结构、值表达式、调用函数等方面的内容,为用户提供了编写有效SQL代码的理论基础。数据定义章节则涉及了表的基本概念、缺省值、约束、系统字段、修改表、权限、模式、...
- 模式匹配:支持正则表达式等模式匹配操作。 - 时间/日期函数和操作符:提供了处理时间日期数据的函数和操作符。 - 序列操作函数:提供了操作序列(SERIAL字段对应的序列对象)的函数。 - 系统信息函数:用于...
FOR 变量 IN 表达式 LOOP -- statements END LOOP; ``` 3. 跳转语句 PostgreSQL 存储过程支持多种跳转语句,包括 `EXIT` 和 `CONTINUE`。例如: ``` LOOP -- statements EXIT WHEN 条件; CONTINUE WHEN 条件; ...
3. **RETURNING子句改进**:在INSERT、UPDATE和DELETE语句中,RETURNING子句可以返回被修改或删除的行,9.5版本增强了这一功能,支持更多的表达式和计算。 4. **逻辑复制**:这是一个重要的新特性,允许数据库之间...