H2数据库整理:该怎么选?

问题描述 投票:4回答:2

看了很多书,也做了很多实验,似乎我想要primary的力量来进行搜索,但是triary或者identical来进行排序。主要问题是。这在H2(或其他DB)中可以实现吗?

次要问题:是否只有我一个人在这里?我是唯一一个在这里的人,还是你们中的任何一个人也喜欢上述组合?如果能确认一下,对我的理智会有帮助。

背景:好像只能在最开始创建数据库的时候设置整理。所以我想确保选对。我主要考虑的是这些用例(目前)。

  1. 一个搜索字段,用户可以在这里开始输入信息来过滤一个表。这里PRIMARY似乎是最合适的,以避免错过任何结果(用户习惯于Google...)。不过,如果能够让用户选择启用二级或三级整理来进行更精确的搜索,那就更好了。

  2. 排序。当用户点击一个表列对内容进行排序时,采用二级排序似乎比较合适。从日常经验来看,我习惯于此。

我看了这里的H2官方文档。http:/www.h2database.comhtmlcommands.html#set_collation.而这里: http:/www.h2database.comhtmldatatypes.html#varchar_ignorecase_type更多相关信息。整理强度与当地语言关系

测试 sql (来自 https:/groups.google.comforum?fromgroups=#!topich2-databaselBksrrcuGdY。):

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

search sql-order-by collation h2
2个回答
2
投票

如果你想对一个数据有两个行为,你必须。

  • 将数据分割成两列。
  • 或使用两个操作集。

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

对于纯H2溶液,您可以使用 H2 别名计算列 或带有查询条件。第一个解决方案可以通过索引来加快查询速度。


0
投票

将近8年后,我根据一些艰苦的学习,提出了自己的建议。

完全不使用整理 (H2数据库的默认值)。

理论依据。使用整理会产生一些 真的 意外的结果和bug。

坑爹。UNIQUE constraints

到目前为止,我在日常业务中看到的最常见的唯一性约束是强制执行唯一性(firstname,lastname)。通常情况下,应该忽略大小写(防止同时使用'thomas müller'和'Thomas Müller'),但不允许使用umlauts(允许同时使用'Thomas Mü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.coma165679631124509。

{      
  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));
}

按条款排序

不进行整理的默认排序在实际场景中并没有什么用,因为它会按照严格的字符串比较进行排序。解决方法是先从数据库中加载数据,然后用代码进行排序。

我个人主要是用英文主力整理器与 空间问题 固定的。即使对于非英文文本列也能正常工作。

但你可能还需要使用自定义比较器来满足更困难的要求,比如自然或直观的排序顺序,例如 像windows explorer那样排序语义版本化.

{
  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数据库是否使用了整理?

查看SETTINGS表。如果没有设置整理,表中就没有条目。

COLLATION

© www.soinside.com 2019 - 2024. All rights reserved.