【问题标题】:Inline BLOB / BINARY data types in SQL / JDBCSQL / JDBC 中的内联 BLOB / BINARY 数据类型
【发布时间】:2012-03-08 09:03:48
【问题描述】:

假设我想避免在 JDBC 中使用绑定变量并使用“ad-hoc”语句运行 SQL,例如:

connection.createStatement().executeQuery("SELECT ...");

是否有任何约定/JDBC 转义语法来内联 BLOB 数据类型?我知道H2 has this syntax

INSERT INTO lob_table VALUES (X'01FF');

但这不是标准。有什么通用的解决方案吗?请注意,我对一般方法感兴趣。我知道这可能会变得非常低效。

【问题讨论】:

  • 如果它是文本字段而不是图像,大多数 DBMS 将接受字符串。如果您想在其中获取非文本信息,可以将其转换为十六进制,尽管那样很昂贵。
  • @TonyHopkinson:我不知道数据的语义,所以我不得不假设它实际上是二进制数据。所以你是说大多数数据库都接受十六进制字符串?
  • 在文本块中,是的。图片,我不知道,从来没有尝试过。嗯,也许 Convert(VarBinary(),"SomeString" 也可能是一个观众,突然想到
  • @TonyHopkinson:这似乎是特定于 SQL Server 的。很高兴知道它是如何工作的,但通常对于这个问题,它超出了范围。我只是在寻找BLOB / BINARY 数据类型

标签: sql jdbc binary blob inline


【解决方案1】:

可能没有 JDBC 转义语法,所以我搜索了一下,发现并成功测试了以下内容:

  • SQL Server、Sybase ASE、Sybase SQL Anywhere

    INSERT INTO lob_table VALUES (0x01FF);
    
  • DB2

    -- Use a blob constructor. This is not needed for VARCHAR FOR BIT DATA types
    INSERT INTO lob_table VALUES (blob(X'01FF'));
    
  • Derby、H2、HSQLDB、Ingres、MySQL、SQLite

    INSERT INTO lob_table VALUES (X'01FF');
    
  • 甲骨文

    -- As mentioned by a_horse_with_no_name, keep in mind the relatively low
    -- limitation of Oracle's VARCHAR types to hold only 4000 bytes!
    INSERT INTO lob_table VALUES (hextoraw('01FF'));
    
  • Postgres

    -- There is also hex encoding as of Postgres 9.0
    -- The explicit cast is important, though
    INSERT INTO lob_table VALUES (E'\\001\\377'::bytea);
    

    有关 Postgres 十六进制编码的更多详细信息,请参阅 A.H.'s answer

  • SQL 标准

    -- SQL actually defines binary literals as such 
    -- (as implemented by DB2, Derby, H2, HSQLDB, Ingres, MySQL, SQLite):
    <binary string literal> ::=
      X <quote> [ <space>... ] 
      [ { <hexit> [ <space>... ] <hexit> [ <space>... ] }... ] <quote>
    
    <hexit> ::=
      <digit> | A | B | C | D | E | F | a | b | c | d | e | f
    

【讨论】:

  • 非常好的编译。请注意,Oracle 的字符文字限制为 4000 个字符,这也适用于 hextoraw() 函数。这限制了最大值。您可以这样创建的 blob 的大小。
  • @eckes:是的,它的工作原理如上所述,并在jOOQ 中以这种方式实现。您在什么情况下尝试过这个(即完整的陈述是什么)?
  • @LukasEder 是的,你是对的,INSERT INTO tBlob(cID, cBlob) VALUE ("1",CAST(X'010203' AS BLOB)) 实际上适用于 Derby。我的问题似乎与Flyway 相关。顺便说一句:没有演员表它不起作用,它会返回:ERROR 42821: Columns of type 'BLOB' cannot hold values of type 'CHAR () FOR BIT DATA'.,根据 Derby 规范,这是预期的。
  • @eckes:“顺便说一句:没有演员表它不起作用”:是的,这可能是真的。 Derby 对数据类型非常挑剔...
  • 显而易见的注意事项:至少在 MySQL 中,BLOB 是一种特定类型的字符串。因此,在有用的地方,“普通”字符串文字也可以用作 BLOB 文字:INSERT INTO lob_table VALUES ('abc')
【解决方案2】:

我想在Lukas' answer 中添加一些 PostgreSQL 特定的东西:

最短和最简单的解决方案是(至少从 PostgreSQL 9.0 开始):

insert into lob_table (data) values( E'\\x0102030405FF' )

没有任何转换(如果该列已经是 bytea 一个)并且只有 一个 \\x 标记在开头。这是Binary Data Types 部分中记录的“十六进制格式”。

关于X'01FF' 语法:根据string constant 文档,PostgreSQL 确实支持它——用于位字符串。而且似乎没有从位到字节的标准转换。

【讨论】:

  • 很好,感谢您的补充。我不知道我做错了什么,但在我的 Postgres 实例 (9.0) 中,运行 select E'\\x01FF' 时,十六进制变体似乎不起作用。但也许我错过了一些细节
  • 现在可以工作了吗?我在 9.1 上测试过。我的猜测:您使用了E'\\x01\\xFF',这确实不起作用:-)
  • 它确实有效。这只是我的无意义的十六进制代码01FF,它在 utf-8 中没有有用的对应关系,这就是它仍然在输出中转义的原因。呃! ;-)
【解决方案3】:
public String binaryLiteral(Connection con, byte[] bytes) {
    String databaseName = con.getMetaData().getDatabaseProductName();
    String binary = DatatypeConverter.printHexBinary(bytes);
    switch (databaseName) {
        case "Microsoft SQL Server":
        case "Sybase Anywhere": case "ASE": case "Adaptive Server Enterprise": // Sybase
            return "CONVERT(VARBINARY(MAX), '0x" + binary + "', 1)";
        case "Oracle":
            if (binary.length() <= 4000) {
                return "HEXTORAW('" + binary + "')";
            } else {
                // https://stackoverflow.com/questions/18116634/oracle-10-using-hextoraw-to-fill-in-blob-data/62162036#62162036
                return "CONCAT_RAWS(RAWS(" +
                        Streams.stream(Splitter.fixedLength(4000).split(binary))
                                .map(chunk -> "HEXTORAW('" + chunk + "')")
                                .collect(Collectors.joining(",")) +
                        "))";
            }
        case "PostgreSQL":
            return "E'\\\\x" + binary + "'";
        case "H2":
        // the following list is mostly untested
        case "HSQL Database Engine":
        case "Apache Derby":
        case "Ingres":
        case "MySQL":
        case "MariaDB":
        case "SQLite":
        case "Informix Dynamic Server":
        case "DB2":
        case "Firebird":
        default: // SQL Standard
            return "X'" + binary + "'";
    }

CONCAT_RAWSRAWS 的来源在Oracle 10: Using HEXTORAW to fill in blob data 中给出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-04
    • 2018-10-30
    • 1970-01-01
    • 2015-11-21
    • 2022-07-07
    • 1970-01-01
    • 1970-01-01
    • 2020-12-21
    相关资源
    最近更新 更多