Java中的UCanAccess在带有特殊字符的列中使用ORDER BY子句返回错误的顺序

问题描述

使用带有.mdb文件的Microsoft Access数据库(2007-2013),我创建了一个仅包含一个文本列test_table的简单"name"表,并插入了以下测试值:

óbito,fanatico,orbita,fanático,fanta,órbita,fantástico,obito,obituario,orbitando

当我使用MS Access查询设计执行查询SELECT * FROM test_table ORDER BY name时,返回以下有序结果:

fanatico,óbito,orbitando

这是完全正确的订单。

现在,我需要在Java软件中检索和使用这些值。为此,我使用版本5.0.0上的UCanAccess JDBC driver连接到数据库。连接本身已成功打开,但是,当我执行上述 same 查询时,它将返回以下内容

fanatico
fanta
fantástico
fanático
obito
obituario
orbita
orbitando
óbito
órbita  

这不是正确的顺序(例如óbito应该紧跟obito之后)。所需顺序应将重音词视为与等效的未重音词相同。
óbitoobito之前还是之后都没关系,但它们必须在一起
我尝试使用COLLATE,尝试更改字符集等,但是没有任何效果。有没有人经历过类似的事情,您能帮我解决这个问题吗?预先感谢。

解决方法

驱动程序正在按其二进制表示形式和/或单个ASCII字符进行排序。两者都提供您在底部提供的排序顺序。这完全是由驱动程序造成的问题,并且“修复”将受到限制。

在JDBC驱动程序更改日志中,在2.0.9.3发行说明下发布了一种解决方法:WORKAROUND suggested: if you want the same behaviour of Access: select * from table2 order by orderJet( COLUMN1).

如果这不起作用,那么您要么需要 a)通过在原始数据库中创建/维护一个SORTORDER列来颠覆驱动程序的排序,该列包含相同的单词并去除所有重音字符,或者b)找到一种方法来更改从之后到达的排序司机。这些都不是可取的,所以我希望开发人员提供的解决方法足够。

,

默认情况下,Java不执行对语言环境敏感的字符串比较。 在您的示例中,我尝试按照以下运行程序进行自然排序

 List<String> strings = Arrays.asList(new String[]{"óbito","fanatico","orbita","fanático","fanta","órbita","fantástico","obito","obituario","orbitando"});
    
    Collections.sort(strings);
    System.out.println("Output = " + strings);

输出为

Output = [fanatico,fanta,fantástico,fanático,obito,obituario,orbita,orbitando,óbito,órbita]

现在突出显示,只需替换下面的行

Collections.sort(strings,Collator.getInstance(Locale.US));

我得到了您期望的输出

Output = [fanatico,órbita,orbitando]

上面的示例为您提供了与语言环境敏感的字符串比较,以了解它们之间的区别。您可以通过多种方式从代码或数据库配置中解决此问题。

例如,您可以查看here

,

您尝试强制执行CharSet吗?

在这里CharSet for MS Access '97 DB using UCanAccess

class DatabaseOpener : JackcessOpenerInterface {
  override fun open(fl: File,pwd: String?): Database {
    return DatabaseBuilder.open(fl).apply {
      this.charset = charset("Cp1252")
    }
  }
}

// URL
"jdbc:ucanaccess://<path-to-mdb-file>;memory=false;jackcessOpener=${DatabaseOpener::class.qualifiedName!!}"


使用纯JDBC连接时,您可以尝试添加连接参数:

private static java.sql.ResultSet executeDataTable(String sql) throws Exception {
    Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
    String conStr = "jdbc:ucanaccess://" + dataDir + "ABC.mdb";
    Properties props = new java.util.Properties();
    props.put("charSet","Cp1252");
    java.sql.Connection con = java.sql.DriverManager.getConnection(conStr,props);

    java.sql.Statement stmt = con.createStatement();
    return stmt.executeQuery(sql);
}

您需要检查您的字符集可能是什么。因此有可能替换为“ Cp1252”。