看了很多书,也做了很多实验,似乎我想要primary的力量来进行搜索,但是triary或者identical来进行排序。主要问题是。这在H2(或其他DB)中可以实现吗?
次要问题:是否只有我一个人在这里?我是唯一一个在这里的人,还是你们中的任何一个人也喜欢上述组合?如果能确认一下,对我的理智会有帮助。
背景:好像只能在最开始创建数据库的时候设置整理。所以我想确保选对。我主要考虑的是这些用例(目前)。
一个搜索字段,用户可以在这里开始输入信息来过滤一个表。这里PRIMARY似乎是最合适的,以避免错过任何结果(用户习惯于Google...)。不过,如果能够让用户选择启用二级或三级整理来进行更精确的搜索,那就更好了。
排序。当用户点击一个表列对内容进行排序时,采用二级排序似乎比较合适。从日常经验来看,我习惯于此。
我看了这里的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;
如果你想对一个数据有两个行为,你必须。
对于你的目的,通常存储一个原始数据的 "规范 "表示,以便在规范的形式上进行搜索,然后对原始数据进行分类显示。也许你应该使用一些 "文本搜索引擎",如 Apache Lucene.
将近8年后,我根据一些艰苦的学习,提出了自己的建议。
完全不使用整理 (H2数据库的默认值)。
理论依据。使用整理会产生一些 真的 意外的结果和bug。
到目前为止,我在日常业务中看到的最常见的唯一性约束是强制执行唯一性(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 */);
}
建议。没有整理的默认行为就很好,表现出预期的效果。如果想进行更多的模糊搜索,可以使用自己的代码搜索或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);
}
查看SETTINGS表。如果没有设置整理,表中就没有条目。