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 <constant> | 压缩值为NULL和指定值的字段存储空间为0 | 无 | - |
CHARACTER SET LATIN | 指定字段存储字符集 | 无 | - |
1.2.4 约束
Teradata建表时的约束项与GBase 8a的约束项对照表如下,供迁移时参考。
Teradata | Teradata描述 | GBase 8a | GBase 8a描述 |
CONSTRAINT <constraint name> | 约束名称 | 无 | - |
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 (<expression>) | 去除字符数据中前后端的空格 |
TRIM (BOTH FROM <expression>) | 同上 |
TRIM (TRAILING FROM <expression>) | 去除后端的空格 |
TRIM (LEADING FROM <expression>) | 去除前端的空格 |
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 |