我需要执行对case和accents不敏感的SELECT查询。出于演示目的,我创建了一个类似的表:
create table table
(
column text collate nocase
);
insert into table values ('A');
insert into table values ('a');
insert into table values ('Á');
insert into table values ('á');
create index table_cloumn_Index
on table (column collate nocase);
然后,我在执行以下查询时得到了这些结果:
SELECT * FROM table WHERE column LIKE 'a';
> A
> a
SELECT * FROM table WHERE column LIKE 'á';
> á
SELECT * FROM table WHERE column LIKE 'Á';
> Á
如何解决这个问题,以便以下任何查询的结果如下:
> A
> a
> Á
> á
顺便说一下,sqlite在iOS上运行。
提前致谢,
答案 0 :(得分:18)
两种基本方法:
您可以在表格中创建第二列,其中包含不带国际字符的字符串。此外,在对此辅助搜索列进行搜索之前,您还应该从正在搜索的字符串中删除国际字符(这样您就可以将非国际字符与非国际字符进行比较)。
这是我用来转换国际字符的例程:
NSData *data = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
您还可以用以下内容替换重音字符:
NSMutableString *mutableString = [string mutableCopy];
CFStringTransform((__bridge CFMutableStringRef)mutableString, NULL, kCFStringTransformStripCombiningMarks, NO);
顺便说一句,如果你需要对结果进行排序,你也可以对这个辅助搜索字段而不是主字段进行排序,这样可以避免因SQLite无法对国际字符进行排序而产生的问题。
您也可以创建自己的“非重音”C函数(在您的班级的@implementation
之外定义此C函数):
void unaccented(sqlite3_context *context, int argc, sqlite3_value **argv)
{
if (argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_TEXT) {
sqlite3_result_null(context);
return;
}
@autoreleasepool {
NSMutableString *string = [NSMutableString stringWithUTF8String:(const char *)sqlite3_value_text(argv[0])];
CFStringTransform((__bridge CFMutableStringRef)string, NULL, kCFStringTransformStripCombiningMarks, NO);
sqlite3_result_text(context, [string UTF8String], -1, SQLITE_TRANSIENT);
}
}
然后,您可以定义一个将调用此C函数的SQLite函数(在打开数据库之后调用此方法,这将在您关闭该数据库之前生效):
- (void)createUnaccentedFunction
{
if (sqlite3_create_function_v2(database, "unaccented", 1, SQLITE_ANY, NULL, &unaccented, NULL, NULL, NULL) != SQLITE_OK)
NSLog(@"%s: sqlite3_create_function_v2 error: %s", __FUNCTION__, sqlite3_errmsg(database));
}
完成后,您现在可以在SQL中使用这个新的unaccented
函数,例如:
if (sqlite3_prepare_v2(database, "select a from table where unaccented(column) like 'a'", -1, &statement, NULL) != SQLITE_OK)
NSLog(@"%s: insert 1: %s", __FUNCTION__, sqlite3_errmsg(database));
答案 1 :(得分:4)
您需要create some user function,或覆盖(即替换)like()
functions的默认实现。原因是sqlite中的LIKE
运算符不支持非ASCII不区分大小写:
SQLite只能理解ASCII字符的大写/小写 默认。对于unicode,LIKE运算符默认区分大小写 超出ASCII范围的字符。例如, 表达'a'LIKE'A'为TRUE但'æ'LIKE'Æ'为FALSE。
这是有道理的,否则sqlite需要支持不同的文化,因为案例因人而异。一个例子是the capital i
in Turkey which is not I
but a dotted İ
, and the lower-case of I
is a dot-less ı
。在sqlite中嵌入所有这些文化信息会非常繁琐(即它会增加sqlite目标代码)。
答案 2 :(得分:2)
这是我的LIKE问题解决方案
static void myLow(sqlite3_context *context, int argc, sqlite3_value **argv)
{
NSString* str = [[NSString alloc] initWithUTF8String:
(const char *)sqlite3_value_text(argv[0])];
const char* s = [[str lowercaseString] UTF8String];
sqlite3_result_text(context, s, strlen(s), NULL);
[str release];
}
// call it once after opening db
sqlite3_create_function(_db, "myLow", 1, SQLITE_UTF8,NULL, &myLow, NULL, NULL);
然后代替查询
SELECT * FROM table WHERE column LIKE 'a'
你应该使用
SELECT * FROM table WHERE myLow(column) LIKE 'a'