SELECT
功能描述
从表或视图中查询数据。SELECT操作就像叠加在数据库表上的过滤器,通过指定查询的条件信息,可以从数据库表中过滤出用户需要的数据。
注意事项
- 表的所有者、拥有表SELECT权限的用户或拥有SELECT ANY TABLE权限的用户,可以对表或视图进行SELECT操作查看数据,当三权分立开关关闭时,系统管理员默认拥有此权限。
- SELECT支持普通表之间的JOIN,不支持普通表和GDS外表的JOIN,即SELECT语句中不能同时出现普通表和GDS外表。
- 用户进行SELECT操作,必须拥有SELECT语句中使用的字段的SELECT权限。
- 仅同时拥有对表的SELECT权限和UPDATE权限的用户,可以对表进行FOR UPDATE或FOR SHARE操作。
- 指定分区语句目前不支持走全局索引扫描。
语法格式
查询数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [ WITH [ RECURSIVE ] with_query [, ...] ] SELECT [/*+ plan_hint */] [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ] { * | {expression [ [ AS ] output_name ]} [, ...] } [ FROM from_item [, ...] ] [ WHERE condition ] [ [ START WITH condition ] CONNECT BY [NOCYCLE] condition [ ORDER SIBLINGS BY expression ] ] [ GROUP BY grouping_element [, ...] ] [ HAVING condition [, ...] ] [ WINDOW {window_name AS ( window_definition )} [, ...] ] [ { UNION | INTERSECT | EXCEPT | MINUS } [ ALL | DISTINCT ] select ] [ ORDER BY {expression [ [ ASC | DESC | USING operator ] | nlssort_expression_clause ] [ NULLS { FIRST | LAST } ]} [, ...] ] [ LIMIT { [offset,] count | ALL } ] [ OFFSET start [ ROW | ROWS ] ] [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY [OFFSET offset_count]] [ {FOR { UPDATE | SHARE } [ OF table_name [, ...] ] [ NOWAIT | WAIT n | SKIP LOCKED ]} [...] ]; |
- 缓存SELECT语句计划的场景下,WHERE IN候选子集建议条件个数不超过100,防止引发动态内存过高问题:
- WHERE IN候选子集过大时,生成计划的内存占用会增大。
- 当拼接SQL构造的WHERE IN子集不同,缓存计划的SQL模板无法复用。会生成大量不同的计划且计划无法共享,占用大量内存。
- condition和expression中可以使用targetlist(查询返回列表)中表达式的别名:
- 只能同一层引用。
- 只能引用targetlist中的别名。
- 只能是后面的表达式引用前面的表达式。
- 不能包含volatile函数。
- 不能包含Window function函数。
- 不支持在JOIN ON条件中引用别名。
- targetlist中有多个要应用的别名则报错。
- 其中子查询with_query为:
1 2
with_query_name [ ( column_name [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( {select | values | insert | update | delete} )
- 其中指定查询源from_item为:
1 2 3 4 5 6 7 8 9 10 11
{[ ONLY ] table_name [ * ] [ partition_clause ] [ [ AS ] alias [ ( column_alias [, ...] ) ] ] [ TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ] ] [ TIMECAPSULE {TIMESTAMP | CSN} expression ] |( select ) [ AS ] alias [ ( column_alias [, ...] ) ] |with_query_name [ [ AS ] alias [ ( column_alias [, ...] ) ] ] |function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ] |function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] ) |xmltable_clause |from_item unpivot_clause |from_item pivot_clause |from_item [ NATURAL ] join_type from_item [ ON join_condition | USING ( join_column [, ...] ) ]}
- 指定查询源from_item中指定分区partition_clause为:
1 2
{PARTITION { ( { partition_name | subpartition_name } [, ...] ) | FOR ( partition_value [, ...] ) } | SUBPARTITION { ( subpartition_name ) | FOR ( subpartition_value [, ...] )}}
- 指定分区只适合分区表。
- PARTITION指定多个分区名时,可以存在相同的分区名,最终的分区范围取多个分区的并集。
- 指定查询源from_item中xmltable_clause为:
XMLTABLE( xmlnamespaces_clause row_expression passing_clause columns_clause )
- xmlnamespaces_clause为:
{ XMLNAMESPACES( {string AS identifier | DEFAULT string } [, { string AS identifier | DEFAULT string } ][...] ), } - passing_clause为:
[ PASSING [BY { REF | VALUE }] document_expression [BY { REF | VALUE }] ] - columns_clause为:
[ COLUMNS name { type [PATH column_expression] [DEFAULT default_expression] [NOT NULL | NULL] | FOR ORDINALITY } [, ...] ]
- xmlnamespaces_clause为:
- 指定查询源from_item中指定分区partition_clause为:
- 其中GROUP BY子句为:
1 2 3 4 5 6
{() |expression |( expression [, ...] ) |ROLLUP ( { expression | ( expression [, ...] ) } [, ...] ) |CUBE ( { expression | ( expression [, ...] ) } [, ...] ) |GROUPING SETS ( grouping_element [, ...] )}
- 其中设置排序方式nlssort_expression_clause为:
1NLSSORT ( column_name, ' NLS_SORT = { SCHINESE_PINYIN_M | generic_m_ci } ' )
- 简化版查询语法,功能相当于SELECT * FROM table_name。
1TABLE { ONLY {(table_name)| table_name} | table_name [ * ]};
参数说明
- WITH [ RECURSIVE ] with_query [, ...]
用于声明一个或多个可以在主查询中通过名称引用的子查询,相当于临时表。这种子查询语句结构称为CTE(Common Table Expression)结构,应用CTE结构时,执行计划中将存在CTE SCAN的内容。如果声明了RECURSIVE,SELECT子查询可以通过名称引用其自身。
其中with_query的详细格式为:
with_query_name [ ( column_name [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( {select | values | insert | update | delete} )- with_query_name:指定子查询生成的结果集名称,在查询中可使用该名称访问子查询的结果集。
- column_name:指定子查询结果集中显示的列名。
- 每个子查询可以是SELECT、VALUES、INSERT、UPDATE或DELETE语句。
- 应用CTE结构,需要声明RECURSIVE,且RECURSIVE需要在WITH后进行声明。当存在多个CTE的情况下,只需要在第一个CTE处声明RECURSIVE。
- 用户可以使用[ NOT ] MATERIALIZED对CTE进行修饰。对于Stream计划,目前仅支持内联执行方式,此时该语法不生效。
- 如果声明为MATERIALIZED,WITH查询将被物化,生成一个子查询结果集的复制,在引用处直接查询该复制,因此WITH子查询无法和主干SELECT语句进行联合优化(如谓词下推、等价类传递等)。当使用NOT MATERIALIZED进行修饰时,如果WITH查询语义上可以作为子查询内联执行,则可以和主干SELECT语句进行联合优化(如谓词下推、等价类传递等)。
- 如果用户没有显式声明物化属性则遵守以下规则:如果CTE只在所属SELECT主干中被引用一次,且语义上支持内联执行,则会被改写为子查询内联执行,否则以CTE SCAN的方式物化执行。
- plan_hint子句
用于对SELECT对应语句块生成的计划进行hint调优,以/*+ */的形式在SELECT关键字后进行声明,具体的hint调优用法请参见《SQL调优指南》中“使用Plan Hint进行调优”章节。每条语句中只有第一个/*+ plan_hint */注释块会作为hint生效,注释块中可以写多条hint。
- ALL
可选,返回所有符合SELECT查询条件的行,为SELECT查询的默认行为。
- DISTINCT [ ON ( expression [, ...] ) ]
从SELECT的结果集中删除所有重复的行,确保结果集中的每行都是唯一的。
ON ( expression [, ...] ):只保留符合expression运算的结果集合中的第一行数据。
- 由于DISTINCT ON仅保留符合expression的行的集合的第一行,并未对符合expression的行的集合进行排序,所以指定DISTINCT ON后,其结果并非固定,当需要返回唯一且符合预期的数据行时,建议同时指定ORDER BY进行数据筛选。
- DISTINCT ON表达式中不支持非整数常量排序。
- SELECT列表
指定查询表中列名,可以是部分列或者是全部(使用通配符*表示)。
通过使用子句AS output_name可以对输出字段进行添加别名,别名通常用于输出字段的显示。
列名可以用以下形式进行表达:
- 手动输入列名,多个列之间用逗号分隔。
- 列名可以用FROM子句计算出来的结果/字段表示。
- 支持关键字NAME、VALUE和TYPE作为列别名。
- FROM子句
为SELECT查询限定一个或多个数据源表。
FROM子句中涉及如下的元素:
- table_name
表名或视图名,名称前可加模式名进行限定,如:schema_name.table_name。
支持使用DATABASE LINK方式对远程表以及同义词进行操作,具体的使用方式请参见《开发指南》中“特性使用指导 > DATABASE LINK”章节。
- alias
给表或复杂的表引用添加一个临时的表别名,方便被其他的查询进行引用。
别名用于方便引用或者在自连接中消除歧义。如果提供了别名,可直接引用别名(代替表的实际名称)。
JOIN操作产生的拼接表joined_table添加别名时,如果joined_table被括号指定(即(joined_table)),请勿使用非保留关键字UNPIVOT和PIVOT作为表别名。
- TABLESAMPLE sampling_method ( argument [, ...] ) [ REPEATABLE ( seed ) ]
表示使用指定的采样方法sampling_method检索表table_name中行的子集。可选择的采样方法sampling_method包括:
- SYSTEM(percent)
- BERNOULLI(percent)
- HYBRID(p1,p2)
混合随机采样。包括两个步骤:首先以概率p1对数据块进行随机采样,其次对已采样的数据内容以概率p2进行按行独立随机采样。其中,p1和p2的取值范围均为[0, 100]。
REPEATABLE子句:可选,采样方法sampling_method的补充条件,seed为采样方法中产生随机数的种子值,可以为任意非空常量值。当表结构/数据未发生更改且进行多次采样操作时,如果未指定REPEATABLE ( seed ),系统将基于自动生成的种子值为每一次查询获取一个新的随机采样,获取的采样结果并非固定;指定REPEATABLE ( seed )后,获取的采样结果唯一固定。
- TIMECAPSULE { TIMESTAMP | CSN } expression
- TIMECAPSULE TIMESTAMP
- TIMECAPSULE CSN
- expression
- 系统表、DFS表、全局临时表、本地临时表、UNLOGGED表、视图、序列表、共享表以及继承表目前不支持闪回查询。
- 当对表进行表结构修改操作或物理存储操作后,无法对表再次进行闪回查询,即在闪回点和当前点之间如果执行过修改表结构或影响物理存储的语句(TRUNCATE、DDL、DCL或VACUUM FULL),进行闪回查询会显示操作失败。执行过DDL的表进行闪回操作报错“ERROR:The table definition of %s has been changed.”;涉及表结构改变等操作的DDL执行闪回操作报错“ERROR: recycle object %s desired does not exist.”。
- 闪回查询支持PCR类型的UBTree索引进行索引扫描;如果没有创建PCR类型的UBTree索引,闪回查询只能通过seqScan进行全表扫描。
- 因闪回点过旧(闪回版本被回收等导致无法获取闪回点版本),导致闪回失败报错“Restore point too old.”。
- 通过TIMESTAMP指定闪回点,闪回数据和实际时间点最多偏差为3秒。
- 当对表执行TRUNCATE后,再次进行闪回查询或闪回表操作时,通过TIMESTAMP进行的闪回操作会报错(Snapshot too old);通过CSN进行的闪回操作会找不到数据或者报错(Snapshot too old)。
- GTM-Free场景下,各节点使用本地CSN且没有全局统一CSN号,暂不支持使用CSN方式进行闪回查询操作。
- column_alias
- PARTITION
- partition_name
- partition_value
指定的分区键值。在创建分区表时,如果指定了多个分区键,可以通过PARTITION FOR子句指定的这一组分区键的值,唯一确定一个分区。
- subquery
- with_query_name
- function_name
- join_type
- [ INNER ] JOIN
- LEFT [ OUTER ] JOIN
左(外)关联。将两个表进行拼接,以左边的表作为主表,根据查询条件,主表数据全部展示,从表数据根据连接条件是否匹配进行展示,无法匹配的信息数据用NULL填充。
- RIGHT [ OUTER ] JOIN
右(外)关联。将两个表进行拼接,以右边的表作为主表,根据查询条件,主表数据全部展示,从表数据根据连接条件是否匹配进行展示,无法匹配的信息数据用NULL填充。
可以将右(外)关联转换成左(外)关联,只要把左边和右边的输入互换位置即可。
- FULL [ OUTER ] JOIN
- CROSS JOIN
CROSS JOIN等效于INNER JOIN ON (TRUE),即没有被条件删除的行。这种连接类型只是符号上的方便,与简单的FROM和WHERE的效果相同。
INNER JOIN和OUTER JOIN必须声明一个连接条件(即ON join_condition或USING (join_column [, ...])),CROSS JOIN中不需要声明。
其中CROSS JOIN和INNER JOIN生成一个简单的笛卡尔积,和在FROM的顶层列出两个项的结果相同。
- ON join_condition
连接条件,用于限定连接中的连接对象的匹配规则,如ON left_table.a = right_table.a。不建议使用int等数值类型作为join_condition,因为int等数值类型可以隐式转换为bool值(非0值隐式转换为true,0转换为false),可能导致非预期的结果。
- USING(join_column[,...])
ON left_table.a = right_table.a AND left_table.b = right_table.b ... 的简写。要求对应的列必须同名。
- NATURAL
- from item
- xmltable_clause
xmltable_clause仅支持在ORA兼容模式和PG兼容模式下使用。xmltable_clause基于指定的XMLTYPE类型(ORA兼容模式下)或XML类型(PG兼容模式下)的数据产生一个虚拟表。
- xmlnamespaces_clause
可选,结构由XMLNAMESPACES以及以英文逗号分隔的XML命名空间声明的子句组成(以英文逗号分隔的XML命名空间声明的子句位于XMLNAMESPACES之后)。其中string为英文单引号作为边界符的命名空间全称,identifier为英文双引号作为边界符的命名空间别名且别名可以在row_expression及columns_clause中使用。当前版本不支持使用DEFAULT声明默认的命名空间。
- row_expression
row_expression为英文单引号作为边界符的XPath 1.0表达式。将passing_clause中的document_expression作为其上下文,获得一组XML节点。XML节点经过columns_clause处理生成虚拟表的每一行。
在ORA兼容模式下,row_expression支持传入以英文单引号(')作为边界符、逗号(,)作为分隔符的数字或者XML文本组成的序列。
- passing_clause
passing_clause以PASSING开始,其中的document_expression为传入XMLTABLE中被处理的XMLTYPE类型(ORA兼容模式下)或XML类型(PG兼容模式下)的数据,目前仅支持单个数据。在ORA兼容模式下,使用BY VALUE或BY REF都会报错;在PG兼容模式下,虽然可以识别接收第一处和第二处的BY VALUE或BY REF,但并未做功能上的处理。
- columns_clause
可选,用于指明将在虚拟表中生成的列所需的相关信息,如表1所示。
表1 COLUMNS信息说明 信息
说明
name
列的名称。
type
列的类型。
PATH
可选,column_expression为XPath 1.0的表达式,由row_expression得到的节点集中的某个节点作为其上下文,经其处理得到该节点生成的行数据中对应列的值所需的数据,在将其转换为type类型的结果时,存在隐式转换。若没有指定PATH部分,则name会被当作column_expression。
DEFAULT
可选,default_expression为表达式,如果通过column_expression处理后得到的是NULL值,会将计算default_expression得到的结果用于替换NULL值,default_expression仅在需要的时候才进行计算,若表达式固定,则在需要的时候只会计算一次。
NOT NULL | NULL
可选,在PG兼容模式下,用于限定该列是否可为NULL值,若列值与指定的选项不符则会报错。
FOR ORDINALITY
说明该列为行号列,从1开始为生成的行填充行号,最多只能有一个列被标记为FOR ORDINALITY。
在ORA兼容模式下,columns_clause可省略,省略columns_clause后,默认生成COLUMNS column_value XMLTYPE PATH '.'用于进行后续处理。
PG兼容模式下,columns_clause不可省略。
目前xmltable_clause存在以下约束:
- 涉及的XPath表达式均为XPath 1.0。
- 目前不支持在row_expression使用形如“namespace::*”的XPath表达式。
- 目前不支持在column_expression使用形如“..”的XPath表达式。
- 通过column_expression得到的数据在转换为type类型的数据时:在ORA兼容模式下,当数据过长且超过类型的typmod会截断处理;目前仅对CHAR、CHARACTER、NCHAR、BPCHAR、VARCHAR、CHARACTER VARYING、VARCHAR2以及NVARCHAR2数据类型(包括附带(n)形式)的typmod大于0时,过长的数据会进行截断处理。在PG兼容模式下,当数据过长且超过类型的typmod时会报错处理。
- 目前支持传入的XMLTYPE类型(ORA兼容模式下)或XML类型(PG兼容模式下)数据的最大值为1GB。
- 从不支持XMLTABLE的版本升级到支持XMLTABLE的版本时,在升级观察期期间,不可使用XMLTABLE语法。
- 仅在ORA兼容模式下支持XPath中存在“*:nodename”,表示选取nodename节点时忽略其命名空间,其中nodename为节点名称。
- 非保留关键字XMLTABLE不能作为Functions as Table Sources类型函数的函数名称。
- 在ORA兼容模式下,使用数字和XML文本组成的序列输入场景下,存在以下约束:
- 不支持和passing_clause、columns_clause联合使用。
- 序列中以逗号分隔的元素个数范围为[1, 1024]。
- 不支持表达式作为序列元素。
- XML文本内容中的>、"以及&,不会被转义为>、"和&。
- XML文本节点名称仅支持与大于符号(>)之间存在一个或多个空格,并且输出结果不会删除节点名称与大于符号(>)之间的空格。
- 升级观察期不支持该功能。
- xmltable嵌套xmlquery的returning sequence场景下,column_clause中的xpath仅支持'.'。
- xpath中'.'后不能跟下标表达式,例如:'.[6]';或者谓词表达式,例如:'.[.>5]'。
- 在输入非良构的XMLTYPE类型(ORA兼容模式下)数据时,在非良构部分之后的用于节点间控制书写格式的空格和回车字符当作文本节点解析,如node2节点的结束标签与node3节点的开始标签之间的空格和回车即会被当作文本节点解析。
<root> <node1>node1</node1> malform <node2>node2</node2> <node3>node3</node3> </root>
实际情况:
<root><node1>node1</node1> malform <node2>node2</node2> <node3>node3</node3> </root>
示例:
-- 创建ORA兼容数据库。 gaussdb=# CREATE DATABASE ora_db DBCOMPATIBILITY = 'ORA' ENCODING = 'utf8'; gaussdb=# \c ora_db -- 支持数字和xml文本组成的序列输入。 ora_db=# SELECT * FROM XMLTABLE('1, 2, <a>12</a>'); column_value -------------- 1 2 <a>12</a> (3 rows) ora_db=# \c postgres gaussdb=# DROP DATABASE ora_db; - xmlnamespaces_clause
- unpivot_clause 将列转换为行。
UNPIVOT [ {INCLUDE | EXCLUDE} NULLS ] ( unpivot_col_clause unpivot_for_clause unpivot_in_clause )- {INCLUDE | EXCLUDE} NULLS
可选,该子句用于控制转置后的结果是否包含存在NULL值的行。未指定该子句,unpivot操作默认会从结果集中过滤存在NULL值的行。
INCLUDE NULLS:结果集中保留包含存在NULL值的行。
EXCLUDE NULLS:从结果集中过滤存在NULL值的行。
- unpivot_col_clause为:
unpivot_col_element
unpivot_col_element指定了输出的列名,用于保存待转置列的列值。
- unpivot_col_element为:
{ column | ( column [, column]... ) } - unpivot_for_clause为:
FOR { unpivot_col_element }unpivot_col_element:用于指定输出的列名,用于保存待转置列的列名或别名。
- unpivot_in_clause为:
IN ( unpivot_in_element [,unpivot_in_element...] )
unpivot_in_clause:待转置列,列名和列值将保存在unpivot_col_element中。
unpivot_in_element为:{ unpivot_col_element }[ AS { unpivot_alias_element } ]unpivot_col_element:指定的待转置列,若采用( column [, column]... )形式指定待转置列,( column [, column]... )中所有的column列名将通过下划线“_”进行拼接,并保存在输出列中。如,IN ((col1, col2))将会生成列名“col1_col2”,并保存在unpivot_for_clause指定的输出列中。AS关键字可为待转置列指定别名,当指定别名后,输出列中将保存别名而不再保存待转置列的列名。
- unpivot_alias_element为:
{ alias | ( alias [, alias]... )}alias:为指定的别名。
目前unpivot_clause存在如下约束:
- 仅支持在ORA兼容模式数据库下使用。
- unpivot_clause子句内不支持与hint配合使用。
- 对于unpivot_col_clause,其unpivot_col_element指定的输出列数目需与unpivot_in_clause中unpivot_col_element的列数目相同。
- 对于unpivot_for_clause,其unpivot_col_element指定的输出列数目需与unpivot_in_clause中unpivot_alias_element的别名数目相同。
- 对于unpivot_in_clause,别名必须为常量,或者可以转换为常量的表达式。
- 对于unpivot_in_clause,常量表达式支持的函数仅支持为不可变(IMMUTABLE)函数。
- 对于unpivot_in_clause的所有unpivot_col_element,如果unpivot_col_element相同位置的column类型存在差异,unpivot会尝试进行类型转换,以将这些转置列的列值转换为公共类型。同理。对于unpivot_alias_element,如果unpivot_alias_element相同位置的alias类型存在差异,unpivot也会进行类似的类型转换。
- {INCLUDE | EXCLUDE} NULLS
- pivot_clause
PIVOT [ XML ] ( aggregate_function ( expr ) [[AS] alias ] [, aggregate_function ( expr ) [[AS] alias ] ]... pivot_for_clause pivot_in_clause )- aggregate_function ( expr ) [[AS] alias ]
aggregate_function针对给定的表达式进行聚合计算,计算结果将保存在pivot_in_clause指定的输出列中。
[AS] alias:为aggregate_function指定别名,别名将以“_别名”格式记录在pivot_in_clause指定的输出列名后。
- pivot_for_clause为:
FOR { column | ( column [, column]... ) }pivot_for_clause:待转置行。
column:表示待转置行的列。
- pivot_in_clause为:
IN ( { { { expr | ( expr [, expr]... ) } [ [AS] alias] }... } )pivot_in_clause指定了输出结果的列名,列名可由一个expr或多个expr构成。当列名由多个expr构成时,expr按顺序通过下划线“_”进行连接,即“expr1, expr2”对应的输出列名为“expr1_expr2”。除了生成输出列名外,expr还决定着聚合函数触发时机,当待转置行的行值与expr的值相同时,pivot将进行聚合函数aggregate_function的计算,并将计算结果保存在列名由expr构成的输出列中。
目前pivot_clause存在如下约束:
- 仅支持在ORA兼容模式下使用。
- pivot_clause子句内不支持与hint配合使用。
- 当指定多于一个aggregate_function时,最多允许一个aggregate_function没有别名,其余aggregate_function均需指定别名。
- XML只支持语法不支持功能。
- pivot_in_clause中的expr可以是常量,或者是可以转换为常量的表达式。若expr不是一元表达式,则需为expr指定别名。
- 对于pivot_in_clause中的expr,常量表达式支持的函数只支持不可变(IMMUTABLE)函数。
- 对于pivot_in_clause中的expr,当通过AS为其指定别名时,非保留关键字可作为别名使用;其他情况下,非保留关键字不能作为别名使用。
- 输出列的列名长度限制为63,超出将报错。
- aggregate_function ( expr ) [[AS] alias ]
- table_name
- WHERE子句
WHERE子句构成一个行选择表达式,用来缩小SELECT查询的范围。
condition:返回值为布尔型的任意表达式,仅满足该条件的行才会被显示。请勿使用int等数值类型作为condition,因为int等数值类型可以隐式转换为bool值(非0值隐式转换为true,0转换为false),可能导致非预期的结果。
WHERE子句中可以通过指定"(+)"操作符的方法将表的连接关系转换为外连接。该操作并非SQL的标准语法,在做平台迁移的时候可能面临语法兼容性的问题,不建议用户使用这种用法。同时使用"(+)"存在以下限制:
- "(+)"只能出现在WHERE子句中。
- 如果FROM子句中已经对表连接关系进行指定,那么无法继续在WHERE子句中使用"(+)"。
- "(+)"只能作用在表或者视图的列上,不能作用在表达式上。
- 如果表存在多个连接条件,那么必须在所有的连接条件中指定"(+)",否则"(+)"将不会生效,表连接会转化成内连接,并且不显示任何提示信息。
- "(+)"作用的连接条件中的表不能跨查询或者子查询。如果"(+)"作用的表,不在当前查询或者子查询的FROM子句中,则会报错。如果"(+)"作用的对端的表不存在,则不报错,同时连接关系会转化为内连接。
- 除同一单表的外连接表达式外,"(+)"作用的表达式不可直接通过OR操作符连接。
- 如果"(+)"作用的列是和一个常量的比较关系,那么这个表达式会成为JOIN条件的一部分。
- 当一张表被同时作为多张表的外表时,若其对应的内表之间没有连接关系,则内表之间先做笛卡尔积,再和外表做外连接。
- "(+)"只能出现在比较表达式、BETWEEN AND/NOT BETWEEN AND表达式、NOT表达式、ANY/SOME表达式、ALL表达式、IN/NOT IN表达式、NULLIF表达式、IS DISTINCT FROM/IS NOT DISTINCT FROM表达式、IS NULL/IS NOT NULL表达式或IS OF表达式中。"(+)"不能出现在其他类型表达式中,并且这些表达式中不允许出现通过AND和OR连接的表达式。
- "(+)"只能转化为左外连接或者右外连接,不能转化为全连接,即不能在一个表达式的两个表上同时指定"(+)"。
- 在ORA兼容模式下,"(+)"操作符括号中可以包含空格,例如:"( +)"、"(+ )"。
- "(+)"操作符不支持自动参数化处理。
- 对于WHERE子句的LIKE操作符,当LIKE中要查询特殊字符“%”、“_”、“\”时,需要使用“\”来进行转义。在ORA兼容模式下,可以在GUC参数standard_conforming_strings为on时,设置behavior_compat_options参数的取值为ignore_like_default_escape,以支持将反斜杠字符“\”作为普通字符匹配。
gaussdb=# CREATE DATABASE ora_db DBCOMPATIBILITY = 'ORA'; gaussdb=# \c ora_db; ora_db=# SET standard_conforming_strings = on; ora_db=# SET behavior_compat_options = ignore_like_default_escape; ora_db=# SELECT 'aa\a' LIKE 'aa\a'; ?column? ---------- t (1 row) ora_db=# SELECT 'aaa' LIKE 'aa\a'; ?column? ---------- f (1 row) ora_db=# SET behavior_compat_options = ''; ora_db=# SELECT 'aa\a' LIKE 'aa\a'; ?column? ---------- f (1 row) ora_db=# SELECT 'aaa' LIKE 'aa\a'; ?column? ---------- t (1 row) ora_db=# \c postgres; gaussdb=# DROP DATABASE ora_db;
- WHERE子句后面添加IN子句且当IN后面不添加括号时,支持IN后面只添加一个元素,约束仅支持在ORA兼容模式数据库下使用,并且此时WHERE子句中仅支持存在这一个条件。该元素有如下限制:
- 常量:如字符串、整数、浮点数等。
- 列名。
- CASE WHEN子句。
- 函数。
- "(+)"操作符支持在提取公共表达式后执行合法性校验。公共表达式定义为完全相同的表达式结构,包括表达式内的顺序、表达式内的占位符序号等。
SELECT * FROM a,a2 WHERE a.id(+) IS NULL AND a.id(+) = a2.id OR a.id(+) = a2.id AND a.id(+) = 1;
提取公共表达式a.id(+) = a2.id后,可转化为:
SELECT * FROM a,a2 WHERE a.id(+) = a2.id AND (a.id(+) IS NULL OR a.id(+) = 1);
转化后的表达式满足OR操作符两侧均为同一单表的外连接表达式,因此校验成功。
SELECT * FROM a,a2 WHERE a.id(+) IS NULL AND a2.id = a.id(+) OR a.id(+) = a2.id AND a.id(+) = 1;
由于a2.id = a.id(+)与a.id(+) = a2.id的表达式顺序不同,无法提取公共表达式,因此校验失败。
在PREPARE语句或通过游标动态执行查询语句中,使用占位符绑定参数时,需满足公共表达式中的占位符序号完全相同。
PREPARE p1 AS SELECT * FROM a,a2 WHERE a.id IS NULL AND a.id(+) = $1 OR a.id(+) = $2 AND a.id = 1;
由于a.id(+) = $1和a.id(+) = $2的占位符序号不同($1≠$2),不符合公共表达式定义,因此校验失败。
- START WITH子句
START WITH子句通常与CONNECT BY子句同时使用,数据进行层次递归遍历查询,START WITH代表递归的初始条件。若省略该子句,单独使用CONNECT BY子句,则表示以表中的所有行作为初始集合。该功能请参见CONNECT BY子句子句。
- CONNECT BY子句
CONNECT BY代表递归连接条件,和START WITH子句同时使用,实现数据遍历递归的功能。
CONNECT BY条件中可以对列指定PRIOR关键字,表示以列为递归键进行递归。若在递归连接条件前指定NOCYCLE,则表示当出现循环记录时停止递归。
含START WITH condition CONNECT BY子句的SELECT语句不支持使用FOR SHARE或FOR UPDATE锁。
START WITH语句的执行流程是:
- 由START WITH区域的条件选择初始的数据集。示例中先将('A', 1, 0)选择出来,再将初始的数据集设为工作集。
- 当工作集不为空,将工作集的数据作为输入,查询下一轮的数据,过滤条件由CONNECT BY区域指定。其中,PRIOR关键字表示当前记录,示例中prior id = fatherid表示当前记录的id是下一条记录的fatherid。
- 将上一步中筛选出来的数据集作为工作集,并重复操作上一步。
gaussdb=# CREATE TABLE test(name varchar, id int, fatherid int); gaussdb=# INSERT INTO test VALUES('A', 1, 0), ('B', 2, 1),('C',3,1),('D',4,1),('E',5,2); gaussdb=# SELECT * FROM test START WITH id = 1 CONNECT BY prior id = fatherid ORDER SIBLINGS BY id DESC; name | id | fatherid ------+----+---------- A | 1 | 0 D | 4 | 1 C | 3 | 1 B | 2 | 1 E | 5 | 2 (5 rows)当前START WITH默认行为是宽度优先搜索,可以通过和伪列配合,实现深度优先搜索。如:gaussdb=# SELECT sys_connect_by_path(name,'-') as path, *, LEVEL FROM test START WITH id = 1 CONNECT BY fatherid=prior id ORDER BY path; path | name | id | fatherid | level --------+------+----+----------+------- -A | A | 1 | 0 | 1 -A-B | B | 2 | 1 | 2 -A-B-E | E | 5 | 2 | 3 -A-C | C | 3 | 1 | 2 -A-D | D | 4 | 1 | 2 gaussdb=# DROP TABLE test;
如果在数据集中存在循环,数据库会提供循环检测。默认行为当检查到循环时,会直接报错,不返回任何数据;若指定NOCYCLE关键字,查询可以正常执行,当出现循环记录时停止递归并退出。
- 伪列:数据库为每一条选出来的数据添加伪列,方便用户了解数据在递归或者树状结构中的位置。
- LEVEL:节点的层级,根节点层级为1。
- CONNECT_BY_ISCYCLE :用于返回当前节点是否与父行/子行成环。
- CONNECT_BY_ISLEAF:是否为叶子节点。当某个节点不存在任何子节点时,其即为叶子节点,CONNECT_BY_ISLEAF会被置为1;否则会被置为0。
举例:(假设已存在表T1,数据结构如表2所示。)
SELECT * FROM T1 CONNECT BY PRIOR B=A AND LEVEL<=3;
结果的树型结构如图1所示,其中蓝色的节点为叶子节点。 - 查询函数:除了伪列之外,数据库还提供了查询函数(具体请参见层次递归查询函数)。
- sys_connect_by_path(col, separator):返回从根节点到当前行的连接路径。col为路径中显示的列的名称,separator为连接符。
- connect_by_root(col):显示该节点最顶级的节点,col为输出列的名称。
- 除了伪列和查询函数外,在CONNECT BY子句之外还可使用PRIOR关键字修饰列。在SELECT查询列、DISTINCT子句、WHERE子句、GROUP BY子句、HAVING子句、WINDOW子句、ORDER BY子句使用,可显示父行列值。
- 在层次查询过程中,严格按照深度优先搜索的顺序进行。如果在START WITH或CONNECT中使用rownum作为过滤条件,对于每条尝试被返回的记录,rownum会先加1,之后按照rownum相关条件判断;对于不满足的记录,会被丢弃且rownum会减1。
- PRIOR关键字不能在START WITH语句中指定。
- 除targetlist外,"prior(单列)"会被解析为"prior 单列",不感知用户自定义的名为prior的函数。
- 只能对表中的列指定PRIOR,不支持对表达式、伪列及类型转换指定PRIOR关键字。
- CONNECT BY语句中,PRIOR修饰的列不可以和level/rownum等伪列在同一个条件里(如(PRIOR a = level)),但可在不同条件里(如(PRIOR a = b) and (level = 1)),不同条件是指CONNECT BY语句最上层的AND连接起来的条件。
- START WITH/CONNECT BY语句中禁止将伪列用于子连接,即类似于"rownum = (子查询)"或"rownum in (子查询)"。
- CONNECT BY子句中不建议使用ROWNUM,如需使用请充分测试,避免结果和预期不一致。
- 在WITH AS定义的CTE上调用START WITH/CONNECT BY时,如果存在多个CTE,需要保证每一个CTE的定义不依赖于其他CTE。
- 如果数据中不存在环路,但是报错runs into cycle,需要考虑增大max_recursive_times。
- connect_by_isleaf、connect_by_iscycle和level类型均为int类型。
- connect_by_isleaf、connect_by_iscycle和level在层次查询下,会被解析为伪列,而不会解析为投影列中别名名称和伪列相同的列。
- 不建议在定义带有层次查询的视图时引用其他视图。
- START WITH调优建议:
- 根据CONNECT BY中的条件,建立对应的索引,来提高START WITH语句的性能。
- 根据explain performance或者WDR报告中的计划识别瓶颈点,如果发现Recursive Union的递归部分的算子(内层计划)为Hash JOIN,但是Hash表是针对临时表tmp_result构建或者计划中显示hash表发生物化(batch大于1),可能是work_mem过小导致无法对外层数据表建立Hash表。可以通过调大work_mem参数来提高性能。
GaussDB会对小数据量的表有优化,把表的结果缓存在 hash 表中来提高性能,此时不需要索引。但是如果数据量超过 work_mem 的限制,该优化会失效,此时可采用建立索引的方式尝试优化。
- START WITH语句中使用空或NULL表示递归初始条件为空,返回空值结果。
- CONNECT BY语句中使用空表示递归条件为空,返回所有符合START WITH子句条件的结果。
- PRIOR修饰的列仅支持如下类型:INT8、INT1、INT2、OID、INT4、BOOL、CHAR、NAME、FLOAT4、FLOAT8、ABSTIME、RELTIME、DATE、DATEA(仅在ORA兼容性下生效)、CASH、TIME、TIMESTAMP、TIMESTAMPTZ、SMALLDATETIME、UUID、INTERVAL、TIMETZ、INT2VECTOR、CLOB、NVARCHAR2、VARCHAR、TEXT、VECTOR、BPCHAR、RAW、BYTEA、NUMERIC、XID、CID以及TID。通过强制类型转换为上述类型的操作无法避开白名单限制,如:PRIOR col::text(其中col不是上述白名单中的类型)。
- 在CONNECT BY子句之外使用PRIOR关键字修饰列时,需结合GUC参数enable_startwith_prior_enhance值,显示语句行为。关闭参数时使用PRIOR关键字修饰列等同于不添加PRIOR关键字,会显示当前行列值。打开参数时在支持子句(SELECT查询列、DISTINCT子句、WHERE子句、GROUP BY子句、HAVING子句、WINDOW子句、ORDER BY子句)中使用PRIOR关键字修饰列,可显示父行列值。除此外,以下场景语句会报错:
- 在支持子句(SELECT查询列、DISTINCT子句、WHERE子句、GROUP BY子句、HAVING子句、WINDOW子句、ORDER BY子句)中,PRIOR修饰的列为伪列LEVEL、CONNECT_BY_ISCYCLE、CONNECT_BY_ISLEAF。
- 在带有CONNECT BY子句的SELECT语句中,ON条件、ORDER SIBLINGS BY子句中使用PRIOR修饰列。
- 在不带CONNECT BY子句的语句中,使用PRIOR关键字修饰列。
- 当在同一查询语句中多次使用PRIOR修饰不同列时,只有当所有被修饰列的值均相同时,才认为是重复数据,即存在环路。
- level/connect_by_isleaf/connect_by_iscycle列作为层次递归查询函数sys_connect_by_path/connect_by_root入参时,会被解析为伪列并报错。
- ORDER SIBLINGS BY子句
START WITH语句输出时,不同层的数据会依次返回。但是在每一层内部,数据库会自动选择最优的执行路径,所以无法保证实现的顺序。如果用户对最终输出顺序有需求,可以用ORDER SIBLINGS BY子句,用法和ORDER BY子句一样,用于在递归过程中每层内部的排序。
ORDER SIBLINGS BY后的表达式仅支持对普通列、列名偏移量以及对列名的窗口函数调用的方式进行排序,不支持对列名调用START WITH相关系统函数和使用START WITH相关伪列等方式。
- GROUP BY子句
将查询结果按某一列或多列的值分组,值相等的为一组。
- CUBE ( { expression | ( expression [, ...] ) } [, ...] )
CUBE是自动对GROUP BY子句中列出的字段进行分组汇总,结果集将包含维度列中各值的所有可能组合,以及与这些维度值组合相匹配的基础行中的聚合值。它会为每个分组返回一行汇总信息, 用户可以使用CUBE来产生交叉表值。如在CUBE子句中给出三个表达式(n = 3),运算结果为2n = 23 = 8组。 以n个表达式的值分组的行称为常规行,其余的行称为超级聚集行。
- GROUPING SETS ( grouping_element [, ...] )
GROUPING SETS是GROUP BY子句的高级扩展功能,其允许在单个查询中显式定义多个GROUP BY选项。与CUBE或ROLLUP不同,GROUPING SETS通过精准指定所需的分组集,数据库不需要执行完整CUBE或ROLLUP生成的聚合集合,从而显著提升查询效率。
使用GROUPING SETS子句时,如果SQL查询语句中含有DISTINCT ON、ORDER BY或多表等值连接(JOIN)等逻辑语句,可能会出现报错。建议将GROUPING SETS子句的计算逻辑封装到内层子查询中,使分组集运算优先独立执行。SELECT DISTINCT ON (a) a, b FROM t1 GROUP BY GROUPING SETS ((a, b), (b)) ORDER BY a, b DESC;
可改写为:
SELECT DISTINCT ON (a) a, b FROM (SELECT a, b FROM t1 GROUP BY GROUPING SETS ((a, b), (b))) AS sub_t ORDER BY a, b DESC;
- 若sql_mode中包含ONLY_FULL_GROUP_BY选项,存下以下情况:
- SELECT列表中非聚集函数列与GROUP BY字段一致时,不会报错。
- SELECT列表中非聚集函数列与GROUP BY字段不一致时,存在以下情况:
- GROUP BY列表中包含主键或唯一非空键时,SQL语句不会报错。
- SELECT列表中非聚集函数列,在GROUP BY列表或WHERE列表中包含,且当SELECT列表中非聚集函数列在WHERE列表中包含时,WHERE子句中的列需要是等于某一常量的形式,不会报错。
- 对于同时含有JOIN子句和GROUP BY子句时,存在以下情况:
- 若sql_mode中不包含ONLY_FULL_GROUP_BY选项,无上述约束,以上报错场景均不报错。
- SELECT同时存在非聚集函数列和聚集函数时,需要与GROUP BY子句同时使用,否则报错。
- 若非聚集函数列不在GROUP BY列中,且分组后的非聚集函数列包含多条数据,由于执行计划不同,DN数据分布不同,查询出的非聚集函数列数据为分组后的数据中的其中一条。
- GROUP BY子句中不支持非整数常量排序。
- CUBE ( { expression | ( expression [, ...] ) } [, ...] )
- HAVING子句
与GROUP BY子句配合使用,实现选择特殊的组。HAVING子句将组的一些属性与一个常数值比较,只有满足HAVING子句中的逻辑表达式的组才会被展示。
- WINDOW子句
WINDOW window_name AS ( window_definition ) [, ...]
- window_name:被窗口定义window_definition所引用的名称。
- window_definition:
[ existing_window_name ] [ PARTITION BY expression [, ...] ] [ ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...] ] [ frame_clause ]frame_clause:对窗口函数定义一个窗口框架window frame,窗口函数(并非所有)依赖于该框架。
window frame:表示当前查询行的一组相关行。
其中frame_clause的形式如下:
[ RANGE | ROWS ] frame_start [ RANGE | ROWS ] BETWEEN frame_start AND frame_end
frame_start和frame_end形式如下:
UNBOUNDED PRECEDING VALUE PRECEDING CURRENT ROW VALUE FOLLOWING UNBOUNDED FOLLOWING
针对使用到VALUE场景存在如下约束:
- 被聚集函数/窗口函数操作的表列仅支持INT1、INT2、INT4、INT8、FLOAT4、FLOAT8、NUMERIC、INTERVAL、TIME、TIMETZ、TIMESTAMP、TIMESTAMPTZ、DATEA(仅在ORA兼容性生效)和DATE类型。
- VALUE类型仅支持INT1、INT2、INT4、INT8、INT16、FLOAT4、FLOAT8、NUMERIC、INTERVAL和字符串(仅支持可以隐式转换为数字的字符串)类型。
- VALUE的值仅支持为非负数。
- VALUE当前只支持常量作为上下边界,不支持变量与表达式作为上下边。
- UNION子句
select_statement UNION [ALL] select_statement
- select_statement:不包含ORDER BY、LIMIT或FOR UPDATE子句的SELECT语句。
- UNION操作符:计算多个select_statement返回行集合的并集。
- ALL:可选,未指定时,UNION结果不包含重复的行。
UNION子句有如下约束条件:
- 多个SELECT语句中列的数量必须相同,每列的数据类型以及顺序必须相同。
- 同一个SELECT语句中的多个UNION操作符优先级为从左向右依次执行,如需要改变优先级,可使用括号指定顺序。
- FOR UPDATE不能在UNION的结果或输入中声明。
- UNION子表达式中可以包含用括号包围的ORDER BY子句或用括号包围的LIMIT子句。
- 拼接UNION ALL子句时,推荐子句个数<100,超出时需保证实例内存足够,以避免内存不足。
- 在与NULL进行集合操作时,存在以下约束:
- 只支持NULL本身是投影列或者NULL是FROM语句子查询中的投影列。
- CTE场景与递归查询场景中,不支持复杂的子查询(DISTINCT语句、GROUP BY语句、ORDER BY语句以及PARTITION BY语句)。
- INTERSECT子句
select_statement INTERSECT select_statement
- select_statement:不包含FOR UPDATE子句的SELECT语句。
- INTERSECT操作符:计算多个select_statement返回行集合的交集,并对重复的行进行去重。
INTERSECT子句存在以下约束条件:- 同一个SELECT语句中的多个INTERSECT操作符优先级为从左向右依次执行,如需要改变优先级,可使用括号指定顺序。
- 当对多个SELECT语句的执行结果进行UNION和INTERSECT操作,INTERSECT优先级高于UNION。
- EXCEPT子句
select_statement EXCEPT [ ALL ] select_statement
- select_statement:不包含FOR UPDATE子句的SELECT表达式。
- EXCEPT操作符:计算存在于左边select_statement的输出而不存在于右边select_statement的输出行。同一个SELECT语句中的多个EXCEPT操作符优先级为从左向右依次执行,如需要改变优先级,可使用括号指定顺序。
- ALL:可选,未指定时,EXCEPT的结果不包含任何重复的行;指定ALL时,一个在左边表中有m个重复而在右边表中有n个重复的行将在结果中出现max(m-n,0)次。
目前,不支持对EXCEPT的结果或对任何EXCEPT的输入声明FOR UPDATE子句。
- MINUS子句
与EXCEPT子句具有相同的功能和用法。
- ORDER BY子句
对SELECT语句检索得到的数据进行升序或降序排序。ORDER BY子句中不支持非整数常量排序。
- ORDER BY表达式中如果包含多列,则根据以下行为进行排序:
- 从左向右依次执行,首先根据最左边的列进行排序,如果值相同,则根据下一个表达式进行比较。
- 如果对于所有声明的表达式都相同,则按随机顺序返回。
- 在与DISTINCT关键字一起使用的情况下,ORDER BY中排序的列必须包括在SELECT语句所检索的结果集的列中。
- 在与GROUP BY子句一起使用的情况下,ORDER BY中排序的列必须包括在SELECT语句所检索的结果集的列中。
- 对于不与GROUP BY子句一起使用,并且SELECT语句所检索的结果集的列中包含聚合函数的情况:
- 如果检索的结果集的列中不包含聚合函数,则忽略ORDER BY子句。
- 如果检索的结果集的列中同时包含聚合函数,则仅保留对聚合函数列的排序,忽略其他排序。
- 在ORA兼容模式数据库中,当指定DISTINCT关键字时,支持ORDER BY子句中所引用的列或表达式必须在DISTINCT列表中出现:
- ORDER BY子句支持的表达式范围,需要遵守ORDER BY自身的约束。
- ORDER BY表达式和常量运算,仅支持常量和ORDER BY整体表达式运算,不保证支持常量和非整体表达式的运算:
-- 支持。 -- 建议常量表达式和整体表达式运算时,对整体表达式加括号。 SELECT DISTINCT c1*c2+c2*c1 FROM t1 ORDER BY c2*c1+c1*c2+1; SELECT DISTINCT c1*c2+c2*c1 FROM t1 ORDER BY (c2*c1+c1*c2)+1; SELECT DISTINCT c1*c2+c2*c1 FROM t1 ORDER BY 1+(c2*c1+c1*c2); -- 不支持。 -- 常量和非整体表达式运算,常量的位置会影响表达式的结构校验逻辑,不保证正常运算。 SELECT DISTINCT c1*c2+c2*c1 FROM t1 ORDER BY 1+c2*c1+c1*c2; SELECT DISTINCT c1*c2+c2*c1 FROM t1 ORDER BY c2*c1+1+c1*c2;
- 如果ORDER BY和DISTINCT表达式含有多次强制类型转换,数据库会对强制类型转换的表达式进行解析转换。若ORDER BY解析后的表达式在DISTINCT解析后的列表中出现,则校验通过,否则不通过。若DISTINCT表达式和ORDER BY不一致,不保证解析后的结果一致:
-- 不支持。 -- DISTINCT表达式和ORDER BY原始表达式不一致,且解析后的结果也不一致。 SELECT DISTINCT c1::int::char::int,c2::integer::int3::int4 FROM t1 ORDER BY c2::char::int + c1; -- 支持。 -- DISTINCT表达式和ORDER BY原始表达式不一致,但解析后的结果一致。 SELECT DISTINCT c1::int::char::int,c2::integer::int3::int4 FROM t1 ORDER BY c2::char::int + c1::char::int; SELECT DISTINCT c1::int::int::char::int::int,c2::integer::int3::int4 FROM t1 ORDER BY c2::char::int + c1::int::char::int; SELECT DISTINCT c1::int::int::char::char::char::int::int,c2::integer::int3::int4 FROM t1 ORDER BY c2::char::int + c1::int::char::int;
- 不支持函数内部的加法和乘法的交换场景:
SELECT DISTINCT BIT_LENGTH(c1+c2) FROM t1 ORDER BY BIT_LENGTH(c2+c1);
- 当DISTINCT表达式和ORDER BY表达式都包含函数别名,仅支持函数属性为STABLE和IMMUTABLE的别名:
-- 不支持。 -- 函数属性为VOLATILE。 SELECT DISTINCT DBE_RANDOM.GET_VALUE(c1+c2,100) AS c0 FROM t1 ORDER BY c0+1; -- 支持。 -- 函数属性为STABLE。 SELECT DISTINCT add_numbers(c1,c2) AS c0 FROM t1 ORDER BY c0+1;
- 若ORDER BY表达式后面只有常数,常数含义为DISTINCT表达式的位置,需要满足ORDER BY本身的约束:
-- 支持。 -- 1指的是DISTINCT列表中第一个位置的表达式。 SELECT DISTINCT c1,c2 FROM test_table ORDER BY 1; -- 不支持。 -- 2指的是DISTINCT列表中第二个位置的表达式,此处DISTINCT列表中仅有一个表达式,会报错“位置2的表达式不存在”。 SELECT DISTINCT 1 FROM test_table ORDER BY 2;
- ORDER BY表达式和常量运算,仅支持常量和ORDER BY整体表达式运算,不保证支持常量和非整体表达式的运算:
- 针对加法和乘法运算,仅支持加法和乘法左右表达式一致的交换场景,不支持加法和乘法运算含有不一致左右表达式的交换场景。
- ORDER BY子句支持的表达式范围,需要遵守ORDER BY自身的约束。
如果要支持中文拼音排序,需要在初始化数据库时指定编码格式为UTF-8、GB18030、GB18030_2022、GBK或ZHS16GBK。命令如下:
initdb –E UTF8 –D ../data –locale=zh_CN.UTF-8 initdb -E GB18030 -D ../data -locale=zh_CN.GB18030 initdb -E GB18030_2022 -D ../data -locale=zh_CN.GB18030 initdb –E GBK –D ../data –locale=zh_CN.GBK initdb –E ZHS16GBK –D ../data –locale=zh_CN.GBK
- ORDER BY表达式中如果包含多列,则根据以下行为进行排序:
- LIMIT子句
LIMIT子句由两个独立的子句组成:
LIMIT { count | ALL }:限制返回行数,count为指定行数,LIMIT ALL的效果和省略LIMIT子句一样。
OFFSET start count:声明返回的最大行数。count为指定行数,start为指定开始返回行之前忽略的行数。如果同时指定,则会在start行之后才开始计算count个返回行。
LIMIT子句不支持ROWNUM作为count或者offset。
- OFFSET子句
SQL:2008开始提出一种不同的语法:
OFFSET start { ROW | ROWS }start:指定开始返回行之前忽略的行数。
- FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY [OFFSET offset_count]
如果不指定count,默认值为1,FETCH子句限定返回查询结果从第一行开始的总行数。
- FOR UPDATE | SHARE子句
- FOR UPDATE:对SELECT检索出的行进行添加排他锁,用于避免检索出的行数据在当前事务结束前被其他事务修改或者删除,即其他的UPDATE、DELETE、SELECT FOR UPDATE操作将被阻塞,直到当前事务结束。
- FOR SHARE:对SELECT检索出的行进行添加共享锁,用于避免检索出的行数据在当前事务结束前被其他事务修改或者删除,即其他的UPDATE、DELETE、SELECT操作将被阻塞(不阻塞SELECT FOR SHARE),直到当前事务结束。
- [ OF table_name [, ...] ]:添加锁的对象。如果明确地指定表名称,则只对指定的表进行添加锁,其他在SELECT中使用的表将不会被锁定;否则将锁定该命令中所有使用的表。如果应用于一个视图或者子查询,同样将锁定所有该视图或子查询中使用到的指定的表。
为了避免操作等待其他事务提交,可通过以下选项进行设置:
- NOWAIT:如果被选择的行不能立即添加锁,执行SELECT FOR UPDATE NOWAIT将会立即报错。
- WAIT n:如果被选择的行不能立即添加锁,等待n秒(其中,n为int类型,取值范围:0 <= n <= 2147483),n秒内获取锁则正常执行,否则报错。
- SKIP LOCKED:对表添加锁时跳过已经加锁的行,SKIP LOCKED只能跳过行锁,对不同事务中锁与锁不互相阻塞的场景不会跳过,如SELECT FOR SHARE - SELECT FOR SHARE SKIP LOCKED。
- 多个FOR UPDATE和FOR SHARE子句可以用于为不同的表指定不同的锁定模式。
- 如果一个表中同时出现(或隐含同时出现)在FOR UPDATE和FOR SHARE子句中,则按照FOR UPDATE处理。类似的,同理,如果影响一个表的任意子句中出现了NOWAIT,该表将按照NOWAIT处理。
- 对于FOR UPDATE或FOR SHARE操作,执行计划不能下推的SQL直接返回报错信息;对于执行计划可以下推的,下推到DN执行。
- 对投影列或者WHERE条件中存在rownum的查询不支持FOR UPDATE或FOR SHARE。
- 对于子查询是stream计划的FOR UPDATE或FOR SHARE操作,不支持加锁的同一行被并发更新。
- 对于ORDER BY FOR UPDATE或ORDER BY FOR SHARE操作,stream计划的sort算子和lock算子执行顺序与其他计划有所差别。stream计划是先执行lock再执行sort,其他计划是先执行sort再执行lock。原因是stream计划如果数据不在当前DN,需要重分布数据,回到数据的原始DN去加锁。由于重分布后数据会变得无序,所以最后还要加sort算子。如果先sort后lock,这样会导致原始有序的数据重新变得无序,这时sort就无意义了,可以消除此sort算子。最终计划的执行顺序就由原始的sort -> lock -> sort变为了lock -> sort。
- 对于FOR UPDATE或FOR SHARE操作并发场景,通常使用添加ORDER BY对数据进行排序的方式来避免无响应等异常,在分布式内这种做法不合理,因为DN的加锁顺序无法通过ORDER BY进行确定,另外指定ORDER BY会造成性能开销,所以不建议加ORDER BY解决该问题。
- DATABASE LINK功能不支持SKIP LOCKED语法。
- 分布式场景下不支持对多表FOR UPDATE/SHARE。
- 层次查询语句不支持与该子句同时使用。
- NLS_SORT
按照指定的方式排序。
取值范围:
- SCHINESE_PINYIN_M,按照中文拼音排序。
- generic_m_ci,不区分大小写排序(可选,仅支持纯英文不区分大小写排序)。
目前仅支持中文拼音格式排序和不区分大小写排序。在创建数据库时,需指定编码格式为UTF8、GB18030、GB18030_2022、GBK或ZHS16GBK;如果指定为其他编码,如SQL_ASCII,则可能报错或排序无效。
- PARTITION子句
查询分区表中相应分区的数据。
