oracle将ISBN10转换为ISBN13

时间:2016-08-26 06:41:21

标签: oracle plsql

我需要将ISBN从10位转换为13位。我试过但没有得到正确的结果。这是我尝试过的代码,但没有给出正确的结果。

Create or replace FUNCTION F_ISBN_CONV_13 (ISBN_10 IN VARCHAR2) RETURN VARCHAR2
    AS
        V_ISBN_13 VARCHAR2(13);
    BEGIN
        SELECT
        CASE WHEN LENGTH(ISBN_10) = 10 THEN

            CASE WHEN SUBSTR(ISBN_10,1,3) = '801' THEN
                '201' ||
                SUBSTR(ISBN_10,1,9)  ||
                SUBSTR(
                    (
                        10 -
                        SUBSTR(
                            (
                                (
                                    2 +
                                    1 +
                                    SUBSTR(ISBN_10,2,1) +
                                    SUBSTR(ISBN_10,4,1) +
                                    SUBSTR(ISBN_10,6,1) +
                                    SUBSTR(ISBN_10,8,1)
                                )  +
                                (
                                    (
                                        0 +
                                        SUBSTR(ISBN_10,1,1) +
                                        SUBSTR(ISBN_10,3,1) +
                                        SUBSTR(ISBN_10,5,1) +
                                        SUBSTR(ISBN_10,7,1) +
                                        SUBSTR(ISBN_10,9,1)
                                    )
                                ) * 3
                            )
                            ,-1
                            ,1
                        )
                    )
                    ,-1
                    ,1
                )
            ELSE
                '978' ||
                SUBSTR(ISBN_10,1,9)  ||
                SUBSTR(
                    (
                        10-
                        SUBSTR(
                            (
                                (
                                    9 +
                                    8 +
                                    SUBSTR(ISBN_10,2,1) +
                                    SUBSTR(ISBN_10,4,1) +
                                    SUBSTR(ISBN_10,6,1) +
                                    SUBSTR(ISBN_10,8,1)
                                ) +
                                (
                                    (
                                        7 +
                                        SUBSTR(ISBN_10,1,1) +
                                        SUBSTR(ISBN_10,3,1) +
                                        SUBSTR(ISBN_10,5,1) +
                                        SUBSTR(ISBN_10,7,1) +
                                        SUBSTR(ISBN_10,9,1)
                                    )
                                ) * 3
                            )
                            ,1
                            ,1
                        )
                    )
                    ,-1
                    ,1
                )
            END
        ELSE
            ISBN_10
        END INTO V_ISBN_13
    FROM
        DUAL;

    RETURN V_ISBN_13;
EXCEPTION
   --< code >
END F_ISBN_CONV_13;

2 个答案:

答案 0 :(得分:1)

我认为以下代码应该是不言自明的。有关详细信息,请参阅维基百科链接。

-- https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_to_ISBN-13_conversion
create or replace function isbn10_to_13(p_isbn10 in varchar2)
return varchar2 is
  v_isbn10_digits constant varchar2(9) := substr(replace(p_isbn10, '-', ''), 1, 9);
  v_isbn13 varchar2(17) := '978-' || substr(p_isbn10, 1, length(p_isbn10) - 1);
  v_checkdigit number;
begin
  -- https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-13_check_digit_calculation
  v_checkdigit :=
      (1 * 9)
    + (3 * 7)
    + (1 * 8)
    + (3 * to_number(substr(v_isbn10_digits, 1, 1)))
    + (1 * to_number(substr(v_isbn10_digits, 2, 1)))
    + (3 * to_number(substr(v_isbn10_digits, 3, 1)))
    + (1 * to_number(substr(v_isbn10_digits, 4, 1)))
    + (3 * to_number(substr(v_isbn10_digits, 5, 1)))
    + (1 * to_number(substr(v_isbn10_digits, 6, 1)))
    + (3 * to_number(substr(v_isbn10_digits, 7, 1)))
    + (1 * to_number(substr(v_isbn10_digits, 8, 1)))
    + (3 * to_number(substr(v_isbn10_digits, 9, 1)))
    ;
  v_checkdigit := 10 - mod(v_checkdigit, 10);

  if v_checkdigit = 10
  then
    v_checkdigit := 0;
  end if;

  return v_isbn13 || v_checkdigit;
end;
/

示例

col isbn10 for a13
col isbn13 for a17

with isbn10(i10) as (
  select '0-30-640615-x' from dual union all
  select '0-07-223065-7' from dual union all
  select '0-596-51446-x' from dual
)
select isbn10.i10 as isbn10, isbn10_to_13(isbn10.i10) as isbn13
from isbn10;

ISBN10        ISBN13
------------- -----------------
0-30-640615-x 978-0-30-640615-7
0-07-223065-7 978-0-07-223065-9
0-596-51446-x 978-0-596-51446-4

答案 1 :(得分:0)

我得到了正确的结果。

Create or replace FUNCTION F_ISBN_CONV_13 (ISBN_10 IN VARCHAR2) RETURN VARCHAR2
    AS
        V_ISBN_13 VARCHAR2(13);
    BEGIN
        SELECT
        CASE WHEN LENGTH(ISBN_10) = 10 THEN

            CASE WHEN SUBSTR(ISBN_10,1,3) = '801' THEN
                '201' ||
                SUBSTR(ISBN_10,1,9)  ||
                SUBSTR(
                    (
                        10 -
                        SUBSTR(
                            (
                                (
                                    2 +
                                    1 +
                                    SUBSTR(ISBN_10,2,1) +
                                    SUBSTR(ISBN_10,4,1) +
                                    SUBSTR(ISBN_10,6,1) +
                                    SUBSTR(ISBN_10,8,1)
                                )  +
                                (
                                    (
                                        0 +
                                        SUBSTR(ISBN_10,1,1) +
                                        SUBSTR(ISBN_10,3,1) +
                                        SUBSTR(ISBN_10,5,1) +
                                        SUBSTR(ISBN_10,7,1) +
                                        SUBSTR(ISBN_10,9,1)
                                    )
                                ) * 3
                            )
                            ,-1
                            ,1
                        )
                    )
                    ,-1
                    ,1
                )
            ELSE
                '978' ||
                SUBSTR(ISBN_10,1,9)  ||
                SUBSTR(
                    (
                        10-
                        SUBSTR(
                            (
                                (
                                    9 +
                                    8 +
                                    SUBSTR(ISBN_10,2,1) +
                                    SUBSTR(ISBN_10,4,1) +
                                    SUBSTR(ISBN_10,6,1) +
                                    SUBSTR(ISBN_10,8,1)
                                ) +
                                (
                                    (
                                        7 +
                                        SUBSTR(ISBN_10,1,1) +
                                        SUBSTR(ISBN_10,3,1) +
                                        SUBSTR(ISBN_10,5,1) +
                                        SUBSTR(ISBN_10,7,1) +
                                        SUBSTR(ISBN_10,9,1)
                                    )
                                ) * 3
                            )
                            ,-1      -- Need to change here from '1' to '-1'
                            ,1
                        )
                    )
                    ,-1
                    ,1
                )
            END
        ELSE
            ISBN_10
        END INTO V_ISBN_13
    FROM
        DUAL;

    RETURN V_ISBN_13;
EXCEPTION
   --< code >
END F_ISBN_CONV_13;