H2数据库整理强度:选择什么?

时间:2012-12-12 21:47:10

标签: search sql-order-by collation h2

经过大量的阅读和实验,似乎我想要寻找PRIMARY力量,但是想要订购TERTIARY或IDENTICAL。 主要问题:用H2(或任何其他数据库)可以实现吗?

次要问题:我是这里唯一的人还是你们中的任何一个人也喜欢上述组合?一些确认将有助于我的理智。

背景: 似乎只能在创建数据库时从头开始设置排序规则。所以我想确保选择正确的。我主要考虑这些用例(目前):

  1. 用户可以开始输入以过滤表格的搜索字段:这里PRIMARY似乎是最合适的,以避免遗漏任何结果(用户习惯Google ...)。虽然,能够为用户提供启用二级或三级排序规则以进行更精确搜索的选项会很不错。

  2. 订购:当用户点击表格列来订购内容时,TERTIARY / IDENTICAL排序似乎合适。这就是我从日常生活中习惯的。

  3. 我在这里阅读了官方的H2文档:http://www.h2database.com/html/grammar.html#set_collation。 在这里:http://www.h2database.com/html/datatypes.html#varchar_ignorecase_type 一些更相关的信息: Collation STRENGTH and local language relation

    测试sql(来自https://groups.google.com/forum/?fromgroups=#!topic/h2-database/lBksrrcuGdY):

    drop all objects;
    set collation english STRENGTH PRIMARY;
    create table test(name varchar);
    insert into test values ('À'), ('Ä'), ('Â'), ('A'), ('à'), ('ä'), ('â'), ('a'), ('àa'), ('äa'), ('âa'), ('aa'), ('B'), ('b');
    select * from test where name like 'a' order by name;
    select * from test order by name;
    

    enter image description here

2 个答案:

答案 0 :(得分:2)

如果您希望对单个数据有两种行为,则必须:

  • 将数据拆分为两列,
  • 或使用两个操作员集。

出于您的目的,通常存储"规范"表示原始数据,以便在规范形式上进行搜索,然后对原始数据进行排序/显示。也许你应该使用一些"文本搜索引擎"例如Apache Lucene

对于纯H2解决方案,您可以将H2 aliasComputed columns或查询条件一起使用。第一种解决方案允许建立索引以加快查询速度。

答案 1 :(得分:0)

将近8年后,我基于一些辛苦的学习而提出了自己的建议:

完全不使用排序规则(H2数据库的默认设置)。

合理性:使用归类将产生一些确实意外的结果和错误。

陷阱:唯一约束

到目前为止,我在日常业务中看到的最常见的唯一性约束是强制执行唯一性(名字,姓氏)。通常,应忽略大小写(同时防止“ thomasmüller”和“ ThomasMüller”),而不是变音符号(允许“ ThomasMüller”和“ Thomas Muller”)。

使用归类强度SECONDARY设置来实现此目的可能会很诱人(不区分大小写,但区分变音符号)。别。 改为使用VARCHAR_IGNORECASE 列。

{
  // NOT recommended: using SECONDARY collation
  Statement s = DriverManager.getConnection("jdbc:h2:mem:", "test", "test").createStatement();
  s.execute("SET COLLATION ENGLISH STRENGTH SECONDARY");
  s.execute("CREATE TABLE test ( name VARCHAR )");
  s.execute("ALTER  TABLE test ADD CONSTRAINT unique_name UNIQUE(name)");
  s.execute("INSERT INTO  test (name) VALUES ('Müller')");
  s.execute("INSERT INTO  test (name) VALUES ('Muller')");
  // s.execute("INSERT INTO  test (name) VALUES ('muller')" /* will fail */);
}
{
  // recommended: no collation, using VARCHAR_IGNORECASE instead of VARCHAR column
  Statement s = DriverManager.getConnection("jdbc:h2:mem:", "test", "test").createStatement();
  s.execute("CREATE TABLE test ( name VARCHAR_IGNORECASE )");
  s.execute("ALTER  TABLE test ADD CONSTRAINT unique_name UNIQUE(name)");
  s.execute("INSERT INTO  test (name) VALUES ('Müller')");
  s.execute("INSERT INTO  test (name) VALUES ('Muller')");
  // s.execute("INSERT INTO test (name) VALUES ('muller')" /* will fail */);
}

陷阱:搜索/ WHERE子句

建议:不使用排序规则的默认行为就可以了,并且表现出预期的效果。要进行更多的模糊搜索,请使用您自己的代码搜索或像Lucene这样的库。

SECONDARY排序规则强度将匹配,即使大小写不同也是如此。使用SELECT WHERE name = '...'时,您不会期望这种行为,因为您会忘记所有排序规则设置。

{
  Statement s = DriverManager.getConnection("jdbc:h2:mem:", "test", "test").createStatement();
  s.execute("SET COLLATION ENGLISH STRENGTH SECONDARY");
  s.execute("CREATE TABLE test ( name VARCHAR )");
  s.execute("INSERT INTO  test (name) VALUES ('Thomas Müller')");
  ResultSet rs = s.executeQuery("SELECT count(*) FROM test WHERE name = 'Thomas müller'" /* different case */);
  rs.next();
  /* prints 1 (!) */ System.out.println(rs.getLong(1));
}
即使空间不同,

PRIMARY的排序规则强度也会匹配。您是否相信英语主要排序规则会忽略空格?查看此块:https://stackoverflow.com/a/16567963/1124509

{      
  Statement s = DriverManager.getConnection("jdbc:h2:mem:", "test", "test").createStatement();
  s.execute("SET COLLATION ENGLISH STRENGTH PRIMARY");
  s.execute("CREATE TABLE test ( name VARCHAR )");
  s.execute("INSERT INTO  test (name) VALUES ('Thomas Müller')");
  ResultSet rs = s.executeQuery("SELECT count(*) FROM test WHERE name = 'ThomasMüller'" /* no space! */);
  rs.next();
  /* prints 1 (!) */ System.out.println(rs.getLong(1));
}

排序/ ORDER BY子句

没有排序规则的默认排序在实际情况下并不是真正有用,因为它将根据严格的字符串比较进行排序。通过首先从数据库中加载数据,然后使用代码对其进行排序/排序来解决此问题。

就我个人而言,我主要使用固定了spaces problem的英语主要力量整理者。即使对于非英文文本列也可以正常工作。

但是您可能还需要使用自定义比较器来满足更困难的要求,例如自然或直观的排序顺序,例如sort like windows explorersemantic versioning

{
  Statement s = DriverManager.getConnection("jdbc:h2:mem:", "test", "test").createStatement();
  s.execute("CREATE TABLE test ( name VARCHAR )");
  s.execute("INSERT INTO  test (name) VALUES ('é6')");
  s.execute("INSERT INTO  test (name) VALUES ('e5')");
  s.execute("INSERT INTO  test (name) VALUES ('E4')");
  s.execute("INSERT INTO  test (name) VALUES ('ä3')");
  s.execute("INSERT INTO  test (name) VALUES ('a2')");
  s.execute("INSERT INTO  test (name) VALUES ('A1')");
  ResultSet rs = s.executeQuery("SELECT name FROM test ORDER BY name");
  List<String> names = new ArrayList<>();
  while(rs.next()) {
    names.add(rs.getString(1));
  }
  // not very useful strict String.compareTo() result: [A1, E4, a2, e5, ä3, é6]
  System.out.print(names);

  String rules = ((RuleBasedCollator) Collator.getInstance(new Locale("en", "US"))).getRules();
  Collator collator = new RuleBasedCollator(rules.replaceAll("<'\u005f'", "<' '<'\u005f'"));
  collator.setStrength(Collator.PRIMARY);
  names.sort((a, b) -> collator.compare(a, b));
  // as humans usually expect it in a name list / table: [A1, a2, ä3, E4, e5, é6]
  System.out.print(names);
}

如何检查您的H2数据库是否使用排序规则?

查看“设置”表。如果未设置排序规则,则表中将没有任何条目。

COLLATION