Oracle JDBC 和 Oracle CHAR 数据类型

发布于 2024-10-23 23:39:01 字数 1737 浏览 3 评论 0原文

我在 Oracle JDBC 驱动程序处理 CHAR 数据类型时遇到了一个棘手的问题。让我们看一下这个简单的表:

create table x (c char(4));
insert into x (c) values ('a');  -- inserts 'a   '

因此,当我向 CHAR(4) 中插入某些内容时,该字符串始终会填充空格。当我执行这样的查询时,也会完成此操作:

select * from x where c = 'a';    -- selects 1 record
select * from x where c = 'a ';   -- selects 1 record
select * from x where c = 'a   '; -- selects 1 record

这里,常量 'a' 也用空格填充。这就是为什么总是返回记录的原因。当使用 JDBC PreparedStatement 执行这些查询时也是如此。现在棘手的事情是当我想使用绑定变量时:

PreparedStatement stmt = 
  conn.prepareStatement("select * from x where c = ?");
stmt.setString(1, "a");    // This won't return any records
stmt.setString(1, "a   "); // This will return a record
stmt.executeQuery();

这是一种解决方法:

PreparedStatement stmt = 
  conn.prepareStatement("select * from x where trim(c) = trim(?)");
stmt.setString(1, "a");    // This will return a record
stmt.setString(1, "a   "); // This will return a record
stmt.executeQuery();

编辑:现在这些是约束:

  • 上面的解决方法是不可取的,因为它修改了 的内容c?,并且它使得在 c 上使用索引变得非常困难。
  • 将列从 CHAR 移动到 VARCHAR (当然,它应该是)是不可能的

编辑:这些约束的原因是因为我从数据库抽象库 jOOQ 的开发人员的角度提出这个问题。所以我的要求是提供一个非常通用的解决方案,不会破坏 jOOQ 客户端代码中的任何内容。这就是为什么我不太喜欢这种解决方法。这就是为什么我无法访问该 CHAR 列的声明。但我仍然希望能够处理这个案子。

你会怎么做?当我想忽略尾随空格时,处理 CHAR 数据类型的好习惯是什么?

I have a tricky issue with the Oracle JDBC driver's handling of CHAR data types. Let's take this simple table:

create table x (c char(4));
insert into x (c) values ('a');  -- inserts 'a   '

So when I insert something into CHAR(4), the string is always filled with whitespace. This is also done when I execute queries like this:

select * from x where c = 'a';    -- selects 1 record
select * from x where c = 'a ';   -- selects 1 record
select * from x where c = 'a   '; -- selects 1 record

Here, the constant 'a' is filled with whitespace as well. That's why the record is always returned. This holds true when these queries are executed using a JDBC PreparedStatement as well. Now the tricky thing is when I want to use a bind variable:

PreparedStatement stmt = 
  conn.prepareStatement("select * from x where c = ?");
stmt.setString(1, "a");    // This won't return any records
stmt.setString(1, "a   "); // This will return a record
stmt.executeQuery();

This is a workaround:

PreparedStatement stmt = 
  conn.prepareStatement("select * from x where trim(c) = trim(?)");
stmt.setString(1, "a");    // This will return a record
stmt.setString(1, "a   "); // This will return a record
stmt.executeQuery();

EDIT: Now these are the constraints:

  • The above workaround is not desireable as it modifies both the contents of c and ?, AND it makes using indexes on c quite hard.
  • Moving the column from CHAR to VARCHAR (which it should be, of course) is not possible

EDIT: The reasons for these constraints is because I ask this question from the point of view of the developer of jOOQ, a database abstraction library. So my requirements are to provide a very generic solution that doesn't break anything in jOOQ's client code. That is why I'm not really a big fan of the workaround. And that's why I don't have access to that CHAR column's declaration. But still, I want to be able to handle this case.

What would you do instead? What's a good practice for handling CHAR data types when I want to ignore trailing whitespace?

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

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

发布评论

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

