java - 如何使用 jTDS 将表值参数传递给存储过程?

标签 java sql-server stored-procedures jdbc jtds

我需要使用 JTDS jdbc 驱动程序调用存储过程。

但是这个存储过程需要一个结构类型作为参数。 Jtds CallableStatement 没有设置结构的方法,因此我尝试转换为 SQLServerCallableStatement 并设置我想要的结构。 我使用的代码如下

            Connection con = ds.getConnection();
            CallableStatement call = con.prepareCall("{call getErrosSKF ?,?,?,?}");
            call.setString("agrupador", agrupador);
            call.setDate(2, new Date(dataInicio.getTimeInMillis()));
            call.setDate(3, new Date(dataFim.getTimeInMillis()));   

            SQLServerDataTable areas = new SQLServerDataTable();
            areas.addColumnMetadata("id",Types.INTEGER);
            for(Integer a : skfIdAreas) {
                areas.addRow(a);
            }
             // generate an exception
            ((SQLServerCallableStatement) call).setStructured(4, "erroSKFTable", areas);

但我无法强制转换,因为它会生成一个异常,表示 JtdsCallableStatement 无法转换为 SqlServerCallableStatemen

我可以使用其他替代方案吗?

最佳答案

对表值参数 (TVP) 的支持是 Microsoft 的 JDBC Driver for SQL Server 的一个相当新的功能,事实上,根据...

System Requirements for the JDBC Driver

... Microsoft 当前可用的 JDBC 驱动程序均无法与 JRE_6 配合使用。您可以尝试从 Microsoft 找到一个古老的 JDBC 驱动程序,但它无论如何都不会直接支持 TVP,所以您最好坚持使用 jTDS。

现在 jTDS 也不直接支持 TVP,但您可以通过以下方式完成任务

  1. 创建临时表,
  2. 用您的数据填充临时表,然后
  3. 使用匿名代码块从临时表填充 TVP,然后调用存储过程。

示例:

给定一个名为 [phonetic] ... 的现有引用表

letter  word
------  -------
A       Alfa
B       Bravo
C       Charlie
...
Y       Yankee
Z       Zulu

...用户定义的表类型...

CREATE TYPE [dbo].[LetterListTableType] AS TABLE(
    [seq] [int] NOT NULL,
    [letter] [varchar](1) NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [seq] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)

...以及一个将该表类型作为参数的存储过程...

CREATE PROCEDURE [dbo].[GetPhonetic] 
    @letters dbo.LetterListTableType READONLY
AS
BEGIN
    SET NOCOUNT ON;
    SELECT l.seq, l.letter, p.word 
        FROM phonetic p INNER JOIN @letters l on p.letter = l.letter
        ORDER BY l.seq;
END

...以下 Java 代码...

// 0. create some test data
String[] letters = new String[] { "G", "o", "r", "d" };
//
// 1. create temporary table
Statement s = conn.createStatement();
s.executeUpdate("CREATE TABLE #tmp (seq INT IDENTITY PRIMARY KEY, letter VARCHAR(1))");
//
// 2. populate temporary table with letters to look up
PreparedStatement ps = conn.prepareStatement("INSERT INTO #tmp (letter) VALUES (?)");
for (String letter : letters) {
    ps.setString(1, letter);
    ps.addBatch();
}
ps.executeBatch();
//
// 3. use anonymous code block to pass table-valued parameter to stored procedure
String sql = 
          "SET NOCOUNT ON; "
        + "DECLARE @tvp dbo.LetterListTableType; "
        + "INSERT INTO @tvp (seq, letter) SELECT seq, letter FROM #tmp; "
        + "EXEC dbo.GetPhonetic @tvp; ";
ResultSet rs = s.executeQuery(sql);
while (rs.next()) {
    System.out.printf("%s -> %s%n", rs.getString("letter"), rs.getString("word"));
}

...产生

G -> Golf
o -> Oscar
r -> Romeo
d -> Delta

关于java - 如何使用 jTDS 将表值参数传递给存储过程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54023407/

相关文章:

java - 嵌入式 Jetty HTTP/2 不适用于 Firefox/Chrome,但似乎可以用于 Safari

java - Google appengine Java 文档搜索,java.lang.IllegalArgumentException : number of documents

java - 独立 Java 应用程序中的 JVM 集群

sql - 这两个查询是否相同 - GROUP BY 与 DISTINCT?

sql - SQL Server 存储过程中 IF ELSE 的替代方法

stored-procedures - 存储过程未在 Crystal 报表中显示字段

java - 如何在Spring框架中实现UDP

mysql - 如何使用 linux 命令行对远程数据库执行 "INSERT INTO"查询?

sql-server - 使用 openrowset 将 Excel 文件读入临时表;我如何引用该表?

Mysql存储过程列类型引用