我试图从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程序员)。我做错了什么?
发布于 2017-10-10 13:37:12
您需要给函数规范中的数据类型(而不是参数名称)提供完整的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 Fiddle
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编写另一个函数。
或者使用下面的函数,分别返回CURR和DPOS作为开始和结束。
(注意: SQL中使用的函数只能返回一个值,因此您需要返回一个带有值、开始和结束属性的对象类型,或者为子字符串、start和end有三个单独的函数。)
还希望能够添加分隔符和quoted_by作为参数,并支持“,”(在逗号后面有一个空格)。
是的,但不容易使用正则表达式。类似的情况(部分测试,但没有通过所有的边缘案例):
SQL Fiddle
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) |发布于 2017-10-10 13:06:33
答案是:
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';
/https://stackoverflow.com/questions/46667489
复制相似问题