与Oracle语法上的差异
在这一章节中,我们简单比较一下,HashData 在语法层面与 Oracle 的差异。
数据类型
字符类型
Oracle
HashData
备注
char(n)
char(n)
字节为单位,定长,不足用空格填充
nchar(n)
char(n)
字符为单位,定长,不足用空格填充
varchar2(n)
varchar(n)
字节为单位,变长,有长度限制
nvarchar2(n)
varchar(n)
字符为单位,变长,有长度限制
string
text
字符为单位,变长,没有长度限制
一般情况下,对于 Oracle 的 char 和 nchar 类型,直接换成 HashData 的 char 是没有问题的;而对于变长的 varchar2 和 nvarchar2,想图省事的话,直接换成 HashData 的 TEXT 就可以。
数值类型
Oracle
HashData
备注
SMALLINT
SMALLINT
2个字节
INTEGER
INTEGER
4个字节
BIGINT
BIGINT
8个字节
BINARY_FLOAT
DOUBLE PRECISION
8个字节,15位精度
BINARY_DOUBLE
DOUBLE PRECISION
8个字节,15位精度
FLOAT
DOUBLE PRECISION
8个字节,15位精度
DOUBLE PRECISION
DOUBLE PRECISION
8个字节,15位精度
REAL
REAL
4个字节,6位精度
DECIMAL
DECIMAL
没有精度限制
NUMBER
NUMERIC
没有精度限制
Oracle 的数值类型向 HashData 的数值类型迁移过程中,只要根据 Oracle 数据的精度,在 HashData 中选择相同或者更大精度的类型,数据就能够顺利地迁移过来。但是为了转换过来后数据库的效率(特别是整数类型的时候),需要选择合适的数据类型,才能够完整、正确并且高效地完成 Oracle 数据类型向 HashData 数据类型的迁移。
时间类型
Oracle
HashData
备注
Date
Timestamp(0) without time zone
包含年,月,日,时,分和秒6个字段
Date
只包含年,月和日3个字段
Timestamp
Timestamp without time zone
包含年,月,日,时,分,秒和毫秒
Timestamp with time zone
Timestamp with time zone
带时区的时间戳
Timestamp with local time zone
Timestamp with time zone
带时区的时间戳
Interval
Interval
时间间隔
Oracle 的日期时间类型向 HashData 的数据迁移相对来说简单一些。由于 HashData 的数据类型的极值超越 Oracle,因此,数据迁移过程中,只要根据 Oracle 的数据精度,在 HashData 中选择正确的数据类型,并留意一下二者写法的不同,应该就能够完整正确地迁移过来。
大对象
Oracle
HashData
备注
BLOB
BYTEA
字节
CLOB
TEXT
字符
其他类型
Oracle
HashData
备注
RAW
BYTEA
RAWID
OID
常用函数
字符串操作函数
Oracle
HashData
备注
\
\
\
\
字符串连接符
concat
\
\
字符串连接函数
to_number
to_number
将字符串转换成数值
to_char
::TEXT
类型转换
to_date
to_timestamp
将字符串转化为时间戳
last_date
(date_trun('MONTH', mydate) + INTERVAL '1 MONTH' - INTERVAL '1 DAY')::DATE
当月的最后一天
instr
position
在一个字符串中,查找另外一个字符串出现的位置
substr
substr
截取字符串的一部分
length
length
获取字符串的长度
trim
trim
出去字符串开始和结束的指定字符
initcap
initcap
首字母大写
upper
upper
转大写
lower
lower
转小写
regexp_replace
regexp_replace
正则表达式替换
regexp_substr
substring
根据正则表达式寻找子串
regexp_instr
position(substring)
在一个字符串中查找符合正则表达式的字符串的位置
regexp_like
length(substring)
判断是否有满足条件的子串
数值函数
Oracle
HashData
备注
BITAND
&
对数值按位进行 与 运算
REMAINDER
%
取模
abs
abs
取绝对值
日期函数
Oracle
HashData
备注
SYSDATE
CURRENT_DATE
当前日期
CURRENT_TIMESTAMP
CURRENT_TIMESTAMP/NOW()
当前时间戳
ADD_MONTHS
DATE + INTERVAL
将日期往期推
EXTRACT
EXTRACT
从日期和时间戳中取出年,月,日等
其他函数
decode 是 Oracle 固有的一个函数,用于条件判断。其格式为:
decode(条件,值1,返回值1,值2,返回值2,...,值n,返回值n,缺省值)
当条件等于值 1 的时候返回返回值 1,等于值 n 的时候返回返回值 n,都不等于的时候返回缺省值。
在 HashData 中,decode 函数是用来解码的,和 encode 函数相对。对于 Oracle 的 decode 函数,可以把它转换成 case when 的 SQL 语句,得到一样的效果。另外,Oracle 也支持 case when 的语法,用法和 HashData 一样。
-- Oracle
select decode(y.studentcode, null, '0', '1') studenttype from y;
-- HashData
select case when y.studentcode is null then '0' else '1' end studenttype from y;
存储过程
最简单的存储过程
Oracle
CREATE OR REPLACE PROCEDURE procedure_name
AS
BEGIN
-- comments
NULL;
END;
HashData
CREATE OR REPLACE FUNCTION function_name() RETURNS VOID AS
$$
BEGIN
-- comments
NULL;
END;
$$ LANGUAGE PLPGSQL;
带输入输出参数的存储过程
Oracle
CREATE OR REPLACE PROCEDURE sum_n_product(x IN INTEGER, y IN INTEGER, sum OUT INTEGER, prod OUT INTEGER)
AS
BEGIN
sum := x + y;
prod := x * y;
END;
HashData
CREATE OR REPLACE FUNCTION sum_n_product(x INTEGER, y INTEGER, OUT sum INTEGER, OUT prod INTEGER) AS
$$
BEGIN
sum := x + y;
prod := x * y;
END;
$$ LANGUAGE PLPGSQL;
SELECT INTO
Oracle
CREATE OR REPLACE PROCEDURE find_record(key IN INTEGER, value OUT INTEGER)
AS
BEGIN
SELECT val INTO value FROM mytable WHERE id = key;
END;
HashData
CREATE OR REPLACE FUNCTION find_record(key INTEGER, OUT value INTEGER) AS
$$
BEGIN
SELECT val INTO value FROM mytable WHERE id = key;
END;
$$ LANGUAGE PLPGSQL;
带条件判断的存储过程
Oracle
CREATE OR REPLACE PROCEDURE fib(num IN INTEGER, result OUT INTEGER)
AS
BEGIN
IF NUM <= 0 THEN
result := 0;
ELSEIF num = 1 THEN
result := 1;
ELSE
result := fib (num - 1) + fib (num - 2);
END IF;
END;
HashData
CREATE OR REPLACE FUNCTION fib(INTEGER) RETURNS INTEGER AS
$$
DECLARE
result INTEGER := 0;
num ALIAS FOR $1;
BEGIN
IF num = 1 THEN
result := 1;
ELSEIF num > 1 THEN
result := fib(num - 1) + fib(num - 2);
END IF;
RETURN result;
END;
$$ LANGUAGE PLPGSQL;
动态执行
Oracle 和 HashData 基本是一样的:
EXECUTE 'DELETE FROM mytable WHERE id = key';
执行没有返回值的查询
Oracle 和 HashData 基本也是一样的:
UPDATE mytable SET val = val + delta WHERE id = key;
INSERT INTO mytable VALUES(key, value);
TRUNCATE TABLE mytable;
DELETE FROM mytable WHERE id = key;
LOOP循环
简单的 LOOP 循环
EXIT
LOOP
-- some computations
IF count > 0 THEN
EXIT; -- exit loop
END IF;
END LOOP;
LOOP
-- some computations
EXIT WHEN count > 0; -- same result as previous example
END LOOP;
BEGIN
-- some computations
IF stocks > 10000 THEN
EXIT; -- cause exit from the BEGIN block
END IF;
END;
CONTINUE
LOOP
-- some computations
EXIT WHEN count > 100;
CONTINUE WHEN count < 50;
-- some computations for count IN [50 ... 100] END LOOP;
WHILE
WHILE amount_owed > 0 AND gift_certificate_balance > 0 LOOP
-- some computations here
END LOOP;
WHILE NOT boolean_expression LOOP
-- some computations here
END LOOP;
FOR (integer variant)
FOR i IN 1..10 LOOP
-- some computations here
RAISE NOTICE 'i is %', i;
END LOOP;
FOR i IN REVERSE 10..1 LOOP
-- some computations here
END LOOP;
FOR i IN REVERSE 10..1 BY 2 LOOP
-- some computations here
RAISE NOTICE 'i is %', i;
END LOOP;
返回结果集的 LOOP
CREATE OR REPLACE FUNCTION cs_refresh_mviews() RETURNS INTEGER AS $$
DECLARE
mviews RECORD;
BEGIN
FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP
EXECUTE 'TRUNCATE TABLE ' || quote_ident(mviews.mv_name);
EXECUTE 'INSERT INTO ' || quote_ident(mviews.mv_name) || ' ' || mviews.mv_query;
END LOOP;
RETURN 1;
END;
$$ LANGUAGE PLPGSQL;
游标
在 HashData 中,我们一般很少使用游标,因为当我们使用 FOR LOOP 的时候,数据库后台自动就会转化成游标。不过,这里我们还是可以简单介绍一下HashData 中游标的使用。
游标的声明
DECLARE
curs1 refcursor;
curs2 CURSOR FOR SELECT * FROM tenk1;
curs3 CURSOR (key INTEGER) IS SELECT * FROM tenk1 WHERE unique1 = key;
第一个游标 curs1 是一个通用游标,没有绑定具体的查询;第二个游标 curs2 绑定了具体的查询;第三个游标 curs3 也是一个绑定游标,而且是一个带参数的游标。
打开没有绑定查询的游标
普通查询
OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
动态查询
OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);
打开已经绑定查询的游标
OPEN curs2;
OPEN curs3(42);
使用游标
FETCH curs1 INTO rowvar;
FETCH curs2 INTO foo, bar, baz;
关闭游标
CLOSE curs1;