2013-04-16 45 views
9

在我的應用程序中,我想執行如下查詢:SELECT * FROM tbl WHERE col IN(@list)其中,@ list可以具有變量no的值。我正在使用MS SQL服務器數據庫。當我谷歌這個問題,後來我發現這個鏈接調用帶有表值參數的存儲過程

http://www.sommarskog.se/arrays-in-sql-2008.html

此鏈接說,使用表值參數。所以我使用Microsoft SQL Server Management Studio創建了用戶定義的數據類型。

CREATE TYPE integer_list_tbltype如表(正詮釋NOT NULL PRIMARY KEY)

然後寫存儲過程

CREATE PROCEDURE get_product_names @prodids integer_list_tbltype READONLY AS 
    SELECT p.ProductID, p.ProductName 
    FROM Northwind.dbo.Products p 
    WHERE p.ProductID IN (SELECT n FROM @prodids) 

,然後使用管理工作室只有我執行這個程序

DECLARE @mylist integer_list_tbltype 
INSERT @mylist(n) VALUES(9),(12),(27),(37) 
EXEC get_product_names @mylist 

它給我正確的輸出。但我想知道如何從Java源代碼中調用這個存儲過程。我知道如何調用簡單的存儲過程與恆定數量的參數

CallableStatement proc_stmt = null; 
proc_stmt = con.prepareCall("{call test(?)}"); 
proc_stmt.setString(1,someValue); 

但如何在表值參數情況下調用存儲過程?

回答

4

看起來這是一個計劃除了JDBC但尚未實施:

http://blogs.msdn.com/b/jdbcteam/archive/2012/04/03/how-would-you-use-table-valued-parameters-tvp.aspx

傳遞參數作爲分隔字符串(「9,12,27,37」),然後創建SQL Server中一個名爲「fnSplit」的表值函數,或者任何會返回表中整數值的東西(只要搜索「sql server split function」,其中有數百萬)。

+0

謝謝@凱文。你知道任何解決方案,而不是使用TVP解決問題。 –

+1

嗨Pranay,不客氣。檢查我的原始答案的建議。將分隔字符串作爲類型varchar(max)的單個參數傳遞。然後,在你的存儲過程中,調用SQL Server Split用戶定義的函數(你需要創建它,只需要搜索它,你會發現很多幫助)。 「分割」功能應該從分隔字符串中返回一個表格。祝你好運。 –

+0

只需添加@ Kevin的有用答案,OP的原始鏈接就包含一個名爲「iter_intlist_to_tbl」的函數示例,以將varchar分割爲表變量(http://www.sommarskog.se/arrays-in-sql-2005的.html#迭代)!只是想我會提到它。 – DarthPablo

2

典型的答案(逗號分隔或XML)都與SQL注入的問題。我需要一個答案,允許我使用PreparedStatement。所以我想出了這個:

StringBuilder query = new StringBuilder(); 
query.append(
    "DECLARE @mylist integer_list_tbltype;" + 
    "INSERT @mylist(n) VALUES(?)"); 
for (int i = 0; i < values.size() - 1; ++i) { 
    query.append(",(?) "); 
} 
query.append("; EXEC get_product_names @mylist "); 
PreparedStatement preparedStmt = conn.prepareStatement(query.toString()); 
for (int i = 0; i < values.size(); ++i) { 
    preparedStmt.setObject(i + 1, itemLookupValues.get(i)); 
} 
2

現在它已被添加到JDBC驅動程序6.0。 它CTP2呢。

「此新驅動程序現在支持Table-Valued Parameters和Azure Active Directory。除了這些新功能,我們還添加了Always Encrypted功能,驅動程序還支持國際化域名和參數化。

https://blogs.msdn.microsoft.com/jdbcteam/2016/04/04/get-the-new-microsoft-jdbc-driver-6-0-preview/

下載鏈接:https://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=11774

這裏是文檔如何使用它 https://msdn.microsoft.com/en-us/library/mt651781(v=sql.110).aspx

4

這是記錄在這裏的JDBC driver manual。在你的情況下,你必須這樣做:

try (SQLServerCallableStatement stmt = 
    (SQLServerCallableStatement) con.prepareCall("{call test(?)}")) { 

    SQLServerDataTable table = new SQLServerDataTable(); 
    sourceDataTable.addColumnMetadata("n", java.sql.Types.INTEGER); 

    sourceDataTable.addRow(9); 
    sourceDataTable.addRow(12); 
    sourceDataTable.addRow(27); 
    sourceDataTable.addRow(37); 

    stmt.setStructured(1, "dbo.integer_list_tbltype", table); 
} 

I've also recently documented this in an article

相關問題