2016年4月24日日曜日

[Oracle]JIS丸めのファンクションを作成してみた。

概要

Googleで検索してもなかなか出てこない「JIS丸め」Oracleファンクションを自作してみた。

ソース

create or replace function JIS_ROUND( v_value NUMBER, v_N NUMBER )
--
-- JIS_ROUND
--
-- IN  v_value 対象の数
--     v_N     丸める小数点の桁
-- OUT 丸めた数
--
RETURN NUMBER
IS
 a NUMBER := NULL;
 b NUMBER := NULL;
 ret NUMBER := NULL;
BEGIN

 -- 丸める桁(v_N)の1つ小さいの桁の数を求める
 a := trunc( mod( v_value * power( 10, v_N + 1  ), 10 ) );

 -- 求めた v_N -1 が桁が5以外なら、ROUND
 --             5なら、偶数丸め
 IF a != 5 THEN
  ret := ROUND( v_value, v_N );
 ELSE
  -- 丸める桁
  b := trunc( mod( v_value * POWER(10, v_N ), 2 ) );
  IF b = 0 THEN
   ret := TRUNC( v_value, v_N ); 
  ELSE
   ret := ROUND( v_value, v_N );
  END IF;
 END IF;

 RETURN ret;

END JIS_ROUND;

テスト

テストコードを以下に記載する。

DECLARE
  v_val NUMBER := NULL;
  v_N   NUMBER := NULL;
  v_ret NUMBER := NULL;
  v_expand NUMBER := NULL;
BEGIN

  --
  -- 実行後、すべて [TEST OK] と表示されればよい。
  --

  -- 整数部分の丸めテスト
  v_val := 1234.56;
  v_N := 0;
  v_expand := 1234;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
   DBMS_OUTPUT.PUT_LINE('v_expand:' || v_expand);
   DBMS_OUTPUT.PUT_LINE('v_ret:' || v_ret);
  END IF;

  v_val := 1235.56;
  v_N := 0;
  v_expand := 1236;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
    DBMS_OUTPUT.PUT_LINE('v_expand:' || v_expand);
    DBMS_OUTPUT.PUT_LINE('v_ret:' || v_ret);
  END IF;

  v_val := 1235.46;
  v_N := 0;
  v_expand := 1235;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
    DBMS_OUTPUT.PUT_LINE('v_expand:' || v_expand);
    DBMS_OUTPUT.PUT_LINE('v_ret:' || v_ret);
  END IF;

  v_val := 1235.66;
  v_N := 0;
  v_expand := 1236;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
    DBMS_OUTPUT.PUT_LINE('v_expand:' || v_expand);
    DBMS_OUTPUT.PUT_LINE('v_ret:' || v_ret);
  END IF;

  --
  -- 小数点第1位のテスト
  --
  v_val := 1234.56;
  v_N := 1;
  v_expand := 1234.6;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
  END IF;

  v_val := 1234.55;
  v_N := 1;
  v_expand := 1234.6;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
  END IF;

  v_val := 1234.54;
  v_N := 1;
  v_expand := 1234.5;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
  END IF;

  v_val := 1234.45;
  v_N := 1;
  v_expand := 1234.4;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
    DBMS_OUTPUT.PUT_LINE('v_expand:' || v_expand);
    DBMS_OUTPUT.PUT_LINE('v_ret:' || v_ret);
  END IF;

  v_val := 1234.44;
  v_N := 1;
  v_expand := 1234.4;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
  END IF;

  v_val := 1234.46;
  v_N := 1;
  v_expand := 1234.5;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
  END IF;

  --
  -- 整数部分
  --
  v_val := 1234.56;
  v_N := -1;
  v_expand := 1230;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
  END IF;

  v_val := 1235.56;
  v_N := -1;
  v_expand := 1240;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
  END IF;

  v_val := 1236.56;
  v_N := -1;
  v_expand := 1240;
  select JIS_ROUND(v_val, v_N) into v_ret from dual;
  IF v_expand = v_ret THEN
    DBMS_OUTPUT.PUT_LINE('TEST OK');
  ELSE
    DBMS_OUTPUT.PUT_LINE('TEST NG');
  END IF;

END;