Derby 对 NULL 值的处理

发布于 2024-10-15 21:37:06 字数 1901 浏览 5 评论 0原文

我是 Derby 的新手,我注意到就 null 值而言,我面临着与使用 DB2 RDBMS 类似的问题。 Derby 文档指出,null 值必须有一个与之关联的类型(DB2 最终在版本 9.7 中摆脱了这一点):

http://db.apache.org/derby/docs/10.7/ref/crefsqlj21305.html

现在,我正在尝试在这里找到这个问题的通用解决方案,因为这将是我的数据库抽象库jOOQ。下面的例子只是记录了这个问题。想一想任何其他(更复杂的)例子。以下不起作用:

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
select 
  1000, 'Lukas', 'Eder', 
  '1981-07-10', null, null 
from SYSIBM.SYSDUMMY1

这也不起作用(这实际上是由 jOOQ 完成的):

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
select ?, ?, ?, ?, ?, ? 
from SYSIBM.SYSDUMMY1

因为两个 null 值没有与之关联的类型。解决方案是分别编写如下内容:

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
select 
  1000, 'Lukas', 'Eder', 
  '1981-07-10', cast(null as int), cast(null as varchar(500)) 
from SYSIBM.SYSDUMMY1

或者分别这样

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
select 
  ?, ?, ?, ?, cast(? as int), cast(? as varchar(500)) 
from SYSIBM.SYSDUMMY1

但是,在 Java 中,null 应该转换为的类型通常是未知的:

  • 在本例中,类型可以派生自insert 子句,但这对于更一般的用例来说可能会很复杂或不可能。
  • 在其他示例中,我可以选择任何类型进行转换(例如始终转换为 int ),但这在本例中不起作用,因为您不能将 cast(null as int) 值转换为 ADDRESS
  • 使用 HSQLDB(此问题的另一个候选者),我可以简单地编写 cast(null as object) 这在大多数情况下都可以工作。但 Derby 没有 object 类型。

这个问题之前一直困扰着我使用DB2,至今还没有找到解决方案。有谁知道这些 RDBMS 中有一个稳定通用解决此问题的方法吗?

  • 德比
  • DB2

I am new to Derby and I noticed that I face similar problems as when using the DB2 RDBMS as far as null values are concerned. The Derby documentation states, that a null value must have a type associated with it (something that DB2 finally got rid of in version 9.7):

http://db.apache.org/derby/docs/10.7/ref/crefsqlj21305.html

Now, I am trying to find a general solution to this problem here as this will be a part of my database abstraction library jOOQ. The below example just documents the problem. Think of any other (more complex) example. The following doesn't work:

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
select 
  1000, 'Lukas', 'Eder', 
  '1981-07-10', null, null 
from SYSIBM.SYSDUMMY1

Neither does this (which is what is actually done by jOOQ):

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
select ?, ?, ?, ?, ?, ? 
from SYSIBM.SYSDUMMY1

Because the two null values have no type associated with it. The solution would be to write something like this:

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
select 
  1000, 'Lukas', 'Eder', 
  '1981-07-10', cast(null as int), cast(null as varchar(500)) 
from SYSIBM.SYSDUMMY1

Or like this, respectively

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
select 
  ?, ?, ?, ?, cast(? as int), cast(? as varchar(500)) 
from SYSIBM.SYSDUMMY1

But very often, in Java, the type that null should be cast to is unknown:

  • In this example, the types could be derived from the insert clause, but that might prove to be complicated or impossible for more general use-cases.
  • In other examples, I could just pick any type for the cast (e.g. always casting to int), but that wouldn't work in this example, as you cannot put a cast(null as int) value into ADDRESS.
  • With HSQLDB (another candidate for this problem), I can simply write cast(null as object) which will work in most cases. But Derby does not have an object type.

This problem has been annoying me with DB2 before and I haven't found a solution yet. Does anyone know of a stable, and general solution to this problem for any of these RDBMS?

  • Derby
  • DB2

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

暖心男生 2024-10-22 21:37:06

如果您在 INSERT 上使用 VALUES 子句,则不必转换 NULL 值:

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
VALUES ( 
  1000, 'Lukas', 'Eder', 
  '1981-07-10', null, null 
);

