2016-05-12 56 views
3

鉴于Oracle存储过程:传递一个ColdFusion阵列到甲骨文合集为绑定变量

CREATE TYPE stringlist AS TABLE OF VARCHAR2(100); 
/

CREATE PROCEDURE test_proc(
    list IN stringlist, 
    output OUT VARCHAR2 
) 
AS 
BEGIN 
    IF list IS NULL OR list IS EMPTY THEN 
    RETURN; 
    END IF; 
    output := list(1); 
    FOR i IN 2 .. list.COUNT LOOP 
    output := output || ',' || list(i); 
    END LOOP; 
END; 
/

我怎样才能把这个从ColdFusion的?

<cfscript> 
    arr = [ 'A', 'B', 'C' ]; 

    sp = new StoredProc(
    dataSource = "orcl", 
    procedure = "test_proc", 
    result  = "NA", 
    parameters = [ 
     { cfsqltype = "CF_SQL_ARRAY", type="in", value = arr }, 
     { cfsqltype = "CF_SQL_VARCHAR", type="out", variable = "out" } 
    ] 
).execute(); 

    // WriteDump(sp.getProcOutVariables().out); 
</cfscript> 

失败并:

Error Executing Database Query 
Fail to convert to internal representation: [A, B, C] 
+0

为什么不能变量为清单? –

+0

我知道可以通过对数组进行字符串化,然后在另一端对其进行解析,但是接下来您有两次转换,并且必须修改存储过程。但主要是因为这不是问题的问题 - 它专门将数组传递给集合 - 可以[用Java完成](http://stackoverflow.com/a/37161584/1509264),但我有在ColdFusion中找不到简单/原生的方式。 – MT0

回答

2

首先,设立一个使用Oracle JDBC drivers的数据源。下载相应的JAR文件,并将其放置在ColdFusion实例的lib目录,然后,通过CFIDE管理面板,你可以建立这样一个数据源:

CF Data Source Name: orcl 
JDBC URL:   jdbc:oracle:thin:@localhost:1521:orcl 
Driver Class:  oracle.jdbc.OracleDriver 
Driver Name:   Other 

(注:该驱动程序名称是“其他“而不是‘甲骨文’ - 这将使用Adobe的Oracle驱动程序无法在指定的Oracle驱动程序)

然后你就可以下降到原始的Java,而不是使用<cfstoredproc>new StoredProc()调用存储过程。

<cfscript> 
array  = JavaCast("string[]", [ 'A', 'B', 'C' ]); 
try { 
    connection = createObject('java', 'coldfusion.server.ServiceFactory') 
        .getDataSourceService() 
        .getDataSource('orcl') 
        .getConnection() 
        .getPhysicalConnection(); 
    description = createObject('java', 'oracle.sql.ArrayDescriptor') 
        .createDescriptor('STRINGLIST', connection); 
    oracleArray = createObject('java', 'oracle.sql.ARRAY') 
        .init(description, connection, array); 

    statement = connection.prepareCall('{call test_proc(:input, :output)}'); 
    statement.setARRAYAtName("input", oracleArray); 
    stringType = createObject('java', 'java.sql.Types').VARCHAR; 
    statement.registerOutParameter("output", stringType); 
    statement.executeQuery() 

    returnValue = statement.getString("output"); 
} 
finally 
{ 
    if (isDefined("statement")) 
    statement.close(); 
    if (isDefined("connection")) 
    connection.close(); 
} 
</cfscript> 

顺便说一句,你还可以通过数组查询(然后让你可以在<cfloop>使用的结果)是这样的:

try { 
    // set-up connection, etc. as above 
    statement = connection.prepareStatement('SELECT * FROM TABLE(:input)'); 
    statement.setARRAYAtName("input", oracleArray); 
    resultSet = statement.executeQuery(); 
    queryResult = createObject('java', 'coldfusion.sql.QueryTable') 
       .init(resultSet) 
       .FirstTable(); 
} 
finally 
{ 
    if (isDefined("resultSet")) 
    resultSet.close(); 
    if (isDefined("statement")) 
    statement.close(); 
    if (isDefined("connection")) 
    connection.close(); 
} 
+0

根据问题,数据源和存储过程已经存在。 –

+0

@DanBracuk是的,数据源已经存在,但如果数据源使用ColdFusion附带的Adobe Oracle驱动程序,它将不起作用 - 问题是您必须使用Oracle的Oracle驱动程序。关于你的第二点,我从不重新定义答案中的程序。 – MT0

+1

@ MT0 - 我意识到这只是一个例子,但不要忘记[关闭](http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#close%28 %29)所有语句对象,以确保资源被正确释放。通常,[连接](http://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html#close%28%29)也会关闭(*在所有语句之后) 。但是,CF DSN通常使用连接池,并且我不记得使用ServiceFactory时是否有必要,因为它有点黑盒子。我会想“是”,但你可能想验证一下。 – Leigh