2016-05-12 60 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