oracle语法差异

虚拟表

虚拟表

Oracle获取一个常量需要通过dual,unvdb则不需要

oracle unvdb
select 2 from dual; select 3

虚拟列

虚拟列rownum

对于查询返回的每行数据,rownum都会返回对应列的数值,第一行为1第二行为2以此类推。

  • rownum在select列表中时重写为row_number() over ()

  • rownum在where子句中时重写为limit… offset…

oracle unvdb
select rownum from test; select row_numder() over() as rownum from test;
select tableoid from test where rownum < 10 and rownum >=2; select tableoid from test limit 9 OFFSET 2 ;
select name from test where rownum < 10 and age = '111'; select test.name from test where test.age = '111' limit9;
select * from test wherer rownum between 1 and 10; select tableoid from test limt 10 offset 0;

虚拟列rowid

oracle 中rowid虚拟列会返回特定行的具体地址,在unvdb中为 tableoid || ‘#’ || ctid

oralce unvdb
select rowid, t.* from test t; select tableoid || '#' || ctid, t.* from test as t;

字符串函数

nvl(col,value)

在oracle中nvl(col,value)用来设置默认值,col为空就设置为value。在unvdb中重写为coalesce

oracle unvdb
select nvl(t_phone,1) from test; select coalesce(customer.t_phone,'1') from test;

nvl2(col,v1,v2)

nvl2对col的null值进行处理,如果col为null,则返回v1,否则返回v2。unvdb中没有此类函数,可以重写为case when。

oracle unvdb
select nvl2(t_phone,1,2) from test; select case when t_phone is null then 1else 2 end from test;

decode(arg1,arg2,arg3,arg4)

oracle中decode(arg1,arg2,arg3,arg4)函数,表示arg1等于arg2时取arg3,否则取arg4。 unvdb中没有此类函数,可以重写为 case when

oracle unvdb
select decode(t_phone,'110',1,2) from test; select case when t_phone = '110' then 1else 2 end from test;
select decode(t_phone,null,1,2) from test; select case when t_phone is null then 1 else 2 end from test;

substr(str,int,int)

在oracle中substr是用来取第一个字符串的子串,unvdb中有同名的函数实现类似的功能。其中不同的是oracle中,第二,三个参数是可以为负数的,代表从后面进行计数。unvdb不允许其成为负数,需要对其进行转换。oracle中以0开始计数,unvdb中以1开始计数。

oracle unvdb
select substr(t_phone,1,-2) from test; select substr(t_phone1,length(t_phone) -2) from test;
select substr(t_phone,-3,1) from test; select substr(t_phone,length(t_phone) -3,1) from test;

instr(str1,str2)

oracle中instr用来取一个字符穿的子串位置,当其只有两个参数时,表示子串第一次出现的位置,和unvdb中对应的函数为strpos。当有多个参数时没有对应函数。

oracle unvdb
select inste('123','23') select strpos('123','23')

replace(srcstr,oldsub[,newsub])

在oracle中,replace()函数用于替换字符串,replace(srcstr,oldsub[,newsub]), 和unvdb中的replace函数用法基本一直。需要注意在oracle中没有第三个参数时代表删除此字符,在unvdb中第三个参数可以设置为’’。

oracle unvdb
select replace('123','1'); select replace('123','1','');

listagg(str,[str])

oracle里的listagg函数实现对列值的拼接,它可以在分组内以指定顺序对非分组列进行拼接。在unvdb中可以使用string_agg函数来实现,需要注意语法方面也有区别。另外,其第二个参数可选,默认值’’,在unvdb中需要补充第二个参数。

  • 当没有group by子句时,可以使用over(partiton by… order by…)进行替换

  • 当指定group by子句时,它的重写算法比较复杂

  • 如果需要保持拼接的顺序,需要通过子查询来实现(见第二行)

  • 如果不需要保持拼接顺序,可以把它转化为简单的聚集函数(见第三行)

oracle unvdb
select listagg(t_name,',')
within group(order by t_name)
over (partiton by t_name) as name from test;
select string_agg(test.t_name,',')
over (patition by test.t_phone order by t_custkey)
as name from test;
select listagg(t_name,',')
within group(order by t_name) as
name from test group by t_phone;
select max(paw_dt.name) as name
from (select string_agg (test.t_name,',')
over (partition by test.t_phone order by t_name)
as name, t_phone from test) as paw_dt group by t_phone ;
select listagg(t_name,',')
within group(order by t_name)
as name from test group by t_phone;
select string_agg(t_name,',')
as name from test group by t_phone;

日期函数

sysdate和systimestamp

oracle中sysdate()和sysdate返回的是当前系统的日期 ,时间 (日期,时分秒),在unvdb中对应now()或current_timestamp (日期-时分秒-毫秒)。

