表达式
表达式类似一个公式,我们可以将其应用在查询语句中,用来查找数据库中指定条件的结果集。
简单表达式
逻辑表达式
逻辑表达式的操作符和运算规则,详情请参见逻辑操作符。
比较表达式
常用的比较操作符,请参见操作符。
除比较操作符外,还可以使用以下句式结构:
BETWEEN操作符
a BETWEEN x AND y等效于a >= x AND a <= y
a NOT BETWEEN x AND y等效于a < x OR a > y
检查一个值是不是NULL,可使用:
expression IS NULL
expression IS NOT NULL
或者与之等价的句式结构,但不是标准的:
expression ISNULL
expression NOTNULL
须知: 不要写expression=NULL或expression<>(!=)NULL,因为NULL代表一个未知的值,不能通过该表达式判断两个未知值是否相等。
is distinct from/is not distinct from
is distinct from
A和B的数据类型、值不完全相同时为true。
A和B的数据类型、值完全相同时为false。
将空值视为相同。
is not distinct from
A和B的数据类型、值不完全相同时为false。
A和B的数据类型、值完全相同时为true。
将空值视为相同。
伪列(ROWNUM)
ROWNUM是一个伪列,它返回一个数字,表示从查询中获取结果的行编号。第一行的ROWNUM为1,第二行的为2,依此类推。ROWNUM的返回类型为numeric。ROWNUM可以用于限制查询返回的总行数,例如下面语句限制查询从customer_t1表中返回最多3条记录。
openGauss=# SELECT * FROM customer_t1 WHERE ROWNUM <= 3; c_customer_sk | c_customer_id | c_first_name | c_last_name | amount ---------------+---------------+--------------+-------------+-------- 3869 | hello | Grace | | 1000 3869 | hello | Grace | | 1000 3869 | | Grace | | (3 rows)
条件表达式
在执行SQL语句时,可通过条件表达式筛选出符合条件的数据。
条件表达式主要有以下几种:
CASE
CASE表达式是条件表达式,类似于其他编程语言中的CASE语句。
CASE表达式的语法图请参考图1。
CASE子句可以用于合法的表达式中。condition是一个返回BOOLEAN数据类型的表达式:
- 如果结果为真,CASE表达式的结果就是符合该条件所对应的result。
- 如果结果为假,则以相同方式处理随后的WHEN或ELSE子句。
- 如果各WHEN condition都不为真,表达式的结果就是在ELSE子句执行的result。如果省略了ELSE子句且没有匹配的条件,结果为NULL。
示例:
注:如果模式tpcds不存在。请创建模式tpcds后,再进行建表操作。
openGauss=# CREATE TABLE tpcds.case_when_t1(CW_COL1 INT); openGauss=# INSERT INTO tpcds.case_when_t1 VALUES (1), (2), (3); openGauss=# SELECT * FROM tpcds.case_when_t1; cw_col1 --------- 1 2 3 (3 rows) openGauss=# SELECT CW_COL1, CASE WHEN CW_COL1=1 THEN 'one' WHEN CW_COL1=2 THEN 'two' ELSE 'other' END FROM tpcds.case_when_t1 ORDER BY 1; cw_col1 | case ---------+------- 1 | one 2 | two 3 | other (3 rows) openGauss=# DROP TABLE tpcds.case_when_t1;
DECODE
DECODE的语法图请参见图2。
将表达式base_expr与后面的每个compare(n) 进行比较,如果匹配返回相应的value(n)。如果没有发生匹配,则返回default。
示例:
openGauss=# SELECT DECODE('A','A',1,'B',2,0); case ------ 1 (1 row)
COALESCE
COALESCE的语法图请参见图3。
COALESCE返回它的第一个非NULL的参数值。如果参数都为NULL,则返回NULL。它常用于在显示数据时用缺省值替换NULL。和CASE表达式一样,COALESCE只计算用来判断结果的参数,即在第一个非空参数右边的参数不会被计算。
示例:
注:如果模式tpcds不存在。请创建模式tpcds后,再进行建表操作。
openGauss=# CREATE TABLE tpcds.c_tabl(Description varchar(10), short_Description varchar(10), last_value varchar(10)) ; openGauss=# INSERT INTO tpcds.c_tabl VALUES('abc', 'efg', '123'); openGauss=# INSERT INTO tpcds.c_tabl VALUES(NULL, 'efg', '123'); openGauss=# INSERT INTO tpcds.c_tabl VALUES(NULL, NULL, '123'); openGauss=# SELECT Description, short_Description, last_value, COALESCE(Description, short_Description, last_value) FROM tpcds.c_tabl ORDER BY 1, 2, 3, 4; Description | short_Description | last_value | coalesce -------------+-------------------+------------+---------- abc | efg | 123 | abc | efg | 123 | efg | | 123 | 123 (3 rows) openGauss=# DROP TABLE tpcds.c_tabl;
如果Description不为NULL,则返回Description的值,否则计算下一个参数short_Description;如果short_Description不为NULL,则返回short_Description的值,否则计算下一个参数last_value;如果last_value不为NULL,则返回last_value的值,否则返回(none)。
openGauss=# SELECT COALESCE(NULL,'Hello World'); coalesce --------------- Hello World (1 row)
NULLIF
NULLIF的语法图请参见图4。
只有当value1和value2相等时,NULLIF才返回NULL。否则它返回value1。
示例:
注:如果模式tpcds不存在。请创建模式tpcds后,再进行建表操作。
openGauss=# CREATE TABLE tpcds.null_if_t1 ( NI_VALUE1 VARCHAR(10), NI_VALUE2 VARCHAR(10) ); openGauss=# INSERT INTO tpcds.null_if_t1 VALUES('abc', 'abc'); openGauss=# INSERT INTO tpcds.null_if_t1 VALUES('abc', 'efg'); openGauss=# SELECT NI_VALUE1, NI_VALUE2, NULLIF(NI_VALUE1, NI_VALUE2) FROM tpcds.null_if_t1 ORDER BY 1, 2, 3; ni_value1 | ni_value2 | nullif -----------+-----------+-------- abc | abc | abc | efg | abc (2 rows) openGauss=# DROP TABLE tpcds.null_if_t1;
如果value1等于value2则返回NULL,否则返回value1。
openGauss=# SELECT NULLIF('Hello','Hello World'); nullif -------- Hello (1 row)
GREATEST(最大值),LEAST(最小值)
GREATEST的语法图请参见图5。
从一个任意数字表达式的列表里选取最大的数值。
openGauss=# SELECT greatest(9000,155555,2.01); greatest ---------- 155555 (1 row)
LEAST的语法图请参见图6。
从一个任意数字表达式的列表里选取最小的数值。
以上的数字表达式必须都可以转换成一个普通的数据类型,该数据类型将是结果类型。
列表中的NULL值将被忽略。只有所有表达式的结果都是NULL的时候,结果才是NULL。
示例:
openGauss=# SELECT least(9000,2); least ------- 2 (1 row)
NVL
NVL的语法图请参见图7。
如果value1为NULL则返回value2,如果value1非NULL,则返回value1。
示例:
openGauss=# SELECT nvl(null,1); nvl ----- 1 (1 row) openGauss=# SELECT nvl ('Hello World' ,1); nvl --------------- Hello World (1 row)
子查询表达式
子查询表达式主要有以下几种:
EXISTS/NOT EXISTS
EXISTS/NOT EXISTS的语法图请参见图8。
EXISTS的参数是一个任意的SELECT语句,或者说子查询。系统对子查询进行运算以判断它是否返回行。如果它至少返回一行,则EXISTS结果就为"真";如果子查询没有返回任何行, EXISTS的结果是"假"。
这个子查询通常只是运行到能判断它是否可以生成至少一行为止,而不是等到全部结束。
示例:
注:下面查询语句中tpcds是模式名。
openGauss=# SELECT sr_reason_sk,sr_customer_sk FROM tpcds.store_returns WHERE EXISTS (SELECT d_dom FROM tpcds.date_dim WHERE d_dom = store_returns.sr_reason_sk and sr_customer_sk <10); sr_reason_sk | sr_customer_sk --------------+---------------- 13 | 2 22 | 5 17 | 7 25 | 7 3 | 7 31 | 5 7 | 7 14 | 6 20 | 4 5 | 6 10 | 3 1 | 5 15 | 2 4 | 1 26 | 3 (15 rows)
IN/NOT IN
IN/NOT IN的语法请参见图9。
右边是一个圆括弧括起来的子查询,它必须只返回一个字段。左边表达式对子查询结果的每一行进行一次计算和比较。如果找到任何相等的子查询行,则IN结果为"真"。如果没有找到任何相等行,则结果为"假"(包括子查询没有返回任何行的情况)。
表达式或子查询行里的NULL遵照SQL处理布尔值和NULL组合时的规则。如果两个行对应的字段都相等且非空,则这两行相等;如果任意对应字段不等且非空,则这两行不等;否则结果是未知(NULL)。如果每一行的结果都是不等或NULL ,并且至少有一个NULL ,则IN的结果是NULL 。
示例:
注:下面查询语句中tpcds是模式名。
openGauss=# SELECT sr_reason_sk,sr_customer_sk FROM tpcds.store_returns WHERE sr_customer_sk IN (SELECT d_dom FROM tpcds.date_dim WHERE d_dom < 10); sr_reason_sk | sr_customer_sk --------------+---------------- 10 | 3 26 | 3 22 | 5 31 | 5 1 | 5 32 | 5 32 | 5 4 | 1 15 | 2 13 | 2 33 | 4 20 | 4 33 | 8 5 | 6 14 | 6 17 | 7 3 | 7 25 | 7 7 | 7 (19 rows)
ANY/SOME
ANY/SOME的语法图请参见图10。
右边是一个圆括弧括起来的子查询,它必须只返回一个字段。左边表达式使用operator对子查询结果的每一行进行一次计算和比较,其结果必须是布尔值。如果至少获得一个真值,则ANY结果为“真”。如果全部获得假值,则结果是“假”(包括子查询没有返回任何行的情况)。SOME是ANY的同义词。IN与ANY可以等效替换 。
示例:
注:下面查询语句中tpcds是模式名。
openGauss=# SELECT sr_reason_sk,sr_customer_sk FROM tpcds.store_returns WHERE sr_customer_sk < ANY (SELECT d_dom FROM tpcds.date_dim WHERE d_dom < 10); sr_reason_sk | sr_customer_sk --------------+---------------- 26 | 3 17 | 7 32 | 5 32 | 5 13 | 2 31 | 5 25 | 7 5 | 6 7 | 7 10 | 3 1 | 5 14 | 6 4 | 1 3 | 7 22 | 5 33 | 4 20 | 4 33 | 8 15 | 2 (19 rows)
ALL
ALL的语法请参见图11。
右边是一个圆括弧括起来的子查询,它必须只返回一个字段。左边表达式使用operator对子查询结果的每一行进行一次计算和比较,其结果必须是布尔值。如果全部获得真值,ALL结果为"真"(包括子查询没有返回任何行的情况)。如果至少获得一个假值,则结果是"假"。
示例:
注:下面查询语句中tpcds是模式名。
openGauss=# SELECT sr_reason_sk,sr_customer_sk FROM tpcds.store_returns WHERE sr_customer_sk < all(SELECT d_dom FROM tpcds.date_dim WHERE d_dom < 10); sr_reason_sk | sr_customer_sk --------------+---------------- (0 rows)
数组表达式
IN
expression IN (value [, …])
右侧括号中的是一个表达式列表。左侧表达式的结果与表达式列表的内容进行比较。如果列表中的内容符合左侧表达式的结果,则IN的结果为true。如果没有相符的结果,则IN的结果为false。
示例:
openGauss=# SELECT 8000+500 IN (10000, 9000) AS RESULT; result ---------- f (1 row)
如果表达式结果为null,或者表达式列表不符合表达式的条件且右侧表达式列表返回结果至少一处为空,则IN的返回结果为null,而不是false。这样的处理方式和SQL返回空值的布尔组合规则是一致的。
NOT IN
expression NOT IN (value [, …])
右侧括号中的是一个表达式列表。左侧表达式的结果与表达式列表的内容进行比较。如果在列表中的内容没有符合左侧表达式结果的内容,则NOT IN的结果为true。如果有符合的内容,则NOT IN的结果为false。
示例:
openGauss=# SELECT 8000+500 NOT IN (10000, 9000) AS RESULT; result ---------- t (1 row)
如果查询语句返回结果为空,或者表达式列表不符合表达式的条件且右侧表达式列表返回结果至少一处为空,则NOT IN的返回结果为null,而不是false。这样的处理方式和SQL返回空值的布尔组合规则是一致的。
说明: 在所有情况下X NOT IN Y等价于NOT(X IN Y)。
ANY/SOME(array)
expression operator ANY (array expression)
expression operator SOME (array expression)
右侧括号中的是一个数组表达式,它必须产生一个数组值。左侧表达式的结果使用操作符对数组表达式的每一行结果都进行计算和比较,比较结果必须是布尔值。
- 如果对比结果至少获取一个真值,则ANY的结果为true。
- 如果对比结果没有真值,则ANY的结果为false。
- 如果结果没有真值,并且数组表达式生成至少一个值为null,则ANY的值为NULL,而不是false。这样的处理方式和SQL返回空值的布尔组合规则是一致的。
- SOME是ANY的同义词。
示例:
openGauss=# SELECT 8000+500 < SOME (array[10000,9000]) AS RESULT; result ---------- t (1 row) openGauss=# SELECT 8000+500 < ANY (array[10000,9000]) AS RESULT; result ---------- t (1 row)
ALL(array)
expression operator ALL (array expression)
右侧括号中的是一个数组表达式,它必须产生一个数组值。左侧表达式的结果使用操作符对数组表达式的每一行结果都进行计算和比较,比较结果必须是布尔值。
- 如果所有的比较结果都为真值(包括数组不含任何元素的情况),则ALL的结果为true。
- 如果存在一个或多个比较结果为假值,则ALL的结果为false。
- 如果数组表达式产生一个NULL数组,则ALL的结果为NULL。如果左边表达式的值为NULL ,则ALL的结果通常也为NULL(某些不严格的比较操作符可能得到不同的结果)。另外,如果右边的数组表达式中包含null元素并且比较结果没有假值,则ALL的结果将是NULL(某些不严格的比较操作符可能得到不同的结果), 而不是真。这样的处理方式和SQL返回空值的布尔组合规则是一致的。
示例
openGauss=# SELECT 8000+500 < ALL (array[10000,9000]) AS RESULT; result ---------- t (1 row)
行表达式
语法如下:
row_constructor operator row_constructor
两边都是一个行构造器,两行值必须具有相同数目的字段,每一行都进行比较,行比较允许使用=,<>,<,<=,>=等操作符,或其中一个相似的语义符。
=<>和别的操作符使用略有不同。如果两行值的所有字段都是非空并且相等,则认为两行是相等的;如果两行值的任意字段为非空并且不相等,则认为两行是不相等的;否则比较结果是未知的(null)。
对于<,<=,>,> =的情况下,行中元素从左到右依次比较,直到遇到一对不相等的元素或者一对为空的元素。如果这对元素中存在至少一个null值,则比较结果是未知的(null),否则这对元素的比较结果为最终的结果。
示例:
openGauss=# SELECT ROW(1,2,NULL) < ROW(1,3,0) AS RESULT;
result
----------
t
(1 row)
游标表达式
游标表达式的语法请参见图12。
使用示例:
-- 样例表
create table test1(id int, name varchar, job varchar);
create table test2(id int, age int);
insert into test1 values (1, 'zhang', 'worker'),(2, 'li', 'teacher'),(3, 'wang', 'engineer');
insert into test2 values (1, 20),(2, 30),(3, 40);
-- 在匿名块中使用游标表达式样例
openGauss=# DECLARE CURSOR c1 IS SELECT t.age, CURSOR(SELECT name FROM test1 t1 where t1.id = t.id) abc FROM test2 t;
openGauss-# age_temp int;
openGauss-# name_temp varchar;
openGauss-# type emp_cur_type is ref cursor;
openGauss-# c2 emp_cur_type;
openGauss-# BEGIN
openGauss$# OPEN c1;
openGauss$# loop
openGauss$# fetch c1 into age_temp, c2;
openGauss$# exit when c1%notfound;
openGauss$# raise notice 'age : %',age_temp;
openGauss$# loop
openGauss$# fetch c2 into name_temp;
openGauss$# exit when c2%notfound;
openGauss$# raise notice 'name : %', name_temp;
openGauss$# end loop;
openGauss$# close c2;
openGauss$# end loop;
openGauss$# CLOSE c1;
openGauss$# END;
openGauss$# /
NOTICE: age : 20
NOTICE: name : zhang
NOTICE: age : 30
NOTICE: name : li
NOTICE: age : 40
NOTICE: name : wang
ANONYMOUS BLOCK EXECUTE
openGauss=#
-- 在存储过程中使用游标表达式样例
openGauss=# create or replace procedure test_cursor_expression
openGauss-# as
openGauss$# age_temp int;
openGauss$# name_temp varchar;
openGauss$# type emp_cur_type is ref cursor;
openGauss$# c2 emp_cur_type;
openGauss$# cursor c1 is SELECT t.age, CURSOR(SELECT name FROM test1 t1 where t1.id = t.id) abc FROM test2 t;
openGauss$# begin
openGauss$# OPEN c1;
openGauss$# loop
openGauss$# fetch c1 into age_temp, c2;
openGauss$# exit when c1%notfound;
openGauss$# raise notice 'age : %',age_temp;
openGauss$# loop
openGauss$# fetch c2 into name_temp;
openGauss$# exit when c2%notfound;
openGauss$# raise notice 'name : %', name_temp;
openGauss$# end loop;
openGauss$# close c2;
openGauss$# end loop;
openGauss$# CLOSE c1;
openGauss$# end;
openGauss$# /
CREATE PROCEDURE
openGauss=# call test_cursor_expression();
NOTICE: age : 20
NOTICE: name : zhang
NOTICE: age : 30
NOTICE: name : li
NOTICE: age : 40
NOTICE: name : wang
test_cursor_expression
------------------------
(1 row)
openGauss=# drop procedure test_cursor_expression;
DROP PROCEDURE
openGauss=#
-- 游标表达式作为SYS_REFCURSOR参数
openGauss=# CREATE FUNCTION f(cur SYS_REFCURSOR)
openGauss-# RETURN NUMBER IS
openGauss$# name_temp varchar;
openGauss$# count_temp number:=0;
openGauss$# begin
openGauss$# loop
openGauss$# fetch cur into name_temp;
openGauss$# exit when cur%NOTFOUND;
openGauss$# count_temp:=count_temp+1;
openGauss$# end loop;
openGauss$# close cur;
openGauss$# return count_temp;
openGauss$# end;
openGauss$# /
CREATE FUNCTION
openGauss=#
openGauss=# select * from test1 where f(cursor(select name from test1)) > 0;
id | name | job
----+-------+----------
1 | zhang | worker
2 | li | teacher
3 | wang | engineer
(3 rows)
openGauss=#
当游标中嵌套游标表达式的时候,游标表达式在每次提取一行数据的时候自动打开,仅如下场景下会自动关闭游标:
- 手动关闭游标表达式,如上述示例中的close c2。
- 当事务结束的时候自动关闭所有的游标表达式。
使用限制
- 游标表达式只支持select和with开头的查询语句。
- 只有将游标游标表达式fetch into到才能使用,直接select游标表达式将只显示ptotal名,如下所示:
openGauss=# SELECT t.age, CURSOR(SELECT name FROM test1 t1 where t1.id = t.id) abc FROM test2 t;
age | abc
-----+---------------------
20 | <unnamed portal 8>
30 | <unnamed portal 9>
40 | <unnamed portal 10>
(3 rows)
openGauss=#
- 游标表达式在事务结束的时候将自动清理资源,因此无法再事务中访问自治事务的游标表达式,如下所示的sql会报错:
openGauss=# create or replace procedure test_cursor_expression_1(out cur1 refcursor)
openGauss-# as
openGauss$# PRAGMA AUTONOMOUS_TRANSACTION;
openGauss$# begin
openGauss$# OPEN cur1 for SELECT t.age, CURSOR(SELECT name FROM test1 t1 where t1.id = t.id) abc FROM test2 t;
openGauss$# end;
openGauss$# /
CREATE PROCEDURE
openGauss=#
openGauss=# create or replace procedure test_cursor_expression_2()
openGauss-# as
openGauss$# age_temp int;
openGauss$# name_temp varchar;
openGauss$# type emp_cur_type is ref cursor;
openGauss$# c1 emp_cur_type;
openGauss$# c2 emp_cur_type;
openGauss$# begin
openGauss$# test_cursor_expression_1(c1);
openGauss$# loop
openGauss$# fetch c1 into age_temp, c2;
openGauss$# exit when c1%notfound;
openGauss$# raise notice 'age_temp : % ', age_temp;
openGauss$# loop
openGauss$# fetch c2 into name_temp;
openGauss$# exit when c2%notfound;
openGauss$# raise notice 'name_temp : %',name_temp;
openGauss$# end loop;
openGauss$# end loop;
openGauss$# end;
openGauss$# /
CREATE PROCEDURE
openGauss=#
openGauss=#
openGauss=# call test_cursor_expression_2();
NOTICE: age_temp : 20
ERROR: cursor "<unnamed portal 5>" does not exist in FETCH statement.
CONTEXT: PL/pgSQL function test_cursor_expression_2() line 13 at FETCH
openGauss=#
- 游标表达式只支持访问游标表达式中或者其父节点的变量,如下sql在游标表达式中访问其父节点的父节点变量是不支持的。
openGauss=# create or replace procedure test_cursor_expression
openGauss-# as
openGauss$# age_temp int;
openGauss$# name_temp varchar;
openGauss$# type emp_cur_type is ref cursor;
openGauss$# c2 emp_cur_type;
openGauss$# cursor c1 is SELECT t.age, cursor(select cursor(select t1.name FROM test1 t1 where t1.id = t.id)) abc FROM test2 t;
openGauss$# begin
openGauss$# OPEN c1;
openGauss$# loop
openGauss$# fetch c1 into age_temp, c2;
openGauss$# exit when c1%notfound;
openGauss$# raise notice 'age : %',age_temp;
openGauss$# loop
openGauss$# fetch c2 into name_temp;
openGauss$# exit when c2%notfound;
openGauss$# raise notice 'name : %', name_temp;
openGauss$# end loop;
openGauss$# close c2;
openGauss$# end loop;
openGauss$# CLOSE c1;
openGauss$# end;
openGauss$# /
CREATE PROCEDURE
openGauss=# call test_cursor_expression();
ERROR: only spport access cursor and it's parent var in cursor expression.
CONTEXT: referenced column: abc
SQL statement "SELECT t.age, cursor(select cursor(select t1.name FROM test1 t1 where t1.id = t.id))abc FROM test2 t"
PL/pgSQL function test_cursor_expression() line 7 at OPEN
openGauss=# drop procedure test_cursor_expression;
DROP PROCEDURE
openGauss=#
- 对于非select和with开头的查询语句,如果需要解释成游标表达式,需要将behavior_compat_options的prefer_parse_cursor_parentheses_as_expr开启,如如下样例所示:
openGauss=# SELECT t.age, CURSOR((SELECT name FROM test1 t1 where t1.id = t.id)) abc FROM test2 t;
ERROR: function cursor(character varying) does not exist
LINE 1: SELECT t.age, CURSOR((SELECT name FROM test1 t1 where t1.id ...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
CONTEXT: referenced column: abc
openGauss=#
openGauss=# set behavior_compat_options = 'prefer_parse_cursor_parentheses_as_expr';
SET
openGauss=#
openGauss=# SELECT t.age, CURSOR((SELECT name FROM test1 t1 where t1.id = t.id)) abc FROM test2 t;
age | abc
-----+--------------------
20 | <unnamed portal 1>
30 | <unnamed portal 2>
40 | <unnamed portal 3>
(3 rows)
openGauss=#