让 H2 将带引号和不带引号的名称视为相同。

26

H2似乎区分带引号和不带引号的名称。有没有办法让它以相同的方式处理它们?

这是我做过的测试:

CREATE TABLE test (dummy INT);
CREATE TABLE "testquote" (dummy INT, "quotedDummy" INT);

以下是查询语句:
SELECT * FROM test; --work
SELECT * FROM "test"; -- doesn't work
SELECT * FROM "testquote"; --work
SELECT * FROM testquote; --doesn't work
SELECT dummy FROM "testquote"; --work
SELECT quotedDummy FROM "testquote"; --doesn't work
SELECT "quotedDummy" FROM "testquote"; --work

我该如何使这些查询与H2兼容?

阅读SQL标准并学会适当使用大写字母。引号的作用是防止默认映射从小写转换为大写。 - bmargulies
@bmargulies,UPPERCASE 在 H2 上能用吗?在 H2 的 SQL 文档中找不到它。 - Drahakar
不是作为函数,只是拼写它们。 "TEST" 是与 plain test 匹配的内容。 - bmargulies
2个回答

41

H2 中的引用名称区分大小写, 这是 SQL 规范所要求的。这意味着下面的语句可以正常工作:

CREATE TABLE "testquote" (dummy INT, "quotedDummy" INT); 
SELECT * FROM "testquote";

但这不会:
SELECT * FROM "TestQuote";
SELECT * FROM "TESTQuote";
SELECT * FROM "TESTQUOTE";

H2中未引用的名称不区分大小写。它们通常会被转换为大写(如Oracle和其他数据库)。这意味着语句

CREATE TABLE test (dummy INT);
SELECT * FROM test;

相同
CREATE TABLE "TEST" ("DUMMY" INT);
SELECT * FROM "TEST";

在这方面,H2与Oracle的行为方式相同。这与其他数据库(如MySQL和PostgreSQL)处理标识符名称的方式有些不同。H2具有兼容性功能:如果在数据库URL后附加;DATABASE_TO_UPPER=FALSE,未引用的标识符将不会转换为大写,这意味着它们也是区分大小写的。但是,您需要在创建数据库时以及每次使用它时附加此设置(如果为现有数据库附加设置,则现有对象的标识符已经转换为大写)。
顺便说一下,这与function UPPER无关,该函数用于数据。您的问题涉及标识符,而不是数据。

有没有办法告诉 h2 数据库将使用引号创建的表名视为不区分大小写?即如果我 create table "test",可以允许 select * from test 正常工作吗? - Brett Ryan
查看兼容性部分,它描述了添加 ;IGNORECASE=TRUE,我已经这样做并重新创建了表,但是它们仍然是按引号引用和区分大小写的。使用1.4.191。 - Brett Ryan
我的错,那是排序规则而不是名称。我想创建带引号/不带引号的标识符,并能够选择引号/不带引号,而不考虑大小写匹配。实际上,我更喜欢相反的方式,即数据库将所有内容转换为小写而不是大写。 - Brett Ryan
如果您使用大写名称,则可以引用它们或不引用它们,并且它们应该指代相同的事物,即您具有一定的容错能力。如果您要引用它们,那么您是按照Microsoft Corporation还是Oracle Corporation的偏好来引用它们?如果非大写数据库表和列名称被强制执行,则除了引用它们之外,您几乎没有选择。但是,如果您是数据库设计师,则可以选择编写SQL,通过尽可能坚持制造商和供应商之间的共同点,使其适用于各种数据库类型。 - Ivan

1

我在Hibernate和H2中遇到了一些奇怪的问题,如果我在@Table注释中指定目录和模式名称,生成的SQL语句将对带引号的表名使用错误的大小写,导致失败。这可能是一个缺陷,但我发现了一个解决方法,在这里分享。

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;

public class H2IdentifierNamingStrategy extends PhysicalNamingStrategyStandardImpl {
    private static final long serialVersionUID = 1L;

    @Override
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
        if(name==null) return null;
        else return new Identifier(name.getText().toLowerCase(), name.isQuoted());
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接