这将像您期望的那样工作(即数据库可以确定 NULL 对应于整数和 varchar(500)。这适用于两种情况DB2 和 Derby(并且也应该在几乎任何其他数据库引擎中工作)。

您也可以将 VALUES 与参数标记一起使用,而无需

在发出插入时进行转换 。 ... select from 语句是因为 SELECT 部分优先 - select 语句返回某些数据类型,无论它们是否与您尝试插入的表兼容(如果不兼容)。如果不兼容,您要么会收到错误(使用强类型数据库引擎,如 DB2 <= 9.5),要么引擎将执行隐式类型转换(如果可能)。

If you use the VALUES clause on your INSERT, you don't have to cast the NULL values:

insert into T_AUTHOR (
  ID, FIRST_NAME, LAST_NAME, 
  DATE_OF_BIRTH, YEAR_OF_BIRTH, ADDRESS) 
VALUES ( 
  1000, 'Lukas', 'Eder', 
  '1981-07-10', null, null 
);

This will work like you expect (i.e. the database can determine that the NULLs correspond to an integer and varchar(500). This works in both DB2 and Derby (and should work in pretty much any other database engine, as well).

You can use VALUES with parameter markers as well, without having to CAST them.

The reason that you have to cast when issuing an insert into ... select from statement is because the SELECT portion takes precedence -- the select statement returns certain data types, regardless of whether they are compatible with the table you're trying to insert them in to. If they aren't compatible, you will either get an error (with strongly typed database engines like DB2 <= 9.5) or the engine will do implicit type conversion (when possible).

自演自醉 2024-10-22 21:37:06

DB2 使用 null 指示符...例如,

EXEC SQL INSERT INTO TABNAM (FILD1, FILD2) 
                     VALUES (:HOSTVAR1, :HOSTVAR2:NULL-IND2)  END-EXEC.

请注意 NULL-IND2 字段,可以将其设置为 -1 以指示数据库表中的该字段应该为 null。

JDBC或Derby有类似的指标吗?

DB2 uses the null indicator... for example

EXEC SQL INSERT INTO TABNAM (FILD1, FILD2) 
                     VALUES (:HOSTVAR1, :HOSTVAR2:NULL-IND2)  END-EXEC.

notice the NULL-IND2 field which can be set to a -1 to indicate that this field in the database table should be null.

Is there a similar indicator for JDBC or Derby?

要走就滚别墨迹 2024-10-22 21:37:06

如果您在PreparedStatement 中将列值保留为问号替换值,然后在运行时使用PreparedStatement.setObject(N, null) 设置这些值,会怎么样?

一般来说,您的库更愿意通过替换参数值来提供列值,以处理字符串中的引号、数据类型转换等问题,并且我认为这种通用替换机制也应该处理您的空值问题。

What if you leave the column values as question-mark substitution values in your PreparedStatement, and then set the values at runtime using PreparedStatement.setObject(N, null)?

In general, your library will prefer to provide column values by substituting parameter values, to handle issues like quotation marks in strings, datatype conversions, etc., and I think that this general substitution mechanism should handle your null value problems as well.

银河中√捞星星 2024-10-22 21:37:06

也许这个解决方案可以帮助您:

insert into T_AUTHOR (
    ID, 
    FIRST_NAME, 
    LAST_NAME, 
    DATE_OF_BIRTH, 
    YEAR_OF_BIRTH, 
    ADDRESS
) select 
    1000, 
    'Lukas', 
    'Eder', 
    '1981-07-10', 
    (select YEAR_OF_BIRTH from T_AUTHOR where true = false), 
    (select ADDRESS from T_AUTHOR where true = false) 
from SYSIBM.SYSDUMMY1

此方法不需要显式转换 null,因为内部 select 将返回具有所需类型的 null。

Maybe this solution helps you:

insert into T_AUTHOR (
    ID, 
    FIRST_NAME, 
    LAST_NAME, 
    DATE_OF_BIRTH, 
    YEAR_OF_BIRTH, 
    ADDRESS
) select 
    1000, 
    'Lukas', 
    'Eder', 
    '1981-07-10', 
    (select YEAR_OF_BIRTH from T_AUTHOR where true = false), 
    (select ADDRESS from T_AUTHOR where true = false) 
from SYSIBM.SYSDUMMY1

This method does not require explicit cast of null, because inner select will return null with required type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文