如果数据集中存在循环,数据库会提供循环检测。默认行为检查到循环会直接报错,不返回任何数据。同时,提供NOCYCLE关键字,查询可以正常执行,只是碰到第一条重复的数据时,会直接退出,而不是报错。
此外,在层次查询过程中,严格按照深度优先搜索的顺序进行。如果在start with或connect by中使用rownum作为过滤条件,对于每条尝试被返回的记录,rownum会先加1,之后按照rownum相关条件判断;对于不满足的记录,会被丢弃且rownum会减1。
EXCEPT子句EXCEPT子句有如下的通用形式:
select_statement EXCEPT [ ALL ] select_statement
select_statement是任何没有FOR UPDATE,FOR NO KEY UPDATE,FOR SHARE或FOR KEY SHARE子句的SELECT表达式。
EXCEPT操作符计算存在于左边SELECT语句的输出而不存在于右边SELECT语句输出的行。
EXCEPT的结果不包含任何重复的行,除非声明了ALL选项。使用ALL时,一个在左边表中有m个重复而在右边表中有n个重复的行将在结果中出现max(m-n,0) 次。
除非用圆括弧指明顺序,否则同一个SELECT语句中的多个EXCEPT操作符是从左向右计算的。EXCEPT和UNION的绑定级别相同。
目前,不能给EXCEPT的结果或者任何EXCEPT的输入声明FOR UPDATE,FOR NO KEY UPDATE,FOR SHARE和FOR KEY SHARE子句。
MINUS子句与EXCEPT子句具有相同的功能和用法。
ORDER BY子句对SELECT语句检索得到的数据进行升序或降序排序。对于ORDER BY表达式中包含多列的情况:
首先根据最左边的列进行排序,如果这一列的值相同,则根据下一个表达式进行比较,依此类推。
如果对于所有声明的表达式都相同,则按随机顺序返回。
在与DISTINCT关键字一起使用的情况下,ORDER BY中排序的列必须包括在SELECT语句所检索的结果集的列中。
在与GROUP BY子句一起使用的情况下,ORDER BY中排序的列必须包括在SELECT语句所检索的结果集的列中。
如果要支持中文拼音排序,需要在初始化数据库时指定编码格式为UTF-8、GB18030或GBK。命令如下:
initdb –E UTF8 –D ../data –locale=zh_CN.UTF-8、initdb -E GB18030 -D ../data -locale=zh_CN.GB18030或initdb –E GBK –D ../data –locale=zh_CN.GBK。
LIMIT子句LIMIT子句由两个独立的子句组成:
LIMIT { count | ALL }
OFFSET start count声明返回的最大行数,而start声明开始返回行之前忽略的行数。如果两个都指定了,会在开始计算count个返回行之前先跳过start行。
LIMIT子句不支持ROWNUM作为count或者offset。
OFFSET子句SQL:2008开始提出一种不同的语法:
OFFSET start { ROW | ROWS }
start声明开始返回行之前忽略的行数。
FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY如果不指定count,默认值为1,FETCH子句限定返回查询结果从第一行开始的总行数。
锁定子句FOR UPDATE子句将对SELECT检索出来的行进行加锁。这样避免它们在当前事务结束前被其他事务修改或者删除,即其他企图UPDATE、 DELETE、 SELECT FOR UPDATE、SELECT FOR NO KEY UPDATE, SELECT FOR SHARE 或 SELECT FOR KEY SHARE这些行的事务将被阻塞,直到当前事务结束。任何在一行上的DELETE命令也会获得FOR UPDATE锁模式,在主键列上修改值的UPDATE也会获得该锁模式。反过来,SELECT FOR UPDATE将等待已经在相同行上运行以上这些命令的并发事务,并且接着锁定并且返回被更新的行(或者没有行,因为行可能已被删除)。
FOR NO KEY UPDATE行为与FOR UPDATE类似,不过获得的锁较弱,这种锁将不会阻塞尝试在相同行上获得锁的SELECT FOR KEY SHARE命令。任何不获取FOR UPDATE锁的UPDATE也会获得这种锁模式。
FOR SHARE的行为类似,只是它在每个检索出来的行上要求一个共享锁,而不是一个排他锁。一个共享锁阻塞其它事务执行UPDATE、DELETE、SELECT FOR UPDATE或者SELECT FOR NO KEY UPDATE,不阻塞SELECT FOR SHARE或者SELECT FOR KEY SHARE。
FOR KEY SHARE行为与FOR SHARE类似,不过锁较弱,SELECT FOR UPDATE会被阻塞,但是SELECT FOR NO KEY UPDATE不会被阻塞。一个键共享锁会阻塞其他事务执行修改键值的DELETE或者UPDATE,但不会阻塞其他UPDATE,也不会阻止SELECT FOR NO KEY UPDATE、SELECT FOR SHARE或者SELECT FOR KEY SHARE。
为了避免操作等待其他事务提交,可使用NOWAIT选项,如果被选择的行不能立即被锁住,将会立即汇报一个错误,而不是等待;WAIT N选项,如果被选择的行不能立即被锁住,等待N秒(其中,N为int类型,取值范围:0 <= N <= 2147483),N秒内获取锁则正常执行,否则报错。
如果在锁定子句中明确指定了表名称,则只有这些指定的表被锁定,其他在SELECT中使用的表将不会被锁定。否则,将锁定该命令中所有使用的表。
如果锁定子句应用于一个视图或者子查询,它同样将锁定所有该视图或子查询中使用到的表。
多个锁定子句可以用于为不同的表指定不同的锁定模式。
如果一个表中同时出现(或隐含同时出现)在多个子句中,则按照最强的锁处理。类似的,如果影响一个表的任意子句中出现了NOWAIT,该表将按照NOWAIT处理。
对列存表的查询不支持for update/no key update/share/key share。
对ustore表的查询只支持for share/for update,不支持for key share/for no key update。
对于子查询是stream计划的for update/share语句,不支持加锁的同一行被并发更新。
NLS_SORT指定某字段按照特殊方式排序。目前仅支持中文拼音格式排序和不区分大小写排序。如果要支持此排序方式,在创建数据库时需要指定编码格式为“UTF8”、”GB18030”或“GBK”;如果指定为其他编码,例如SQL_ASCII,则可能报错或者排序无效。
取值范围:
SCHINESE_PINYIN_M,按照中文拼音排序。
generic_m_ci,不区分大小写排序(可选,仅支持纯英文不区分大小写排序)。
PARTITION子句查询某个分区表中相应分区的数据。
--先通过子查询得到一张临时表temp_t,然后查询表temp_t中的所有数据。
gaussdb=# WITH temp_t(name,isdba) AS (SELECT usename,usesuper FROM pg_user) SELECT * FROM temp_t;
--查询tpcds.reason表的所有r_reason_sk记录,且去除重复。
gaussdb=# SELECT DISTINCT(r_reason_sk) FROM tpcds.reason;
--LIMIT子句示例:获取表中一条记录。
gaussdb=# SELECT * FROM tpcds.reason LIMIT 1;
--查询所有记录,且按字母升序排列。
gaussdb=# SELECT r_reason_desc FROM tpcds.reason ORDER BY r_reason_desc;
--通过表别名,从pg_user和pg_user_status这两张表中获取数据。
gaussdb=# SELECT a.usename,b.locktime FROM pg_user a,pg_user_status b WHERE a.usesysid=b.roloid;
--FULL JOIN子句示例:将pg_user和pg_user_status这两张表的数据进行全连接显示,即数据的合集。
gaussdb=# SELECT a.usename,b.locktime,a.usesuper FROM pg_user a FULL JOIN pg_user_status b on a.usesysid=b.roloid;
--GROUP BY子句示例:根据查询条件过滤,并对结果进行分组。
gaussdb=# SELECT r_reason_id, AVG(r_reason_sk) FROM tpcds.reason GROUP BY r_reason_id HAVING AVG(r_reason_sk) > 25;
--GROUP BY CUBE子句示例:根据查询条件过滤,并对结果进行分组汇总。
gaussdb=# SELECT r_reason_id,AVG(r_reason_sk) FROM tpcds.reason GROUP BY CUBE(r_reason_id,r_reason_sk);
--GROUP BY GROUPING SETS子句示例:根据查询条件过滤,并对结果进行分组汇总。
gaussdb=# SELECT r_reason_id,AVG(r_reason_sk) FROM tpcds.reason GROUP BY GROUPING SETS((r_reason_id,r_reason_sk),r_reason_sk);
--UNION子句示例:将表tpcds.reason里r_reason_desc字段中的内容以W开头和以N开头的进行合并。
gaussdb=# SELECT r_reason_sk, tpcds.reason.r_reason_desc
FROM tpcds.reason
WHERE tpcds.reason.r_reason_desc LIKE 'W%'
UNION
SELECT r_reason_sk, tpcds.reason.r_reason_desc
FROM tpcds.reason
WHERE tpcds.reason.r_reason_desc LIKE 'N%';
--NLS_SORT子句示例:中文拼音排序。
gaussdb=# SELECT * FROM tpcds.reason ORDER BY NLSSORT( r_reason_desc, 'NLS_SORT = SCHINESE_PINYIN_M');
--不区分大小写排序(可选,仅支持纯英文不区分大小写排序):
gaussdb=# SELECT * FROM tpcds.reason ORDER BY NLSSORT( r_reason_desc, 'NLS_SORT = generic_m_ci');
--创建分区表tpcds.reason_p
gaussdb=# CREATE TABLE tpcds.reason_p
r_reason_sk integer,
r_reason_id character(16),
r_reason_desc character(100)
PARTITION BY RANGE (r_reason_sk)
partition P_05_BEFORE values less than (05),
partition P_15 values less than (15),
partition P_25 values less than (25),
partition P_35 values less than (35),
partition P_45_AFTER values less than (MAXVALUE)
--插入数据。
gaussdb=# INSERT INTO tpcds.reason_p values(3,'AAAAAAAABAAAAAAA','reason 1'),(10,'AAAAAAAABAAAAAAA','reason 2'),(4,'AAAAAAAABAAAAAAA','reason 3'),(10,'AAAAAAAABAAAAAAA','reason 4'),(10,'AAAAAAAABAAAAAAA','reason 5'),(20,'AAAAAAAACAAAAAAA','reason 6'),(30,'AAAAAAAACAAAAAAA','reason 7');
--PARTITION子句示例:从tpcds.reason_p的表分区P_05_BEFORE中获取数据。
gaussdb=# SELECT * FROM tpcds.reason_p PARTITION (P_05_BEFORE);
r_reason_sk | r_reason_id | r_reason_desc
-------------+------------------+------------------------------------
4 | AAAAAAAABAAAAAAA | reason 3
3 | AAAAAAAABAAAAAAA | reason 1
(2 rows)
--GROUP BY子句示例:按r_reason_id分组统计tpcds.reason_p表中的记录数。
gaussdb=# SELECT COUNT(*),r_reason_id FROM tpcds.reason_p GROUP BY r_reason_id;
count | r_reason_id
-------+------------------
2 | AAAAAAAACAAAAAAA
5 | AAAAAAAABAAAAAAA
(2 rows)
--GROUP BY CUBE子句示例:根据查询条件过滤,并对查询结果分组汇总。
gaussdb=# SELECT * FROM tpcds.reason GROUP BY CUBE (r_reason_id,r_reason_sk,r_reason_desc);
--GROUP BY GROUPING SETS子句示例:根据查询条件过滤,并对查询结果分组汇总。
gaussdb=# SELECT * FROM tpcds.reason GROUP BY GROUPING SETS ((r_reason_id,r_reason_sk),r_reason_desc);
--HAVING子句示例:按r_reason_id分组统计tpcds.reason_p表中的记录,并只显示r_reason_id个数大于2的信息。
gaussdb=# SELECT COUNT(*) c,r_reason_id FROM tpcds.reason_p GROUP BY r_reason_id HAVING c>2;
c | r_reason_id
---+------------------
5 | AAAAAAAABAAAAAAA
(1 row)
--IN子句示例:按r_reason_id分组统计tpcds.reason_p表中的r_reason_id个数,并只显示r_reason_id值为 AAAAAAAABAAAAAAA或AAAAAAAADAAAAAAA的个数。
gaussdb=# SELECT COUNT(*),r_reason_id FROM tpcds.reason_p GROUP BY r_reason_id HAVING r_reason_id IN('AAAAAAAABAAAAAAA','AAAAAAAADAAAAAAA');
count | r_reason_id
-------+------------------
5 | AAAAAAAABAAAAAAA
(1 row)
--INTERSECT子句示例:查询r_reason_id等于AAAAAAAABAAAAAAA,并且r_reason_sk小于5的信息。
gaussdb=# SELECT * FROM tpcds.reason_p WHERE r_reason_id='AAAAAAAABAAAAAAA' INTERSECT SELECT * FROM tpcds.reason_p WHERE r_reason_sk<5;
r_reason_sk | r_reason_id | r_reason_desc
-------------+------------------+------------------------------------
4 | AAAAAAAABAAAAAAA | reason 3
3 | AAAAAAAABAAAAAAA | reason 1
(2 rows)
--EXCEPT子句示例:查询r_reason_id等于AAAAAAAABAAAAAAA,并且去除r_reason_sk小于4的信息。
gaussdb=# SELECT * FROM tpcds.reason_p WHERE r_reason_id='AAAAAAAABAAAAAAA' EXCEPT SELECT * FROM tpcds.reason_p WHERE r_reason_sk<4;
r_reason_sk | r_reason_id | r_reason_desc
-------------+------------------+------------------------------------
10 | AAAAAAAABAAAAAAA | reason 2
10 | AAAAAAAABAAAAAAA | reason 5
10 | AAAAAAAABAAAAAAA | reason 4
4 | AAAAAAAABAAAAAAA | reason 3
(4 rows)
--通过在where子句中指定"(+)"来实现左连接。
gaussdb=# select t1.sr_item_sk ,t2.c_customer_id from store_returns t1, customer t2 where t1.sr_customer_sk = t2.c_customer_sk(+)
order by 1 desc limit 1;
sr_item_sk | c_customer_id
------------+---------------
18000 |
(1 row)
--通过在where子句中指定"(+)"来实现右连接。
gaussdb=# select t1.sr_item_sk ,t2.c_customer_id from store_returns t1, customer t2 where t1.sr_customer_sk(+) = t2.c_customer_sk
order by 1 desc limit 1;
sr_item_sk | c_customer_id
------------+------------------
| AAAAAAAAJNGEBAAA
(1 row)
--通过在where子句中指定"(+)"来实现左连接,并且增加连接条件。
gaussdb=# select t1.sr_item_sk ,t2.c_customer_id from store_returns t1, customer t2 where t1.sr_customer_sk = t2.c_customer_sk(+) and t2.c_customer_sk(+) < 1 order by 1 limit 1;
sr_item_sk | c_customer_id
------------+---------------
(1 row)
--不支持在where子句中指定"(+)"的同时使用内层嵌套AND/OR的表达式。
gaussdb=# select t1.sr_item_sk ,t2.c_customer_id from store_returns t1, customer t2 where not(t1.sr_customer_sk = t2.c_customer_sk(+) and t2.c_customer_sk(+) < 1);
ERROR: Operator "(+)" can not be used in nesting expression.
LINE 1: ...tomer_id from store_returns t1, customer t2 where not(t1.sr_...
--where子句在不支持表达式宏指定"(+)"会报错。
gaussdb=# select t1.sr_item_sk ,t2.c_customer_id from store_returns t1, customer t2 where (t1.sr_customer_sk = t2.c_customer_sk(+))::bool;
ERROR: Operator "(+)" can only be used in common expression.
--where子句在表达式的两边都指定"(+)"会报错。
gaussdb=# select t1.sr_item_sk ,t2.c_customer_id from store_returns t1, customer t2 where t1.sr_customer_sk(+) = t2.c_customer_sk(+);
ERROR: Operator "(+)" can't be specified on more than one relation in one join condition
HINT: "t1", "t2"...are specified Operator "(+)" in one condition.
--删除表。
gaussdb=# DROP TABLE tpcds.reason_p;
--闪回查询示例
--创建表tpcds.time_table
gaussdb=# create table tpcds.time_table(idx integer, snaptime timestamp, snapcsn bigint, timeDesc character(100));
--向表tpcds.time_table中插入记录
gaussdb=# INSERT INTO tpcds.time_table select 1, now(),int8in(xidout(next_csn)), 'time1' from gs_get_next_xid_csn();
gaussdb=# INSERT INTO tpcds.time_table select 2, now(),int8in(xidout(next_csn)), 'time2' from gs_get_next_xid_csn();
gaussdb=# INSERT INTO tpcds.time_table select 3, now(),int8in(xidout(next_csn)), 'time3' from gs_get_next_xid_csn();
gaussdb=# INSERT INTO tpcds.time_table select 4, now(),int8in(xidout(next_csn)), 'time4' from gs_get_next_xid_csn();
gaussdb=# select * from tpcds.time_table;
idx | snaptime | snapcsn | timedesc
-----+----------------------------+---------+------------------------------------------------------------------------------------------------------
1 | 2021-04-25 17:50:05.360326 | 107322 | time1
2 | 2021-04-25 17:50:10.886848 | 107324 | time2
3 | 2021-04-25 17:50:16.12921 | 107327 | time3
4 | 2021-04-25 17:50:22.311176 | 107330 | time4
(4 rows)
gaussdb=# delete tpcds.time_table;
DELETE 4
gaussdb=# SELECT * FROM tpcds.time_table TIMECAPSULE TIMESTAMP to_timestamp('2021-04-25 17:50:22.311176','YYYY-MM-DD HH24:MI:SS.FF');
idx | snaptime | snapcsn | timedesc
-----+----------------------------+---------+------------------------------------------------------------------------------------------------------
1 | 2021-04-25 17:50:05.360326 | 107322 | time1
2 | 2021-04-25 17:50:10.886848 | 107324 | time2
3 | 2021-04-25 17:50:16.12921 | 107327 | time3
(3 rows)
gaussdb=# SELECT * FROM tpcds.time_table TIMECAPSULE CSN 107330;
idx | snaptime | snapcsn | timedesc
-----+----------------------------+---------+------------------------------------------------------------------------------------------------------
1 | 2021-04-25 17:50:05.360326 | 107322 | time1
2 | 2021-04-25 17:50:10.886848 | 107324 | time2
3 | 2021-04-25 17:50:16.12921 | 107327 | time3
(3 rows)
--WITH RECURSIVE查询示例:计算从1到100的累加值。
gaussdb=# WITH RECURSIVE t1(a) as (
select 100
t(n) AS (
VALUES (1)
UNION ALL
SELECT n+1 FROM t WHERE n < (select max(a) from t1)
SELECT sum(n) FROM t;
------
(1 row)
--UNPIVOT子句示例:将表p1的math列和phy列转置为(class,score)行
gaussdb=# CREATE TABLE p1(id int, math int, phy int);
gaussdb=# INSERT INTO p1 values(1,20,30);
gaussdb=# INSERT INTO p1 values(2,30,40);
gaussdb=# INSERT INTO p1 values(3,40,50);
gaussdb=# SELECT * FROM p1;
id | math | phy
----+------+-----
1 | 20 | 30
2 | 30 | 40
3 | 40 | 50
(3 rows)
gaussdb=# SELECT * FROM p1 UNPIVOT(score FOR class IN(math, phy));
id | class | score
----+-------+-------
1 | MATH | 20
1 | PHY | 30
2 | MATH | 30
2 | PHY | 40
3 | MATH | 40
3 | PHY | 50
(6 rows)
--PIVOT子句示例:将表p2的(class,score)行转置为'MATH'列和 'PHY'列
gaussdb=# CREATE TABLE p2(id int, class varchar(10), score int);
gaussdb=# INSERT INTO p2 SELECT * FROM p1 UNPIVOT(score FOR class IN(math, phy));
gaussdb=# SELECT * FROM p2;
id | class | score
----+-------+-------
1 | MATH | 20
1 | PHY | 30
2 | MATH | 30
2 | PHY | 40
3 | MATH | 40
3 | PHY | 50
(6 rows)
gaussdb=# SELECT * FROM p2 PIVOT(max(score) FOR class IN ('MATH', 'PHY'));
id | 'MATH' | 'PHY'
----+--------+-------
1 | 20 | 30
3 | 40 | 50
2 | 30 | 40
(3 rows)