评论(6

花伊自在美 2024-10-30 23:39:01

如果你想

stmt.setString(1, "a");    // This won't return any records

返回一条记录,请尝试

conn.prepareStatement("select * from x where c = cast(? as char(4))")

If you want

stmt.setString(1, "a");    // This won't return any records

to return a record, try

conn.prepareStatement("select * from x where c = cast(? as char(4))")
唐婉 2024-10-30 23:39:01

我不认为有任何理由使用 CHAR 数据类型,即使它在 Oracle 中是 char(1) 。您可以更改数据类型吗?

I don't see any reason to use CHAR datatype even if it is char(1) in Oracle. Can you change the datatype instead?

多像笑话 2024-10-30 23:39:01

加里的解决方案效果很好。这是一个替代方案。

如果您使用的是 Oracle JDBC 驱动程序,则对 prepareStatement() 的调用实际上会返回一个 OraclePreparedStatement,它具有一个 setFixedCHAR() 方法自动用空格填充您的输入。

String sql = "select * from x where c = ?";
OraclePreparedStatement stmt = (OraclePreparedStatement) conn.prepareStatement(sql);
stmt.setFixedCHAR(1, "a");
...

显然,只有使用 Oracle 驱动程序时,转换才是安全的。

我建议您使用这个而不是 Gary 的答案的唯一原因是您可以更改列大小而无需修改 JDBC 代码。驱动程序会填充正确数量的空格,而开发人员无需了解/管理列大小。

Gary's solution works well. Here's an alternative.

If you are using an Oracle JDBC driver, the call to prepareStatement() will actually return an OraclePreparedStatement, which has a setFixedCHAR() method that automatically pads your inputs with whitespace.

String sql = "select * from x where c = ?";
OraclePreparedStatement stmt = (OraclePreparedStatement) conn.prepareStatement(sql);
stmt.setFixedCHAR(1, "a");
...

Obviously, the cast is only safe if you are using the Oracle driver.

The only reason I would suggest that you use this over Gary's answer is that you can change your column sizes without having to modify your JDBC code. The driver pads the correct number of spaces without the developer needing to know/manage the column size.

分開簡單 2024-10-30 23:39:01

我对此有很好的解决办法。从数据库获取连接时,您必须添加一项属性。

NLS_LANG=american_america.AL32UTF8

或者在 Java 连接中,您可以使用以下代码:

java.util.Properties info = new java.util.Properties();
info.put ("user", user);
info.put ("password",password);
info.put("fixedString","TRUE");
info.put("NLS_LANG","american_america.AL32UTF8");
info.put("SetBigStringTryClob","TRUE");
String url="jdbc:oracle:thin:@"+serverName;
log.debug("url="+url);
log.debug("info="+info);
Class.forName("oracle.jdbc.OracleDriver");
conn  = DriverManager.getConnection(url,info);

I have nice fix for this. You have to add one property while getting connection from database.

NLS_LANG=american_america.AL32UTF8

or in Java connection you can use below code:

java.util.Properties info = new java.util.Properties();
info.put ("user", user);
info.put ("password",password);
info.put("fixedString","TRUE");
info.put("NLS_LANG","american_america.AL32UTF8");
info.put("SetBigStringTryClob","TRUE");
String url="jdbc:oracle:thin:@"+serverName;
log.debug("url="+url);
log.debug("info="+info);
Class.forName("oracle.jdbc.OracleDriver");
conn  = DriverManager.getConnection(url,info);
财迷小姐 2024-10-30 23:39:01

另一种方法是将你的sql修改为

select * from x where NVL(TRIM(c),' ') = NVL(TRIM('a'),' ')

the other way is modify your sql as

select * from x where NVL(TRIM(c),' ') = NVL(TRIM('a'),' ')
怪我太投入 2024-10-30 23:39:01

只需将 RTRIM() 添加到更新查询中的列名(已定义)即可。

Simply add RTRIM() to the column name(which is defimed) in the update query.

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