从Oracle PLSQL调用java时如何将参数传递给java

我试图从plsql调用一个java函数来在csv字符串中的某个索引处返回一个csv项目。 csv字符串还可以在引号内包含分隔符(基于此堆栈溢出问题)。

代码

set serverout on size 100000

CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "XxpayCsv" AS
import java.io.ByteArrayInputStream;
public class XxpayCsv
{
    public static String csv(String line, Integer idx)
    {
        String otherThanQuote = " [^"] ";
        String quotedString = String.format(" " %s* " ", otherThanQuote);
        String regex = String.format("(?x) "+ // enable comments, ignore white spaces
                ",                         "+ // match a comma
                "(?=                       "+ // start positive look ahead
                "  (?:                     "+ //   start non-capturing group 1
                "    %s*                   "+ //     match 'otherThanQuote' zero or more times
                "    %s                    "+ //     match 'quotedString'
                "  )*                      "+ //   end group 1 and repeat it zero or more times
                "  %s*                     "+ //   match 'otherThanQuote'
                "  $                       "+ // match the end of the string
                ")                         ", // stop positive look ahead
                otherThanQuote, quotedString, otherThanQuote);

        String[] tokens = line.split(regex, -1);
        //for(String t : tokens) {
        //    System.out.println("> "+t);
        //}
        return tokens[idx];
    }
};
/

CREATE OR REPLACE
FUNCTION xxpay_csv_at(s varchar2, i number) RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'XxpayCsv.csv (s, i) return java.lang.String';
/

DECLARE
   my_string clob;   -- VARCHAR2(400 CHAR);
BEGIN
   my_string := xxpay_csv_at('a,"b,c",d', 1);
   dbms_output.put_line('The value of the string is: ' || my_string);
END;
/

给我的错误

DECLARE
*
ERROR at line 1:
ORA-29531: no method csv in class XxpayCsv
ORA-06512: at "APPS.XXPAY_CSV_AT", line 1
ORA-06512: at line 4

因为我不知道如何传递字符串和整数作为参数(我不是Java程序员)。 我究竟做错了什么?


您需要使用完整的java路径在函数说明中给出数据类型(而不是参数名称):

CREATE OR REPLACE FUNCTION xxpay_csv_at(s varchar2, i number) RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'XxpayCsv.csv ( java.lang.String, java.lang.Integer ) return java.lang.String';
/

(注意: java.lang.Integer而不是int以符合您在Java代码中的规范)

但你可能想要的只是在Oracle中实现它:

SQL小提琴

Oracle 11g R2架构设置

CREATE OR REPLACE FUNCTION xxpay_csv_at(
  s varchar2,
  i number
) RETURN VARCHAR2 DETERMINISTIC
IS
BEGIN
  RETURN REGEXP_SUBSTR(
    s,
    '(^|,)(([^,"]*".*?")*[^,"]*)',
    1,
    i,
    NULL,
    2
  );
END;
/

查询1

WITH table_name ( csv ) AS (
  SELECT 'foo,bar,c;qual="baz,b""lurb",d;junk="quux,syzygy"' FROM DUAL
)
SELECT csv,
       xxpay_csv_at( csv, 1 ) AS value1,
       xxpay_csv_at( csv, 2 ) AS value2,
       xxpay_csv_at( csv, 3 ) AS value3,
       xxpay_csv_at( csv, 4 ) AS value4
FROM   table_name

结果

|                                               CSV | VALUE1 | VALUE2 |               VALUE3 |               VALUE4 |
|---------------------------------------------------|--------|--------|----------------------|----------------------|
| foo,bar,c;qual="baz,b""lurb",d;junk="quux,syzygy" |    foo |    bar | c;qual="baz,b""lurb" | d;junk="quux,syzygy" |

更新

有没有办法从regexp_substr获取匹配值的位置,这样我就不能只返回某个索引处的csv项目,而是返回原始csv字符串中开始和结束的字符位置?

使用REGEXP_INSTR而不是REGEXP_SUBSTR编写另一个函数。

或者使用下面的函数并分别返回CURRDPOS作为开始和结束。

(注意:SQL中使用的函数只能返回单个值,因此您需要返回具有值,开始和结束属性的对象类型,或者对于子字符串,开始和结束有三个单独的函数。)

还希望能够添加分隔符和quoted_by作为参数并支持分隔符,如','(逗号后面有一个空格)。

是的,但不容易使用正则表达式。 像这样的东西(部分测试,但没有通过所有的边缘情况):

SQL小提琴

Oracle 11g R2架构设置

CREATE OR REPLACE FUNCTION xxpay_csv_at(
  s varchar2,
  i number,
  delim VARCHAR2 DEFAULT ','
) RETURN VARCHAR2 DETERMINISTIC
IS
  j    PLS_INTEGER := 1;
  curr PLS_INTEGER := 1;
  dpos PLS_INTEGER;
  qpos PLS_INTEGER;
BEGIN
  WHILE TRUE LOOP
    dpos := INSTR( s, delim, curr );
    qpos := INSTR( s, '"', curr ); -- Start quote
    WHILE qpos BETWEEN curr AND dpos LOOP
      qpos := INSTR( s, '"', qpos + 1 ); -- End quote
      IF qpos = 0 THEN
        RAISE_APPLICATION_ERROR( -20000, 'Invalid String - No matching end-quote' );
      END IF;
      dpos := INSTR( s, delim, qpos + 1 );
      qpos := INSTR( s, '"', qpos + 1 );
    END LOOP;

    IF dpos = 0 THEN
      IF i = j THEN
        RETURN SUBSTR( s, curr );
      ELSE
        RETURN NULL;
      END IF;
    ELSE
      IF i = j THEN
        RETURN SUBSTR( s, curr, dpos - curr );
      ELSE
        j := j + 1;
        curr := dpos + LENGTH( delim );
      END IF;
    END IF;
  END LOOP;
END;
/

查询2

WITH table_name ( csv ) AS (
  SELECT ', foo,bar, c;qual="baz, b""lurb", d;junk="quux, syzygy", , ' FROM DUAL
)
SELECT csv,
       xxpay_csv_at( csv, 1, ', ' ) AS value1,
       xxpay_csv_at( csv, 2, ', ' ) AS value2,
       xxpay_csv_at( csv, 3, ', ' ) AS value3,
       xxpay_csv_at( csv, 4, ', ' ) AS value4,
       xxpay_csv_at( csv, 5, ', ' ) AS value5,
       xxpay_csv_at( csv, 6, ', ' ) AS value6
FROM   table_name

结果

|                                                         CSV | VALUE1 |  VALUE2 |                VALUE3 |                VALUE4 | VALUE5 | VALUE6 |
|-------------------------------------------------------------|--------|---------|-----------------------|-----------------------|--------|--------|
| , foo,bar, c;qual="baz, b""lurb", d;junk="quux, syzygy", ,  | (null) | foo,bar | c;qual="baz, b""lurb" | d;junk="quux, syzygy" | (null) | (null) |

原来的答案是:

CREATE OR REPLACE
FUNCTION xxpay_csv_at(s varchar2, i number) RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'XxpayCsv.csv (java.lang.String, int) return java.lang.String';
/
链接地址: http://www.djcxy.com/p/6305.html

上一篇: How to pass parameters to java when calling java from Oracle PLSQL

下一篇: How to pass date values in oracle?