oracle中systimestamp返回系统当前时间戳(日期-时分秒-毫秒),在unvdb中对应now()或current_timestamp

oracle unvdb
select sysdate select current_to,estamp
select sysdate() select now()
select systimestamp select current_timestamp

to_date(str,fmt)

oracle中to_date返回的是时间类型,在unvdb中to_date是日期类型,在unvdb中对应的是to_timestamp

oracle unvdb
select to_date(endTime ,'yyyy-mm-ddhh24:mi:ss') from test; select to_timestamp(endTime,'yyyy-mm-ddhh24:mi:ss') from test;

trunc(arg1,[arg2])

在oracle中trunc函数有两种使用方法

  • 第一种是对数字进行截取, trunc(num,[int]); 是去掉数字num小数位以后的部分,并且不进行四舍五入。这种用法和在unvdb的trunc用法一致,不需要转换。

  • 第二种用法是对日期进行提取,trunc(date,[fmt])。这种用法在unvdb对应的函数是date_trunc(fmt, date),需注意在unvdb中fmt是第一个参数,且不可省略。

oracle unvdb
select trunc(111.23,2) select trunc(111.23,2)
select trunc(sysdate,'year') select date_trunc('year',current_timestamp)
select trunc(sysdate) select date_trunc('dd',current_timestamp)

add_months(date,int)

oracle中的add_months函数主要用于对日期函数进行按月增加的操作。在unvdb中没有对应的函数,需要转为基于日期和interval的运算。

oracle unvdb
select add_months(sysdate,2) select current_timestamp + 2 * interval '1 month'

last_ady(date)

oracle中last_day返回指定日期所在月份的最后一天,在unvdb中没有对应函数,需要转为基于日期和interval的运算。

oracle unvdb
select add_months(sysdate,2) select cast(date_trunc('MONTH',current_timestamp) + interval '1 MONTH - 1 DAY' as date)

sql语句

HAVING子句顺序

oracle中允许HACVING在group by 之前或之后。在unvdb中,HAVING子句必须在 group by之后。

oracle unvdb
select t_name from test having count(*) > 2 group by t_name; select t_name from test group by t_name having count(*) > 2;

括号中的表名

oracle中允许单表在括号中使用表名,而unvdb中不允许。

oracle unvdb
select * from (test); select * from test;

UNIQUE关键字

oracle中允许使用UNIQUE进行去重,在unvdb中是DISTINCT关键字实现。

oracle unvdb
select unique t_phone from test; select distinct test.t_phone from test;

MINUS关键字

oracle中可以使用minus关键字来取两个结果的集的差,在unvdb中迁移为except。

oracle unvdb
select t_custkey from test minus select o_custkey from orders; select t_custkey from test except select o_custkey from orders ;

FROM关键字

oracle的delete语句的FROM关键字可以省略,迁移至unvdb需补充上。

oracle unvdb
delete test where 1=0; delete from test where 1 = 0 ;

NOLOGGING关键字

oracle在执行iinsert语句时,可以通过指定NOLOGGING关键字来减少日志记录,提升操作性能。unvdb不支持此关键字。

oracle unvdb
insert into test nologging select * from test_bk; insert into test select * from test_bk;

AS关键字

unvdb 中 insert into 后面不需要添加as关键字。

oracle unvdb
insert into t as select c1 from t1; insert into t select c1 from t1;

FROM子查询别名

oracle中不引起歧义的情况下可以不需要别名,在unvdb中,所有from 子查询都需要带有别名

oracle unvdb
select * from (select * from test); select * from (select * from test) as foo ;

UPDATE语句里的字段名

在unvdb中,update的时候,更新列不允许添加表名前缀。

oracle unvdb
update test t set t.t_name = ‘xxx’ where t_custkey = 1; update test set t_name = ‘xxx’ where t_custkey = 1 ;

左(右)外连接

在oracle中,外连接可以通过在条件上添加(+)来定义, 连接符(+)跟在哪个条件后面就是哪张表被左连。在unvdb中,需将其重写为标准的外连接语法。

oracle unvdb
select * from test,orders where t_custkey = o_custkey(+); select * from test left outer join orders on t_custkey = o_custkey;
select * from test,orders
where t_custkey(+) = o_custkey and t_name(+) = o_clerk and o_custkey>100;
select * from test
right outer join orders on (t_custkey = o_custkey and t_name = o_clerk )
where o_custkey > 100 ;

CONNECT BY子句

oracle中,CONNECT BY 用于存在上下级等层级关系的数据表进行递归查询。语法格式:START WITH condition1 CONNECT BY [ NOCYCLE ] condition2 在unvdb中通过Recursive Common Table Expression来实现此功能,主要是把START WITH… CONNECT BY Prior拆成两个部分,查询表一致,但条件不一致,用UNION ALL合并.

