Teradata到GBase 8a迁移总结,在无文档参考的情况下
Teradata到GBase 8a迁移总结
目录
1 DDL语法相关
1.1 字段类型
1.2 建表语句
1.2.1 表类型
1.2.2 表选项
1.2.3 列选项
1.2.4 约束
1.2.5 分布键
1.2.6 导出表(Derived Table)
1.3 复制表结构与数据
2 DML语法相关
2.1 简写
2.2 关联update
3 函数的使用
3.1 同名且用法相同的函数
3.1.1 ORDER BY
3.1.2 CASE WHEN
3.1.3 COALESCE函数
3.1.4 TRIM函数
3.1.5 EXTRACT函数
3.1.6 ADD_MONTHS函数
3.1.7 ROW_NUMBER开窗函数
3.1.8 ABS函数
3.1.9 EXP函数
3.1.10 LN函数
3.1.11 SQRT函数
3.1.12 SUBSTRING函数
3.1.13 SUBSTR函数
3.2 同名用法不同的函数
3.2.1 CAST对各种类型的转换
3.2.2 RANK函数
3.3 不同名函数的等价改法
3.3.1 求幂运算
3.3.2 TD中的LOG函数
3.3.3 TD中ZEROIFNULL函数
3.3.4 TD中NULLIFZERO函数
3.3.5 TD中的DATE和TIME函数
3.3.6 TD中的INDEX函数
3.3.7 TD中FORMAT短语
4 空串处理
4.1 数值、时间类型字段插入空串
4.1.1 int类型插空串
4.1.2 decimal类型插空串
4.1.3 time类型插空串
4.1.4 timestamp 类型插空串
4.1.5 date类型插空串
4.2 字符类型空串、空格的区别
5 不同类型字段的数据交换和关联
5.1 int和date字段的交互和关联
5.2 int/decimal和varchar字段的关联
6 超范围数据的处理
6.1 decimal类型插入超范围数据
6.2 字符类型插入超范围数据
7 SQL语法上的使用差异
7.1 字符型的列等于数值时的强转
7.2 别名依赖
7.3 TD中sql语句以’;'开始的含义
7.4 TD中的WITH RECURSIVE…递归语法
7.5 TD中的QUALIFY语句
8 开窗函数
9 UDF
1 DDL语法相关
本章节主要描述Teradata建表涉及到的相关内容与GBase 8a的差异;Teradata建表语句中包含较多的表选项和列选项,且支持通用的约束,而GBase 8a在这方面要相对简约些。在无文档参考的情况下,一般都是将GBase 8a不支持的全部去掉即可。
1.1 字段类型
Teradata中字段类型与GBase 8a的字段类型对照表如下,供迁移时参考。
数据类型
Teradata
GBase 8a
数值型
DECIMAL(n,m)/DEC(n,m)
DECIMAL(n,m)
NUMERIC(n,m)
NUMERIC(n,m)
BYTEINT范围(-128~127)
TINYINT范围(-127~127)
SMALLINT范围(-32768~32767)
SMALLINT范围(-32767~32767)
INTEGER/INT范围(-2147483648~2147483647)
INTEGER/INT范围(-2147483647~2147483647)
BIGINT范围(-9233372036854775808~9233372036854775807)
BIGINT范围(-9223372036854
775806~9223372036854775806)
REAL
REAL
FLOAT
FLOAT
DOUBLE PRECISION
DOUBLE/DOUBLE PRECISION
字符型
CHAR(n)/CHARACTER(n) 范围(1~64000)
CHAR(n) 范围(1~255)
VARCHAR(n)/CHAR VARYING(n) 范围(1~64000)
VARCHAR(n) 范围(1~10922)
LONG VARCHAR
VARCHAR(10922)/LONGTEXT
GRAPHIC(n) 范围(1~64000)
CHAR(n) 范围(1~255)
VARGRAPHIC(n) 范围(1~64000)
VARCHAR(n) 范围(1~10922)
LONG VARGRAPHIC
VARCHAR(10922)/LONGTEXT
CLOB
VARCHAR(10922)/LONGTEXT
二进制
BYTE(n)
BLOB/LONG BLOB
VARBYTE(n)
BLOB/LONG BLOB
BLOB
BLOB/LONG BLOB
日期时间型
DATE
DATE
TIME
TIME
TIMESTAMP
DATETIME
1.2 建表语句
1.2.1 表类型
Teradata中的表类型与GBase 8a的表类型对照表如下,供迁移时参考。
Teradata
Teradata描述
GBase 8a
GBase 8a描述
CREATE SET TABLE
普通表,不允许重复记录
CREATE TABLE
普通表,允许重复记录
CREATE MULTISET TABLE
普通表,允许重复记录
CREATE TABLE
普通表,允许重复记录
CREATE GLOBAL TEMPORARY TABLE
全局临时表,特点:
①可以被多个用户共享;
②每个用户会话只能看到自己的数据;
③会话(session)结束时,表的数据被丢掉;
④在数据字典中创建并保持表的定义。
CREATE TABLE
普通表,允许重复记录
CREATE VOLATILE TABLE
可变临时表,特点:
①会话级的表,存在于整个会话期间,会话结束表自动删除;
②不使用数据字典;
③一个会话中,最多有64个可变临时表;
④每个可变临时表必须有唯一的名称。
CREATE TEMPORARY TABLE
临时表,特点:
①会话级的表,存在于整个会话期间,会话结束表自动删除;
1.2.2 表选项
Teradata的表选项是GBase 8a所不支持的,迁移时直接去掉即可;对照表如下,供迁移时参考。
Teradata
Teradata描述
GBase 8a
GBase 8a描述
FALLBACK/NO FALLBACK
是否使用FALLBACK保护机制
无
JOURNAL/NO JOURNAL
有无流水日志
无
BEFORE JOURNAL /NO BEFORE JOURNAL
有无前项流水日志,数据变化前
无
AFTER JOURNAL/NO AFTER JOURNAL
有无后项流水日志,数据变化后
无
CHECKSUM = DEFAULT
CHECKSUM 是用来校验数据是否损坏的。DEFAULT是缺省项,可以再DBS程序中设置。不过,一般情况下DEFAULT为NONE选项,NONE选项不进行CHECKSUM计算,所以对性能没有任何印象
无
FREESPACE = 10 PERCENT
FREESPACE用来定义在每个磁盘柱面上保留的空间(0-75%)
无
DATABLOCKSIZE = 16384 BYTES
DATABLOCKSIZE用来指定数据块大小,最小的数据块为6144字节,最大的数据块是32256字节
无
DEFAULT MERGEBLOCKRATIO
默认合并块比
无
1.2.3 列选项
Teradata建表时的列选项与GBase 8a的列选项对照表如下,供迁移时参考。
Teradata
Teradata描述
GBase 8a
GBase 8a描述
DEFAULT
当字段无数据时用默认值来替代NULL
DEFAULT
当字段无数据时用默认值来替代NULL
WITH DEFAULT
用字段的系统默认值替换NULL
无
FORMAT
缺省的显示格式
无
TITLE
缺省的列标题
COMMENT
缺省的列标题
NOT NULL
不允许空值
NOT NULL
不允许空值
CASESPECIFIC
字母大小写敏感
无
UPPERCASE
字母大小写不敏感,内部用大写字母存储
无
COMPRESS
压缩值为NULL的字段存储空间为0
无
COMPRESS NULL
压缩值为NULL的字段存储空间为0
无
COMPRESS
压缩值为NULL和指定值的字段存储空间为0
无
CHARACTER SET LATIN
指定字段存储字符集
无
1.2.4 约束
Teradata建表时的约束项与GBase 8a的约束项对照表如下,供迁移时参考。
Teradata
Teradata描述
GBase 8a
GBase 8a描述
CONSTRAINT
约束名称
无
PRIMARY KEY
主键,非空,无重复值
PRIMARY KEY
主键,只兼容语法,无真实约束
UNIQUE
唯一
无
CHECK <条件>
指定合法值的范围
无
REFERENCES
外键
无
1.2.5 分布键
Teradata影响数据分布的为主索引,与GBase 8a在语法和约束存在一定的差异性,具体差异点如下:
语法:
TD:
UNIQUE PRIMARY INDEX <index_name> (col1,col2) #唯一
PRIMARY INDEX <index_name> (col1,col2) #非唯一
8a:
DISTRIBUTED BY (‘col1’,’col2’) #GBase字段名需要用引号括起来
差异
Teradata
GBase 8a
唯一性约束
支持
不支持
数据可发生变化
支持
不支持
指定时间类型作为分布键
支持
不支持
指定分布键名称
支持
不支持
1.2.6 导出表(Derived Table)
Teradata导出表特点如下:
1、对查询是本地的 - 存在于整个查询期间,查询结束后,表被丢掉;
2、并入SQL查询的语法;
3、查询完成后,Spool缓冲区的记录被丢掉;
4、不使用数据字典。
GBase 8a中没有导出表的概念,在sql中直接嵌套查询使用即可。
例:
TD中的导出表见如下标红部分:
SELECT last_name,
salary_amount,
department_number,
avgsal
FROM (SELECT AVG(salary_amount),
department_number
FROM employee
GROUP BY department_number) my_temp(avgsal, deptno),
employee ee
WHERE salary_amount > avgsal
AND department_number = deptno
ORDER BY 2 DESC;
8a中使用如下方式即可:
SELECT last_name,
salary_amount,
department_number,
avgsal
FROM (SELECT AVG(salary_amount) as avgsal,
department_number as deptno
FROM employee
GROUP BY department_number) my_temp,
employee ee
WHERE salary_amount > avgsal
AND department_number = deptno
ORDER BY 2 DESC;
1.3 复制表结构与数据
Teradata中建相同表结构的语法为:create multiset/set table tb1 as tb2 with no data/with data;
GBase 8a中对应写法为create table tb1 like tb2;/create table tb1 as select * from tb2;
注意:
1)在TD中建表时有关键字multiset和set,这两个关键字有不同含义,set表示该表不允许有重复记录,数据入表时会自动去重,而multiset是允许有重复记录的表。在迁移表结构带set关键字的表时,8a中只能通过sql来将去重后的数据插入表中,或者允许插入重复数据但是在使用该表时去重;
2)在8a中,create table … like…不能连带数据且不能指定字符集,create table … as …,如果连带分布键时需要指定分布键。
2 DML语法相关
2.1 简写
在Teradata中可使用SEL、INS、DEL来代替SELECT、INSERT、DELETE关键字,GBase 8a 不支持对上述关键字的简写,这个在迁移时可以进行批量替换。
2.2 关联update
Teradata和GBase 8a在关联update时,存在语法上的差异,主要体现在:①GBase 8a需在set字段前加上表的别名,Teradata不需要;② Teradata要比GBase 8a多一个from关键字。
例:
TD:update t1 from t2 set a=t2.a where a is not null;
8a:update t1,t2 set t1.a=t2.a where t1.a is not null;
3 函数的使用
本章节主要列举了Teradata中函数的使用与GBase 8a的异同。
3.1 同名且用法相同的函数
3.1.1 ORDER BY
Teradata和GBase 8a默认都是升序asc,区别在于空值的位置。
1)desc: TD空排在最后面,8a空排在最前面(迁移时要加nulls last)
2)asc: TD空排在最前面,8a空排在最后面(迁移时要加nulls first)
3.1.2 CASE WHEN
case when 的作用基本相同,但是在对字符类型做判断的时,TD和8a还是存在差异的:在TD中根据建表时字段是否指定敏感有关,如果指定了敏感,那么case when大小写是敏感的,反之不敏感;而在8a大小写是不敏感的。这里需要格外注意,会影响查询结果。
3.1.3 COALESCE函数
COALESCE函数在TD中的含义和用法与8a相同,其含义为返回值为列表当中的第一个非NULL 值,在全部为NULL 值的情况下返回值为NULL。
3.1.4 TRIM函数
TRIM函数用于去除字符数据中前头或后端的空格,TD和8a用法基本一致,TRIM函数的使用方法如下:
语法
意义
TRIM ()
去除字符数据中前后端的空格
TRIM (BOTH FROM )
同上
TRIM (TRAILING FROM )
去除后端的空格
TRIM (LEADING FROM )
去除前端的空格
3.1.5 EXTRACT函数
EXTRACT函数用于选取日期和时间中任意字段或任意间隔的值,TD中该函数用法和8a中用法相同,常用的一些用法如下表格:
用法
含义
EXTRACT(YEAR FROM DATE)
返回年份
EXTRACT(MONTH FROM DATE)
返回月份
EXTRACT(DAY FROM DATE)
返回日数
SELECT EXTRACT(HOUR FROM TIME)
返回小时数
SELECT EXTRACT(SECOND FROM TIME)
返回分钟数
3.1.6 ADD_MONTHS函数
ADD_MONTHS(date, number)函数是在一个日期上加上指定的月份数,在TD中的用法和8a中的用法相同。
3.1.7 ROW_NUMBER开窗函数
TD中row_number() over(partition by…order by…)的分析函数在8a中同样支持,用法和含义相同,但是需要注意是空值的排序问题:
1)TD和8a默认都是升序asc;
2)desc: TD空排在最后面,8a空排在最前面,迁移时要加desc nulls last;
3)asc: TD空排在最前面,8a空排在最后面,迁移时要加asc nulls first。
3.1.8 ABS函数
TD和8a的ABS函数用法相同,均为求数值的绝对值。
如:abs(-2)=abs(2)=2。
3.1.9 EXP函数
TD和8a的EXP函数用法相同,均为求e的幂数。
如:exp(2)=e2=7.39
3.1.10 LN函数
TD和8a中的LN函数用法相同,均为求自然对数。
如:ln(2)=0.69
3.1.11 SQRT函数
TD和8a的STRQ函数用法相同,均为求平方根。
如sqrt(9)=3。
3.1.12 SUBSTRING函数
TD中的使用格式为SUBSTRING(col1 FROM 1 FOR 1)。8a中对应的用法为SUBSTRING(col1 FROM 1 FOR 1)或SUBSTRING(col1,1,1)。
需要注意的是,TD和8a在某些场景下稍有不同,如下:
1)pos为负值,td是从-1位开始取数,8a是从倒数第一位开始取数
select substring(‘asdas’,-1,1);
td结果集:‘’
8a结果集:‘s’
2)pos为0,td是从0位开始取数,8a是从第一位开始取数
select substring(‘asdas’,0,1);
td结果集:‘’
8a结果集:‘a’
3)len缺省,pos前不带from,td不支持,8a支持
select substring(‘asdas’,-1);
td结果集:报错
8a结果集:‘s’
4)len缺省,pos前带from,td是从-1位开始取数,8a是从倒数第一位开始取数
select substring(‘asdas’ from -1);
td结果集:‘asdas’
8a结果集:‘s’
3.1.13 SUBSTR函数
substr函数在TD和8a中用法相同,均是对字符串进行截取,如substr(‘abc’,2,2)=‘bc’。
需要注意的是,TD和8a在某些场景下稍有不同,如下:
1)pos为负值,td是从-1位开始取数,8a是从倒数第一位开始取数
select substr(‘asdas’,-1,1);
td结果集:‘’
8a结果集:‘s’
2)pos为0,td是从0位开始取数,8a是从第一位开始取数
select substr(‘asdas’,0,1);
td结果集:‘’
8a结果集:‘a’
3)len缺省,pos前不带from,td是从-1位开始取数,,8a支持
select substr(‘asdas’,-1);
td结果集:‘asdas’
8a结果集:‘s’
4)len缺省,pos前带from,td不支持from,8a是从倒数第一位开始取数
select substr(‘asdas’ from -1);
td结果集:报错
8a结果集:‘s’
3.2 同名用法不同的函数
3.2.1 CAST对各种类型的转换
GBase 8a和Teradata都可以使用cast函数对时间、数值、符等类型进字行转换,但是在用法上略有不同,具体使用对照关系如下表:
类型
Teradata用法
GBase 8a用法
时间
CAST(col1 AS TIMESTAMP(0))
CAST(col1 AS datetime )
数值
CAST(col2 AS INTEGER)
CAST(col2 AS INTEGER)
字符
CAST(col2 AS VARCHAR(20) )
CAST(col2 AS VARCHAR(20) )
注意:Teradata中将数据转为integer后会在前面补全空格,补到11位,插入到char中会从前往后截取后再插入,所以会插入空格。GBase 8a插入的只有该值。
例如:Teradata中cast(‘2’ as integer)=’ 2’,会在前面补空格直到11位,当将此值插入到char(5)的列中时,进去的是空格而不是’2’。在GBase 8a中则是2。
3.2.2 RANK函数
Teradata中的rank(col1)函数,在GBase 8a中需要改写成rank() over(order by col1 desc nulls last),需要注意的是Teradata中的这种简写排序默认是降序,而GBase 8a是升序,改写时需要加上desc nulls last关键字。
另外需要注意,Teradata中的rank函数可带qualify字句限制排队输出的最终结果,其用法类似having,如:
SELECT storeid, prodid, sales, rank(sales)
FROM salestbl
GROUP BY storeid
QUALIFY rank(sales) <= 3;
在上面的sql中,GROUP BY子句不是做聚合,它实际上是改变查询的范围,也引起排序,排序是在组内。
GBase 8a中不直接支持这种写法,可进行如下改写:
SELECT *
FROM (SELECT storeid,
prodid,
sales,
rank() over(partition by storeid order by sales desc nulls last) ran_row
FROM salestbl )t
WHERE ran_row <= 3;
3.2.3 CHAR函数
TD和8a的CHAR函数用法完全不同,TD是求长度,对应的是8a的length函数。
3.2.4 CHARACTER函数
TD和8a的CHARACTER函数用法完全不同,TD是求长度,对应的是8a的length函数。
3.3 不同名函数的等价改法
3.3.1 求幂运算
TD中幂的求法为2**3=8
8a中对应改法为pow(2,3)=8
3.3.2 TD中的LOG函数
TD中log函数返回某数值以10为底的对数,如log(10)=1。需要注意的是,8a中也有log函数,但是默认不是以10为底,而是等价于ln函数,log(2)=ln(2)=0.69。8a中需要使用log10对应TD中log函数。
例:
TD:log(10)
8a:log10(10)
3.3.3 TD中ZEROIFNULL函数
TD中的zeroifnull函数含义是在对数据做处理时,将空值作零处理,8a中使用ifnull函数来进行替换。如TD中zeroifnull(col1)等价于8a中ifnull(col1,0)。
3.3.4 TD中NULLIFZERO函数
TD中:nullifzero函数是将零值作空值处理,使用方法:zeroifnull(col1)。
8a中:可使用nullif(col1,0)函数进行处理,含义为当col1的值为0时返回null。
3.3.5 TD中的DATE和TIME函数
TD中DATE返回当前日期(yyyy/mm/dd),TIME返回当前时间(hh24:mi:ss),如select date,time;返回的是两个字段分别为当前日期和时间,8a中对应的写法分别为current_date和current_time。
3.3.6 TD中的INDEX函数
TD中index函数用来在一个字符串中定位一个子串的开始位置;在8a中可以替代的函数为instr函数。需要注意的是大小写敏感问题:TD是根据建表时字段是否指定敏感有关,8a大小写不敏感。
例:
insert into t3 values(‘AaBbCc’);select instr(a,‘c’) from t3;
td:根据建表时字段是否指定敏感有关,如果指定了敏感,返回6,没有指定返回5
8a:返回5
3.3.7 TD中FORMAT短语
TD中的FORMAT短语用于数据在输出时的格式化处理,但它并不影响数据的内部存储格式。FORMAT短语中常用的格式化字符主要如下:
1) $ 美元标识符
2) 9 数字位
3) Z 将数字中的前缀零去除
4) , 在指定位置插入逗号
5) . 指定小数点位置
6) - 在指定位置插入连字号
7) / 在指定位置插入斜线
8) % 在指定位置插入百分号
9) X 字符数据,每个X代表一个字符
10)G 图形数据.一个G代表一个逻辑字符(双字节)
11)B 在指定位置插入空格
FORMAT常用的日期显示格式列举如下,其中的B表示空格,如下:
1)YYYY/MM/DD
2)YYYY-MM-DD
3)YYYY.DDD
4)DBMMMBYYYY
5)MMBDD,BYYYY
6)YYYYBMMMBDD
7)YY/MM/DD
8)D-MM-YY
9)YBDDD
10)MM’
FORMAT比较常见的用法是对数字的补0和去0操作以及对日期的格式化,例如:
TD中01111(FORMAT’999999’)等价于01111(FORMAT’9(6)'),意思为将该值补0补齐六位,对应GBase的写法为lpad(01111,6,0)。
对一个日期的格式化TD中使用FORMAT ‘YYYY/MM/DD’,8a中使用TO_CHAR(col,‘yyyy/mm/dd’)。
FORMAT的用法在TD中比较广泛,迁移到8a时需要根据具体的不同用法进行对应修改,8a中的to_char函数基本可应对format短语的迁移,有时需要使用lpad来实现。
8a中to_char(number,[FORMAT])函数对数字格式化参数及含义如下表所示:
格式化参数
含义
,
一般作为分组符号使用,将number参数格式化为数位格式字符串输出,例如千位一分组,也可以按百位、十位一分组。通常与0、9、‚.‛配合使用。
示例:99,999。
.
将number参数格式化为小数形式的字符串输出。只能出现一次。通常与0、9、‚,‛配合使用。
示例:999.99。
$
转换为美元货币含义的字符串,只能出现在最前或最后。
示例:$999。
0
占位符,格式化number,如果参数number的位数少于格式化的位数,则显示0补足位。注意:0的优先级高于9。
示例:000。
9
占位符,格式化number,一旦参数number的位数,少于格式化的位数,则用空格补足位。
示例:999。
B、b
如果number的值为0,则替换为空格,可以出现在任意位置。
示例:B9.99
EEEE、eeee
按照科学计数法输出。
示例:9.99EEEE。
FM、fm
删除数字开头和结尾处的空格。
示例:FM909.9。
TME
按照科学计数法返回number。
X、x
转换为16进制。每个X代表16进制的一位。
例如:XX,代表两位16进制数。
如果number,转换成16进制数大于X的个数,则输出‚#‛。
注意:数值必须是大于等于0的整数。前面只能和0或者FM组合使用。
8a中to_char函数也可对日期进行格式化TO_CHAR(datetime,[FORMAT]),可对应TD中format对日期的格式化。具体如下表:
格式化参数
含义
, . ; :
除了左面标准的几个,还允许用文字作为分隔符号。例如年月日日期分隔符。用于格式化输出日期。
AD
即拉丁文 Anno Domini 的简写,表示公元,会根据 nls 的不同转换为公元或者AD 等。
如果是公元后的日期,显示 AD。
如果是公元前的日期,显示 BC。
AM
上午的简写,同 PM(下午),中文环境输出为上午。
如果是上午,返回 AM。
如果是下午,返回 PM。
BC
即拉丁文 Before Christ 的简写,表示公元前,会根据 nls 的不同转换为公元或者 BC 等。
如果是公元后的日期,显示 AD。
如果是公元前的日期,显示 BC。
CC
返回世纪,以阿拉伯数字表示。
D
一周之中的第几天,返回的是序号(1~7)。
DAY
返回日期中的 DAY 部分。返回的是英文全拼形式,首字母大写。
DD
同 DAY,但是返回的是数字形式(01~31)。
DDD
日期中的日是一年当中的第几天,返回的是序号 001~366。
DY
同 DAY,但是返回的是英文形式,返回前三个字母。首字母大写。
FF[n]
就是毫秒,如果不加数字就是用默认的精度,默认 6 位精度。1 ≤ n ≤ 9。只能用于 timestamp 类型的。
FM
删除日期开头和结尾处的空格。
FX
固定模式全局选项。
HH[12 | 24]
表示小时,默认 12 小时制。
HH12,12 小时制。返回(01~12)。
HH24,24 小时制。返回(00~23)。
IW
ISO 标准的一年中的第几周(1~52,或者 1~53)。
MI
返回分钟数(00~59)。
MM
返回月份,返回阿拉伯数字。
MON
返回月份,返回的是英文简写,三个英文字母,首字母大写。
MONTH
返回月份,返回的是英文全拼。首字母大写。
PM
下午的简写,中文环境输出为下午。
Q
返回季度,取值为 1~4。
RM
用罗马数字表示的月份。罗马数字全部大写。
RR或RRRR
返回 2 位或者 4 位年。
SCC
返回数字形式表示的世纪。
SS
返回秒(0~59)。
SSSSS
一天从午夜开始的累积秒数(0~86399)。
TS
返回带有 AM 或者 PM 的时分秒形式的时间。
W
一个月中的第几周,其算法局限在 datetime 参数所属于的月份之内而已。
WW
同 IW。
4 空串处理
本章主要讲述TD和8a在处理空串时的差别。
4.1 数值、时间类型字段插入空串
TD数据库中会将空串转化为系统的默认值,而8a默认情况下,对数据控制比较严格,大部分情况下会将空串认作为非法数据,SQL会报错;8a可通过开启非严格模式避免一些差异,但是不能完全避免( set sql_mode=PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,NO_AUTO_VALUE_ON_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,PAD_CHAR_TO_FULL_LENGTH)。
4.1.1 int类型插空串
以下为int类型字段插入空串的几种场景,TD和8a互有差异:
建表语句:create table t1(a int);
1)insert into t1 values(‘’);
td:int插入空串,转化为0做插入
8a:在严格模式下,认为空串对于int是不合规的,sql报错;在非严格模式下,此sql将空串转化为0做插入
2)insert into t1 select ‘’ from t1;
td:int插入空串,转化为0做插入
8a:在严格模式下,认为空串对于int是不合规的,sql报错;在非严格模式下,此sql将空串转化为-2147483647做插入。(建议:如果在POC测试中要求核对数据,迁移时最好将int改成decimal default 0)
3)select a from t1 where a <> ‘’;
td:结果集非空非零
8a:在严格模式和非严格下,都认为空串对于int是不合规的,但结果集永为空
4.1.2 decimal类型插空串
以下为decimal类型字段插入空串的几种场景,TD和8a互有差异:
建表语句:create table t1(a decimal);
1)insert into t1 values(‘’);
td:decimal插入空串,转化为0做插入
8a:在严格模式下,认为空串对于decimal是不合规的,sql报错;在非严格模式下,空串转化为0做插入
2)insert into t1 select ‘’ from t1;
td:decimal插入空串,转化为0做插入
8a:在严格模式下,认为空串对于decimal是不合规的,sql报错;在非严格模式下,空串转化为0做插入
3)select a from t1 where a <> ‘’;
td:结果集非空非零
8a:在严格模式和非严格下,都认为空串对于decimal是不合规的,但结果集永为空
4.1.3 time类型插空串
以下为time类型字段插入空串的几种场景,TD和8a互有差异:
建表语句:create table t1(a time);
1)insert into t1 values(‘’);
td:time插入空串,转化为00:00:00做插入
8a:在严格模式下,认为空串对于time是不合规的,sql报错;在非严格模式下,空串转化为00:00:00做插入
2)insert into t1 select ‘’ from t1;
td:time插入空串,转化为00:00:00做插入
8a:在严格模式下,认为空串对于time是不合规的,sql报错;在非严格模式下,空串转化为00:00:00做插入
3)select a from t1 where a <> ‘’;
td:非空非’00:00:00’
8a:在严格模式和非严格下,都认为空串对于time是不合规的,但结果集永为空
4.1.4 timestamp 类型插空串
以下为timestamp类型字段插入空串的几种场景,TD和8a互有差异:
建表语句:create table t1(a timestamp);
1)insert into t1 values(‘’);
td:timestamp插入空串,认为空串对于timestamp是不合规的,sql报错;
8a: 在严格模式下,认为空串对于datetime是不合规的,sql报错;在非严格模式下,空串转化为0000-00-00 00:00:00做插入
2)insert into t1 select ‘’ from t1;
td:timestamp插入空串,认为空串对于timestamp是不合规的,sql报错;
8a: 在严格模式下,认为空串对于datetime是不合规的,sql报错;在非严格模式下,空串转化为0000-00-00 00:00:00做插入
3)select a from t1 where a <> ‘’;
td:认为空串对于timestamp是不合规的,sql报错
8a:在严格模式和非严格下,结果集都非空非’0000-00-00 00:00:00’
4)insert into t9 values(‘0000-00-00 00:00:00’);
td:认为数据不合规的,sql报错
8a:在严格模式下,认为数据不合规的,sql报错;在非严格模式下,可以做插入
4.1.5 date类型插空串
以下为date类型字段插入空串的几种场景,,TD和8a互有差异:
建表语句:create table t1(a date);
1)insert into t1 values(‘’);
td:认为空串对于date是不合规的,sql报错
8a:在严格模式下,认为空串对于date是不合规的,sql报错;在非严格模式下,空串转化为0000-00-00做插入
2)insert into t1 select ‘’ from t1;
td:认为空串对于date是不合规的,sql报错
8a:在严格模式下,认为空串对于date是不合规的,sql报错;在非严格模式下,空串转化为0000-00-00做插入
3)select a from t1 where a <> ‘’;
td:认为空串对于date是不合规的,sql报错
8a:在严格模式和非严格下,非空非’0000-00-00’
4)insert into t9 values(‘0000-00-00’);
td:认为数据不合规的,sql报错
8a:在严格模式下,认为数据不合规的,sql报错;在非严格模式下,可以做插入
4.2 字符类型空串、空格的区别
在TD中空串、一个空格、多个空格都是等价的,在8a中三者是不等价的。当数据中有字符和空格混合的情况下,TD中字段数据右边的空串、一个空格、多个空格都是等价的,左边是非等价的。
例:
1)等值:select a,chars(b) from t4 where b=‘’;
td结果集:b = 空串、单个空格、多个空格
8a结果集:b = 空串
2)不等值:select a,chars(b) from t4 where b<>‘’;
td结果集:b <> 空串、单个空格、多个空格、NULL
8a结果集:b <> 空串、NULL
3)关联(右空格):insert into t4 values(1,‘A’); insert into t5 values(2,'A ');select a.,b. from t4 a inner join t5 b on b.b=a.b;
td结果集:可关联
8a结果集:不可关联
4)关联(左空格):insert into t4 values(1,‘A’); insert into t5 values(2,’ A ');select a.,b. from t4 a inner join t5 b on b.b=a.b;
td结果集:不可关联
8a结果集:不可关联
5 不同类型字段的数据交换和关联
5.1 int和date字段的交互和关联
在TD中date类型数据实际上就是数值型,二者之间是可以直接转化和关联的;而在8a中只有在数据交互的时候可以转化,关联时没有隐式转换,且TD的转化需要作-19000000的运算,8a不需要;详情参考以下三个场景:
例:
建表语句:create table t1(a date); create table t2(a int);
1)数值插入date: insert into t1 values(19921010);
td:t1存入3892/10/10,如果插入1992/10/10,insert语句应为insert into t1 values(19921010-19000000);
8a:在严格模式和非严格下,t1都存入1992-10-10
2)int插入date: insert into t1 select a from t2 where a=19921010;
td: t1存入3892/10/10,如果插入1992/10/10,insert语句应为insert into t1 select a-19000000 from t2 where a=19921010
8a:在严格模式和非严格下,t1都存入1992-10-10
3)int和date关联:select a.,b. from t1 a left join t2 b on a.a=b.a;
td:可以关联
8a:在严格模式和非严格下,都认为数据类型不匹配,sql报错;
5.2 int/decimal和varchar字段的关联
TD和8a都能实现数值型和字符型的关联,主要区别在于1和001,以下从三个例子来讲述TD和8a的区别。
例:
建表语句:create table t1(a int); create table t2(a varchar(23));
插入数据:insert into t1 values(1);insert into t2 values(‘1’);insert into t2 values(‘001’);
1)select a.,b. from t1 a inner join t2 b on a.a=b.a;
td:可以关联,1和001都被查出
8a:可以关联,1和001都被查出
2)select * from t2 where a=1;
td:1和001都被查出
8a:1被查出
3)select * from t2 where a=‘1’;
td:1被查出
8a:1被查出
6 超范围数据的处理
6.1 decimal类型插入超范围数据
在TD中对于精度舍入的规则为四舍六入五成双(奇进偶不进),在8a中为四舍五入。
例:
1)create table t1(a decimal(5,3));insert into t1 values(23.3365);
td结果集:23.336
8a结果集:23.337
2)create table t1(a decimal(5,3));insert into t1 values(23.3375);
td结果集:23.338
8a结果集:23.338
6.2 字符类型插入超范围数据
在TD中,字符串类型插入超范围数据,直接作截断处理,而8a中只在非严格模式下,才会做截断处理。
例:
create table t1(a varchar(3));insert into t1 values(‘dasadasd’);
td结果集:插入’das’
8a结果集:严格模式:超长报错;非严格模式:插入’das’
7 SQL语法上的使用差异
7.1 字符型的列等于数值时的强转
TD中字符型的列在sql条件中可以直接等于一个数值,如某条记录的col1的值为’001234’,而sql中写的条件为col1=1234是成立的可以找到该条记录。
8a中这样是找不到该条记录的,需要写成to_number(col1)=1234方可。
7.2 别名依赖
TD中支持投影列中表达式的别名作为列名参与后续运算,如别名可以直接在投影列中、在where条件中、在关联条件中等使用。目前,8a也已经兼容这项功能,需要保证参数:_t_gcluster_support_alias_dependent=1,默认是开启的;但是olap函数中,别名依赖是不生效的,如下:
SELECT substring(storeid,1,6) as sroid ,sales
FROM salestbl
QUALIFY row_number() over(partition by sroid order by sales desc) =1 ;
这种在8a中是不支持的,需要手动进行修改为:
SELECT substring(storeid,1,6) as sroid ,sales
FROM salestbl
QUALIFY row_number() over(partition by substring(storeid,1,6) order by sales desc nulls last) =1 ;
7.3 TD中sql语句以’;‘开始的含义
在TD中一个文本中多条sql语句时,如果有sql是以’;'开始,则该sql和其前面的sql是同时执行的,例如:
select … from …
;select … from …
;
则在执行这个文本里的内容时这两个sql是并行同时执行的。
7.4 TD中的WITH RECURSIVE…递归语法
TD中可以根据用户自己的需要定义任意的递归循环语法,例如:
WITH RECURSIVE
table1…AS…
(
select…from… – sql1
union all
select … From table1 … – sql2
)
select * from table1;
该类型的sql含义为根据sql1为基准产生的临时数据放入table1中,为递归的第一次循环,再根据sql2从table1中的数据来进行递归,每次递归的数据都是根据前一次递归产生的数据,直到最终循环的内容没有数据为止。
这种递归语法8a中不能直接支持,需要通过存储过程来修改替代,替代的大概步骤如下:
create table table1 … as select … from …; – 第一步生成临时表table1,同TD中的sql1
set row_count=1;
while row_count>0 do – 开始循环
set i=i+1;
insert into PEEL_MAP_TABLE
SELECT …
FROM table1
WHERE ... and row_num=i-1; -- 每次递归的数据都是根据前一次递归产生的数据
set row_count=row_count();
end while;
7.5 TD中的QUALIFY语句
在TD中,有一种特有的语法qualify,用于olap函数的刷选,它类似于where、having,所处的位置为:where>having>qualify。目前,8a也已经支持qualify语句,但须要注意以下情况。
例:
SELECT storeid, prodid, sales, rank(sales)
FROM salestbl
GROUP BY storeid
QUALIFY rank(sales) <= 3;
在上面的sql中,GROUP BY子句不是做聚合,它实际上是改变查询的范围,也引起排序,排序是在组内。8a中不直接支持这种写法,可进行如下改写:
SELECT storeid,
prodid,
sales,
rank() over(partition by storeid order by sales desc nulls last)
FROM salestbl
QUALIFY rank() over(partition by storeid order by sales desc nulls last) <= 3;
8 开窗函数
TD中有部分开窗函数功能,是8a所不具备的,只能通过创建存储过程或者建临时表等进行实现的,是个较为复杂的改写过程。以下为改写方案,具体迁移案例见附件。
函数名
含义
改写方案
CSUM
开窗累计和
存储过程改写 或者 自关联不等值join改写
MAVG
开窗移动平均值
LAG+case when改写 或者 自关联不等值join改写
MDIFF
开窗移动差值
LAG函数改写
MLINREG
开窗线性回归预测值
暂无改写方案
MSUM
开窗移动求和
同MAVG
QUANTILE
开窗分位数
CEIL(rn / @countn * 100)方式改写
QUALIFY
相当于OLAP中的having子句
嵌套子查询+where条件改写
PERCEDING/FOLLOWING
开窗函数关键字
GBase 8a不支持只能用LEAD和LAG尝试进行改写
9 UDF
TD中的部分8a不支持或不同名的函数,可通过UDF的形式实现迁移,目前已经完成的UDF如下表:详细请见附件。
TD
8a
months_between
无对应函数,使用UDF
nullifzero
对应函数为nullif,使用UDF可减少迁移量
zeroifnull
对应函数为ifnull,使用UDF可减少迁移量
random
无对应函数,使用UDF
nvl2
无对应函数,使用UDF
width_bucket
无对应函数,使用UDF
substring
当pos为负值时,使用UDF,否则结果集会有问题,除此之外可使用8a自身的substring