使用“?::TIMESTAMP_NTZ”在查询中指定类型时,Snowflake JDBC 批量插入失败并显示“绑定变量?未设置”

Posted

技术标签:

【中文标题】使用“?::TIMESTAMP_NTZ”在查询中指定类型时,Snowflake JDBC 批量插入失败并显示“绑定变量?未设置”【英文标题】:Snowflake JDBC batch insert fails with "Bind variable ? not set" when specifying type in the query using "?::TIMESTAMP_NTZ" 【发布时间】:2020-05-07 01:55:28 【问题描述】:

我们正在使用 JDBC 驱动程序连接到 Snowflake 并执行插入操作。 表可以有多个时间戳列,这意味着单个插入查询可能必须同时处理 timestamp_ntz 和 timestamp_ltz。

当我们在查询中指定类型同时绑定值如下时,它工作正常

INSERT INTO <TABLENAME> VALUES(?::TIMESTAMP_NTZ, ?::TIMETAMP_LTZ)

但是,当我们尝试使用 addBatch() 和 executeBatch() 时,它会失败并显示“绑定变量?未设置”

示例程序 -

try (Connection con = getConnection()) 
    con.createStatement().execute("create or replace table Test_TSNTZ(t1 TIMESTAMPNTZ)");
    try (PreparedStatement ps = con.prepareStatement("insert into Test_TSNTZ values (? ::TIMESTAMP_NTZ)"))  
        java.sql.Timestamp t = java.sql.Timestamp.valueOf("2019-09-23 10:10:10.0");
        for (int i = 0; i < 22; i++) 
            ps.setTimestamp(1, t);
            ps.addBatch();
        
        ps.executeBatch();

        try (Statement statement = con.createStatement()) 
            try (ResultSet resultSet = statement.executeQuery("select * from Test_TSNTZ ")) 
                while (resultSet.next()) 
                    System.out.println(resultSet.getTimestamp(1));
                
            
        
    

【问题讨论】:

表格类型是TIMESTAMPNTZ 是不是打错字了?似乎应该是 'TIMESTAMP_NTZ' 。 如果您存储 NTZ 和 LTZ,那么您提出问题的方式似乎也很奇怪,“同时具有两种类型的时间戳”,您如何知道服务器中的哪个是哪个?我们经常在数据库中以 UTC 格式存储所有内容,因此在工作时不会出现跳跃间隙或混乱,只需了解您希望在 UI 中呈现的方式(什么 TZ)即可。所以看起来好坏参半 【参考方案1】:

如我所见,JDBC 连接器(不确定它是否特定于 Snowflake)如果变量被包围在函数或强制转换运算符。

作为一种解决方法,您可以将时间戳值作为字符串发送。 Snowflake 会将其转换为列类型:

try (Connection con = getConnection()) 
    con.createStatement().execute("create or replace table Test_TSNTZ(t1 TIMESTAMP_NTZ, t2 TIMESTAMP_LTZ)");
    try (PreparedStatement ps = con.prepareStatement("insert into Test_TSNTZ values ( ?, ? )"))  
        java.sql.Timestamp t = java.sql.Timestamp.valueOf("2019-09-23 10:10:10.0");
        for (int i = 0; i < 22; i++) 
            ps.setString(1, t.toString());
            ps.setString(2, t.toString());
            ps.addBatch();
        
        ps.executeBatch();

        try (Statement statement = con.createStatement()) 
            try (ResultSet resultSet = statement.executeQuery("select * from Test_TSNTZ ")) 
                while (resultSet.next()) 
                    System.out.println(resultSet.getTimestamp(1) + "," + resultSet.getTimestamp(2) );
                
            
        
    

【讨论】:

感谢 Gokhan Atil 分享解决方法。这里有什么特别需要注意的吗?我的意思是我们是否需要将时间戳转换为任何特定格式或时区,然后与 setString 一起使用?它确实看起来像一个缺陷,如果不是那么寻找解决这个用例的方法。 在我的测试中,它不需要输入特定的格式。 Java 时间戳使用与 Snowflake 兼容的格式。无论如何,Snowflake 都会尝试自动检测时间戳的格式。

以上是关于使用“?::TIMESTAMP_NTZ”在查询中指定类型时,Snowflake JDBC 批量插入失败并显示“绑定变量?未设置”的主要内容,如果未能解决你的问题,请参考以下文章

雪花在 TIMESTAMP_NTZ 列中显示“无效日期”

Snowflake SQL 错误 - 函数“-”的参数类型无效:(TIMESTAMP_NTZ(9), TIMESTAMP_NTZ(9))

Oracle数据库时间戳(6)转换为雪花timestamp_ntz时抛出错误

如何使用 spring 的 jdbcTemplate 在 SQL 查询中指定参数

如何使用多个条件查找查询在 MongoDB 中指定字段?

OData 错误:URI 中指定的查询无效。该属性不能在查询选项中使用