oracle unvdb
select id from city_branch start with id=1 connect by prior id=parent_id; with RECURSIVE MIG_CTE as (
select id, 1 as level from city_branch where id = 1
union all
select id, level + 1 from city_branch, MIG_CTE where MIG_CTE.id = parent_id)
select * from MIG_CTE ;
select t.branch_level, t.id from city_branch c where (c.branch_level = ‘1’ or t.branch_level = ‘2’)
and (t.sign = ‘1’ or t.sign = ‘4’ or t.sign = ‘8’) and t.status = ‘1’ start with c.id = 1
connect by c.id = prior c.parent_id
order by c.branch_level desc;
with RECURSIVE MIG_CTE as
(select t.branch_level, t.id, 1 as level from city_branch as cwhere ((((branch_level = ‘1’ or t.branch_level = ‘2’)and ((t.sign = ‘1’ or t.sign = ‘4’) or t.sign = ‘8’)) and t.status = ‘1’) and c.id = 1)
union all
select t.branch_level, t.id, level + 1 from city_branch as c, MIG_CTE where ((((branch_level = ‘1’ or t.branch_level = ‘2’) and ((t.sign = ‘1’ or t.sign = ‘4’)
or t.sign = ‘8’)) and t.status = ‘1’) and c.id = MIG_CTE.parent_id))
select * from MIG_CTE order by MIG_CTE.branch_level desc;

操作符的强类型限制

oracle中不同类型进行基于操作符的运算,会自动转化类型,譬如select 1 + ‘1’ from dual。

unvdb是强类型,不同类型的运算会提示类型不匹配,执行select 1 + ‘1’会报错,需要进行显式的类型转换。

涉及的操作符类型包括:

操作符 操作符名称
+ 加法
- 减法
/ 除法
% 取余
* 乘法
|| 字符串拼接

数值运算(+,-,*,/,%)

oracle unvdb
select 1+'1' select 1+1
select 1 + charCol from tbl ; select 1+ cast(charCol as unmeric) from tbl ;
select '1' - 1 select 1-1
select 1* charCol from tbl ; select 1 * cast(charCol as numeric) from tbl ;
select 1 / charCol from tbl ; select 1 / cast(charCol as numeric) from tbl;
select charCol % 2 from tbl; select cast(charCol as numeric) % 2 from tbl;

日期计算(+,-)

oracle unvdb
select sysdate - 1 select current_timestamp - interval ‘1’ DAY
select 1 + sysdate() select interval ‘1’ DAY + now()
select systimestamp +1 select current_timestamp + interval ‘1’ DAY
select systimestamp - 1 select current_timestamp - interval ‘1’ DAY

字符串拼接(||)

oracle unvdb
select 1 || 1 select '1' || '1'
select 1 || c_custkey select 1 || cast(c_custkey as text)

函数参数的强类型限制

oracle中在函数调用时,参数类型进行会自动转化类型,譬如 select substr(123.12,0,2)是合法的,且返回123。unvdb是强类型, 执行select substr(123.12,0,2)会报错,需要进行显式的类型转换。

substr(arg1, arg2, arg3)

oracle unvdb
select substr(1234.1, 0, 4) select substr(‘1234.1’, 1, 4+1)
select substr(‘1234.1’, 0, ‘2’) select substr(‘1234.1’, 0, 2)

sum(arg)

oracle unvdb
select sum('2') select sum(2)

avg(arg)

oracle unvdb
select round(‘2’) select round(2)

条件判断中的强类型限制

oracle中在进行条件判断时,左右表达式的类型进行会自动转化,譬如 where c_phone = 110是合法的。unvdb是强类型, 执行where c_phone = 110会报错,需要进行显式的类型转换。

比较运算(=、>、<、>=、<=、<>)

转换原则,优先转换常量类型;当两个都为数据列时,优先转换左边的。

oracle unvdb
select * from test where t_phone = 110 select * from test where t_phone = ‘110’
select * from test where ‘1’ = t_custkey select * from test where 1 = t_custkey
select * from test where t_phone = t_custkey select * from test where cast(t_phone as int) = t_custkey

BETWEEN

转换原则,转换 var0 between var1 and var2 中的 var1, var2。

oracle unvdb
select * from test where t_custkey between ‘100’ and ‘200’; select * from test where t_custkey between 100 and 200;

IN LIST

转换原则,转换List中的变量。

oracle unvdb
select * from test where t_phone in (110,120); select * from test where t_phone in (‘110’, ‘120’);

默认参数

oracle中有部分函数存在默认参数,而在unvdb其参数是必填项。

to_char(unknown)

oracle unvdb
select to_char(t_custkey) from test; select cast(t_custkey as text) from test;

to_number(str)

oracle unvdb
select to_number(‘100’) select 100
select to_number(t_phone) from test; select cast(t_phone as numeric) from test;