作为参考,我要解决的问题是有效地查找和删除可能包含大量条目的表中的重复项。
我正在使用的表称为 PersistedDay,其中包含一个 dayString 对象(它是一个字符串。:-P)。还有更多与此问题无关的列。我想找到任何有重复的 PersistedDay。
在 SQL 中,这是您可以做到这一点的有效方法之一(仅供参考,我可以在支持 SQLite DB 的 CoreData 上执行此查询):
SELECT ZDAYSTRING FROM ZPERSISTEDDAY GROUP BY ZDAYSTRING HAVING COUNT(ZDAYSTRING) > 1;
这仅返回具有重复项的 dayStrings,然后您可以通过使用生成的日期字符串进行查询来获取这些对象的所有字段(您可以将其用作子查询以在一个请求中完成所有操作)。
NSFetchRequest 似乎也具有执行此操作所需的所有部分,但它似乎并不完全有效。这是我试图做的:
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"PersistedDay" inManagedObjectContext:context];
[request setEntity:entity];
NSPropertyDescription* dayStringProperty = entity.propertiesByName[@"dayString"];
request.propertiesToFetch = @[dayStringProperty];
request.propertiesToGroupBy = @[dayStringProperty];
request.havingPredicate = [NSPredicate predicateWithFormat: @"dayString.@count > 1"];
request.resultType = NSDictionaryResultType;
NSArray *results = [context executeFetchRequest:request error:NULL];
那是行不通的。:-P 如果我尝试获取错误“Unsupported function expression count:(dayString)”。我认为“dayString.@count”中的 dayString 甚至在上面的代码中都不重要......但是,为了清楚起见,我把它放在了里面(SQL 计数只对分组的行进行操作)。
所以,我的问题是:这可能吗?如果可以,这样做的语法是什么?我在 CoreData 文档中找不到任何内容来说明如何执行此操作。
我发现了一个类似的 SO 帖子,不幸的是我现在找不到了,它是关于在有子句中运行计数(我认为没有 group by)。但是,海报在没有找到解决方案后放弃了并以不同的方式做了。我希望这更明确,所以也许有人有答案。:)
作为参考,这是我现在正在做的工作,但需要返回几乎所有行,因为在大多数情况下重复很少:
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"PersistedDay"
inManagedObjectContext:context];
[request setEntity:entity];
NSPropertyDescription* dayStringProperty = entity.propertiesByName[@"dayString"];
// Get the count of dayString...
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath: @"dayString"]; // Does not really matter
NSExpression *countExpression = [NSExpression expressionForFunction: @"count:" arguments: [NSArray arrayWithObject:keyPathExpression]];
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName: @"dayStringCount"];
[expressionDescription setExpression: countExpression];
[expressionDescription setExpressionResultType: NSInteger32AttributeType];
request.propertiesToFetch = @[dayStringProperty, expressionDescription];
request.propertiesToGroupBy = @[dayStringProperty];
request.resultType = NSDictionaryResultType;
NSArray *results = [context executeFetchRequest:request error:NULL];
然后我必须遍历结果,只返回 dayStringCount > 1 的结果。这就是 having 子句应该做的。:-P
注意:我知道 CoreData 不是 SQL。:) 只是想知道我是否可以以与 SQL 相同的效率进行等效类型的操作。