Вызов хранимой процедуры с табличным параметром из java
В моем приложении я хочу, чтобы выполнить запрос типа выберите * из tbl, где col в (@list) где,@list может иметь переменную no значений. Я использую базу данных MS SQL server. Когда я google эту проблему, то я нашел эту ссылку
http://www.sommarskog.se/arrays-in-sql-2008.html
эта ссылка говорит использовать табличный параметр. Поэтому я создал пользовательский тип данных с помощью Microsoft SQL Server Management Студия.
создать тип integer_list_tbltype в виде таблицы (N int не нулевой первичный ключ)
затем я написал хранимую процедуру
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)
а затем с помощью management studio только я выполнил эту процедуру
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);
но как вызвать хранимую процедуру в случае параметра table-value?
5 ответов
похоже, что это запланированное дополнение к JDBC, но еще не реализовано:
передайте параметр как строку с разделителями ("9,12,27,37"), а затем создайте табличную функцию в SQL Server под названием "fnSplit" или что-то еще, что вернет целочисленные значения в таблице (просто найдите "SQL server split function", есть миллионы их.)
это описано здесь руководство драйвера JDBC. В вашем случае вам придется сделать следующее:
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);
}
типичные ответы (разделенные запятыми или XML) все имеют проблемы с SQL-инъекцией. Мне нужен был ответ, который позволяет мне использовать PreparedStatement. Вот я и придумал:--2-->
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));
}
теперь он был добавлен в драйвер JDBC 6.0. Это версия ctp2 еще.
" этот новый драйвер теперь поддерживает табличные параметры и Azure Active Directory. В дополнение к этим новым функциям мы добавили дополнительные функции для Всегда зашифрованного. Драйвер также поддерживает Интернационализированные и параметризованные доменные имена."
https://blogs.msdn.microsoft.com/jdbcteam/2016/04/04/get-the-new-microsoft-jdbc-driver-6-0-preview/
скачать link: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
после поиска некоторое время я нашел ответ на эту проблему.Особенно, когда вы используете предложение IN и ни один из операндов не является переменным, вы можете использовать значения с разделителями-запятыми в качестве входных данных в предложении IN.
вот пример того, как хранимая процедура, которая будет извлекать всех адвокатов данного типа адвоката в предоставленном почтовом коде, будет выглядеть как использование динамического SQL.
CREATE PROCEDURE [dbo].[GetLawyers] ( @ZIP CHAR(5), @LawyerTypeIDs VARCHAR(100) )
AS
DECLARE @SQL VARCHAR(2000)
SET @SQL = 'SELECT * FROM [dbo].[Lawyers]
WHERE [ZIP] = ' + @ZIP + ' AND
[LawyerTypeID] IN (' + @LawyerTypeIDs + ')'
EXECUTE (@SQL)
GO
для выполнения хранимой процедуры передачи почтового индекса, введенного пользователем и выбранного адвокат вводит значение, разделенное запятыми:
EXECUTE [dbo].[GetLawyers] '12345', '1,4'
таким образом, вывод заключается в том, что вам не нужно использовать TVP. Какой бы язык[Java, PHP] вы не использовали, просто передайте параметры как строку с разделителями-запятыми в хранимую процедуру, и она будет работать идеально.
таким образом, в JAVA вы можете вызвать выше хранимую процедуру: -
proc_stmt = con.prepareCall("{call GetLawyers(?,?)}");
proc_stmt.setString(1,"12345");
proc_stmt.setString(2,"'1,4'");