人大金仓数据库兼容mysql中truncate函数

128 阅读3分钟

关键字:KingbaseES、人大金仓、函数、truncate

函数调研

    1. mysql 8 truncate函数调研

语法:TRUNCATE(X, D)

其中,参数X是数值number类型,D是int整数类型,保留小数位数,函数返回值为number类型。如果D为0,则结果没有小数点或小数部分。D可以是负的,使值X的小数点左边的D位数变为0。

    1. kes trunc函数调研

有2种调用形式:

  • trunc(dp或numeric)
  • trunc(v , s)

第一种调用方式,传参可以是dp number或者numeric类型,若传入浮点数返回类型为numeric,若传入整数返回类型为double precision。

第二种调用方法中传参可以为

  • TRUNC(date),TRUNC(date [, fmt ]),传参为date,返回的值始终是数据类型 DATE,如果省略 fmt,则使用默认格式模型’ DD’,并且返回的值将被 date 截断为时间为午夜的日期。
  • TRUNC(number),TRUNC(n1 [, n2 ]),传参为number,此函数将任何数值数据类型或任何可以隐式转换为数值数据类型的非数值数据类型作为参数。如果省略 n2,则 函数返回与参数的数值数据类型相同的数据类型。如果包含 n2,则函数返回 NUMBER。
  • TRUNC(text),trunc(text [, int]),第一个参数为 text 文本类型,并且需要为标准数字输入,没有范围限制。如果无法转换为标准数字,则报错。 如果第一个参数为 NULL 则返回 NULL。 第二个参数 int 如果省略,则将 text 文本截断为 0 位(即为整数)。如果 int 为负数,则截断小数点左侧的数字位数

推导分析

语句MysqlKes
select truncate(122.123, 4);截断数大于小数点的个数122.123122.1230
select truncate(0,3);00.000
select truncate('',3);0Null
select truncate(' ',3);0报错
select truncate(1.2334,'');1,warningNull
select truncate(1.2334,' ');1,warning报错
select truncate('asd sdfjskdgjrei asdja',-1.8);0,warning报错
select truncate('2023-08-07',2);2023,warning报错
select truncate('2023-08-07 12:12:30',-9);0,warning报错
select truncate(date'2022-01-01',-1.8);20220100报错
select trunc(date'2023-08-08','year');20230808,warning2023-01-01
select truncate(1.2345,'12');1.23451.23450 0000000
select truncate(122.123, 100000000000000000000);122.123,warning报错
select trunc(123.21);报错123
  1. 在mysql中如果截断数及第二个参数大于第一个参数小数点后面的总个数,直接返回该数本身,而在kes下会在小数点后面补零
  2. 在mysql中传参为’‘或’ ‘会默认为0,而kes下’‘默认null,’ ‘报错
  3. Mysql中不支持一个传参,kes一个参数可以认为是mysql中第二个参数为0,其结果一致
  4. 在mysql中字符串形式’…’(除’123‘这样数字字符串外)均会转换为number类型然后执行截断,但会提示warning,kes直接报错
  5. Mysql第一个参数最大支持10000000000000000000为八字节,kes第一个参数最大1000000000,是四字节大小

实现函数

3.1 用c语言方式实现

KDB_FUNCTION_INFO_V1(truncate);Datumtruncate(KDB_FUNCTION_ARGS){Numeric value = KDB_GETARG_NUMERIC(0);int32 retainNum = KDB_GETARG_INT32(1);Numeric res;if(retainNum > 0){NumericVar convert;set_var_from_num(value,&convert);if(retainNum > (&convert)->dscale)//value小数点后面有几个数{KDB_RETURN_NUMERIC(value);}else{res = DatumGetNumeric(DirectFunctionCall2(numeric_trunc, NumericGetDatum(value), Int32GetDatum(retainNum)));}}else{res = DatumGetNumeric(DirectFunctionCall2(numeric_trunc, NumericGetDatum(value), Int32GetDatum(retainNum)));}KDB_RETURN_NUMERIC(res);}
    1. 用plsql语言实现

| 1. create function sys.truncate(numeric,int4)

  1. returns numeric
  2. as $$
  3. declare
  4.     value numeric;
  5.     result numeric;
  6. begin
  7.     value := length(substring(cast(1 as varchar), position(. in cast(1 as varchar), position('.' in cast(1 as varchar))+ 1));
  8.     if value < $2 then
  9.         return $1;
  10.     else
  11.         return (select trunc(1,1,2));
  12.     end if;
  13. end;

| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |

在不直接调用kes下trunc函数的基础上实现mysql中truncate函数

create function sys.truncate1(numeric,int4)returns numericas declare    left_value numeric;     right_value numeric;     temp varchar;    temp1 varchar;    res numeric;begin    left_value := length(substring(cast($1 as varchar), position('.' in cast($1 as varchar))+ 1));    right_value := length($1 ::varchar) - left_value -1;    if $2 >= 0 then        if left_value <= $2 then            return $1;        else            temp := substr(cast($1 as varchar), 1, right_value+1+$2);            return TO_NUMBER(temp,'99999999999999999999.999999999999999999999999');        end if;    else        if -$2 >= right_value then            return 0;        else            temp := substr(cast($1 as varchar), 1, right_value-ABS($2));            temp1 := RPAD(temp, ABS($2) + length(temp), '0');            return TO_NUMBER(temp1,'99999999999999999999.999999999999999999999999');        end if;    end if;end; language plpgsql;

参考资料

《KingbaseES SQL 语言参考手册》