[WITH with_queries] SELECT select_list FROM table_expression [sort_specification]
1、select_list
a、“*” :遍历所有行和用户定义的所有列从表中。select_list也可以使用可用列的子集或列的计算,如:
select a, b+c from table1.
b、使用select命令忽略table_expression,将其当做计算器,如:select 3*4;
c、select_list中返回不同的结果,你可以调用一个函数,如:select random();
2、table_expression
table_expression包含from从句,后面可跟where,group by,having从句,简单的table_expression引用磁盘上的表,但复杂的table_expression可以以不同的方式修改or结合基表。
可选where,group by,having从句指定逐次转换管道执行在from子句派生表中。所有的转换产生一个虚表,提供通过select_list 计算查询输出的行
a、from 从句
从给定的一个逗号分隔的表引用列表派生一个or多个其他表,语法:
from table_reference [, table_reference [, …]]
table_reference可以是一个表的名称、派生表如子查询、表连接or这些复杂的组合。如果超过一个table_reference在from从句中列出,它们交叉连接形成中间虚表,然后通过where,group by,having从句转换,形成最后的整个表的表达式。
表连接
一个表连接是来自其他2个表(实表or派生表)根据特定连接类型的规则。
cross join
T1 cross join T2
从T1和T2中行进行每一个可能的组合,如笛卡尔积。T1中有n行,T2中有m行,那么交叉连接后,连接表有n*m行。
From T1 cross join T2 等效于 from T1, T2
也等效于:from T1 inner join T2 on true
限制连接
T1 {[inner]|{left|right|full}[outer]} join T2 on boolean_expression
T1 {[inner]|{left|right|full}[outer]} join T2 using(join column list)
T1 natural {[inner]|{left|right|full}[outer]} join T2
inner 和 outer 在所有连接中是可选的,默认为inner;left,right,full属于outer。
连接条件通过on 或 using从句or 通过关键字natural指定,连接条件决定了哪些行从2个源表匹配,详细如下:
on从句最普遍的一个连接条件:类似于where从句中的布尔表达式,若on从句为true时,T1和T2匹配一对行。
using是一个速记符号:它以逗号分隔列名称的列表,连接表必须有相同的列,形成一个连接条件所指定的每一个列是相等。所以,using(a,b,c) 等效于 on(t1.a=t2.a and t1.b=t2.b and t1.c=t2.c)
natural是using的一个速记:使用using列表包含在输入表中所有列的名称,如没有共同列,natural的行为类似于交叉连接
inner join
在T1中每行R1,在T2中的每一行满足连接条件R1的行
left outer join
首先,执行inner join,然后,为T1中不满足连接条件T2中任何行,连接行在T2中的列使用null值被添加,所以,连接表中至少有1行对应T1中的行。
right outer join
首先,执行inner join,然后,为T2中不满足连接条件T1中任何行,连接行在T1中的列使用null值被添加,所以,连接表中至少有1行对应T2中的行。
full outer join
首先,执行inner join,然后, 为T1中不满足连接条件T2中任何行,连接行在T2中的列使用null值被添加; 为T2中不满足连接条件T1中任何行,连接行在T1中的列使用null值被添加。
t1表
num | name
-----+------
1 | a
2 | b
3 | c
(3 rows)
t2表
num | value
-----+-------
1 | xxx
3 | yyy
5 | zzz
(3 rows)
select * from t1 cross join t2;
select * from t1 inner join t2 on t1.num=t2.num;
select * from t1 inner join t2 using(num);
select * from t1 natural inner join t2;
select * from t1 left join t2 on t1.num=t2.num;
select * from t1 left join t2 using(num);
select * from t1 right join t2 on t1.num=t2.num;
select * from t1 right join t2 using(num);
select * from t1 full join t2 on t1.num=t2.num;
select * from t1 full join t2 using(num);
on从句也能够包含条件,但涉及直接表连接,可能对一些查询是有用:
select * from t1 left join t2 on t1.num=t2.num and t2.value='xxx';
注意:添加where从句将得到不同的结果
select * from t1 left join t2 on t1.num=t2.num where t2.value='xxx';
因为在表连接前的on从句已经被处理,而表连接之后where从句被处理。
表和列的别名
可以给表取一个临时的名字,在查询的其余部分引用,创建表的别名:
from table_reference as alias;
或
from table_reference alias;
通常,对表名称较长设置别名,可保持join从句可读性
设置别名是当前查询引用表的新名称,在该查询中不允许再使用原名称
当join从句输出结果使用别名,该别名隐藏了join从句内的原名称
子查询
指定一个派生表必须包括在括号中,必须指定表的别名,如:
from(select * from table1) as alias_name
当子查询中涉及分组or聚集时,它不能降低到一个普通的表连接
子查询也能表示值列表
from (values('anne', 'smith'), ('bob','jone')) as names(first, last);
为值列表的列指定别名也是可选的
表函数
产生行集的函数,由基本数据类型和组合数据类型组成。在查询的from从句中,它们使用像一张表,视图or子查询。通过表函数返回的列可以包含在select、join或where从句中以相同的方式作为一个表,视图or子查询的列。
如果一个表函数返回一个基本数据类型,单结果列名匹配函数名,若函数返回复合类型,这些列的结果得到一个该类型个体属性。
b、where从句
where search_condition
search_condition返回boolean类型的值
在from从句处理完成后,从派生虚表中的每一行检查search_condition,如检查结果为true,那么该行被保持在输出表中,否则(false/null)它将被丢弃。search_condition通常引用from从句中生成表中的至少一列,这不是必需,但否则,where从句没有意义。
c、group by从句和having 从句
通过where从句过滤后,可能从派生的输入表进行分组,使用group by从句,使用having从句消除组行。
select select_list from … [where …]
group by grouping_column_reference [, grouping_column_reference]...
将表中所有列中有相同值的列组合在一起,消除冗余的输出or聚集计算。如:
表test1
x | y
---+---
a | 3
c | 2
b | 5
a | 1
(4 rows)
select x from test1 group by x;
这里不能执行:select * from test1 group by x ,因为表中y列没有单一的值与每一个组相关,分组的列可以引用select_list中的列因为它们在每一组中有单一值。
通常,若一个表被分组,没有列在group by从句中的列不能被引用除了在聚合表达式中的列,如:select x, sum(y) from test1 group by x;
在严格的sql中,group by从句后列仅仅指源表中的列,但pg扩展,允许group by从句后的列是select_list中的列,分组表达式取代简单列名也被支持。
若一张表已经使用group by进行分组,但只对一些组感兴趣,可以使用having从句过滤,类似与where从句,但只从分组的结果中过滤。语法:
select select_list from … [where …] group by …
having boolean_expression
boolean_expression可以引用分组表达式和未分组的表达式(在一个聚合函数中的)
eg:
select x, sum(y) from test1 group by x having sum(y) > 3;
select x, sum(y) from test1 group by x having x < 'c';
3、select lists
table_expression可以通过组合表、视图、分组等构建一个中间虚表,该表最终由select_list处理,select_list来确定中间表中的哪些列被输出。
select_list items
最简单的一种select_list是*,输出由table_expression产生的所有列,否则,select_list是一个逗号分隔的值表达式or列的名字,列的名字可以是表中真实列名字or别名。若有多于1张表有相同的列名,那么必须给定其表的名称,如:
Select tb1.a, tb2.a from …
如果在select_list增加任意的值表达式,那么再返回表中增加一个新的虚拟列,值表达式对返回结果的每一行求值一次。
column labels
select_list中的项可以为后续处理指定一个名称,该名称可用于如order by从句or客户端的应用程序,如:
select a as value, b+c as sum from …
若没有使用as指定列名,系统默认引用列名。函数调用,则使用函数名。复杂表达式,系统将生成一个通用的名称。as为可选,为避免列名与pg中的关键字冲突,可以使用双引号,如:
Select a value, b+c as sum from … //value 为pg中关键字
Select a “value”, b+c as sum from …
distinct
select_list处理后,结果表可以通过distinct来消除重复行,如:
select distinct select_list from …
用all取代distinct可保持所有行的默认行为。如果2行中至少一列值不同,则2行认为是不同的,null值在比较是相同的。另外,一个任意表达可以确定哪些行是不同的,语法:
Select distinct on (expression [, expression …]) select_list …
expression:评估所有行的任意值表达式,一个行集的所有表达式相等被视为重复,只有行集中的第一个保留到输出中。注意,行集的第一行是不可预知的,除非足够列的查询是排序,保证唯一的行排序在distinct处理前(distinct处理发生在order by之后)
distinct on从句不是sql标准,有时被认为不好的风格,因为处理结果的不确定性,较好的做法:在from从句中使用group by和子查询。
4、combining queries
2个查询结果可以使用union、intersection、difference操作符进行结合,语法:
query1 union [all] query2
query1 intersect [all] query2
query1 except [all] query2
set operations可以被嵌套or组成链,如:
query1 union query2 union query3
union:添加query2的结果到query1中,虽然没有保证行真实返回的顺序。从它的结果中消除了重复行,类似于distinct;若使用union all不会消除重复行。
intersect:包含query1和query2中的所有行,重复行会消除除非all使用
except:返回在query1中不在query2中的所有行,重复行会消除除非all使用。
为了计算2个查询结果的union、intersection、difference,这2个query必须兼容,即他们返回相同的列数和相应的列具有兼容的数据类型。
5、Sorting Rows
经过查询产生的输出列表(在select list处理之后)可以排序,如不指定行的排序,将返回一个不确定的行顺序,实际的顺序依赖于扫描和连接计划类型以及磁盘上的顺序,但这个是不能依靠,只有明确指定排序才能返回一个特定的输出顺序。
order by从句指定排序:
select select_list from table_expression
order by sort_expression [ASC|DESC] [NULLS {FIRST|LAST}]
[, sort_expression2 [ASC|DESC] [NULLS {FIRST|LAST}] …]
sort_expression(s)可以是select_list中任何有效的表达式:
select a,b from table1 order by a+b, c;
当指定排序表达式多个时,后面的排序表达式行排序是根据其前面的排序表达式的值进行比较。每个表达式后面可跟ASC 或DESC关键字来指定行的顺序是升序or降序,默认为ASC。
NULLS FIRST 或NULLS LAST 是用来确定nulls出现在 non-nulls之前或之后。默认null值排序大于任何non-null值,因此, NULLS FIRST是DESC的默认方式。
注意,排序选项是独立的排序列,order by x,y DESC 等于 order by x ASC,y DESC
一个 sort_expression可以是列标签名 or 输出列数,如根据输出的第一列排序:
select a+b as sum, c from table1 order by sum;
select a, max(b) from table1 group by a order by 1;
注意,输出列是单独的列,如下面错误方式:
select a+b as sum, c from table1 order by sum + c;
这个限制减少了混乱,如果排序项名称既匹配输出列名字或表中列的名字时仍然存在混乱。
6、limit and offset
limit and offset允许你检索一部分的行集,语法:
select select_list from table_expression
[order by …]
[limit {number|ALL}] [offset number]
如果指定limit count,不会有更多的行返回(但可能少于count,如果查询本身行小于count)。Limit ALL等同于与忽略limit从句。
offset跳过多少行开始检索返回行。Offset 0 相当于忽略offset从句。
当使用Limit时,使用order by 从句约束结果行集到一个唯一的序列非常重要。否则,你得到一个不可预知的子集,你可能会问第十行至第二十行,但第十行至第二十行是什么样的顺序?此顺序未知,除非你明确指定order by
查询优化以使用limit到账户当生成查询计划时,所以你很有可能根据的给的limit 和 offset获取不同的查询计划。因此,使用limit/offset值来选择查询结果的不同子集。
由于offset从句是在服务器端计算,因此一个大的offset可能是低效的。
7、values lists
values提供一个生成常量表的方式,它可以使用在一个没有真实创建和操作磁盘上表的查询上,语法:
values (expression [, ...]) [, …]
每个括号内的列表生成表里的一行,列表必须有相同的元素数量(相当于表相同数量列)并且,每个列表中相应的元素具有兼容的数据类型。结果列的实际类型由相同规则决定通过union,如:
VALUES (1, 'one'), (2, 'two'), (3, 'three');
等效于
SELECT 1 AS column1, 'one' AS column2
UNION ALL
SELECT 2, 'two' UNION ALL SELECT 3, 'three';
默认,pg指定column1,column2,等为值表的列。这个column name不是sql标准并且不同的数据库系统可能不一致,故,最好的做法使用表的别名重写默认方法的名字,如:
select * from (values (1,'one'),(2,'two'),(3,'three')) as t(num, letter);