NSP-предикат для выбора строки с максимальным значением по группе - PullRequest
3 голосов
/ 20 сентября 2011

Я использую базовые данные для хранения сущностей в форме

TrackerEntry

  • имя пользователя
  • 1008 * Отметка времени *

Я хочу выбрать самую последнюю запись для каждого пользователя. При использовании sql это будет что-то вроде

SELECT MAX(timestamp) FROM Log GROUP BY username

Есть ли способ создать NSP-предикат для этого?

Ответы [ 2 ]

3 голосов
/ 20 сентября 2011

Я бы сделал это с помощью NSExpression. Этот фрагмент кода ниже не будет работать для вас, потому что вам придется группировать по имени пользователя, но это лучший способ сделать это без необходимости извлекать все. Вы хотите выполнить максимум и группу в БД, а не в памяти - так как это будет быстрее:

NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];

// Expression for the max
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"timestamp"];

NSEntityDescription *entity = [NSEntityDescription entityForName:entityName
                                          inManagedObjectContext:self.coreDataStack.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setResultType:NSDictionaryResultType];

NSExpression *valueSumExpression = [NSExpression expressionForFunction:@"max:" arguments:[NSArray arrayWithObject:keyPathExpression]];

NSExpressionDescription *expressionDescription = [[[NSExpressionDescription alloc] init] autorelease];
[expressionDescription setName:@"maxTimestamp"];
[expressionDescription setExpression:valueSumExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];

[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];

// Filter
//NSPredicate *pred = [NSPredicate predicateWithFormat:@" your predicate here"];
//fetchRequest.predicate = pred;

NSArray *results = [self.coreDataStack.managedObjectContext executeFetchRequest:fetchRequest error:nil];
if([results count] == 0) {

} else {

    // [[results objectAtIndex:0] valueForKey:@"maxTimestamp"];

}
0 голосов
/ 20 сентября 2011

Это сработало для меня, но это цикл. Сначала вы должны получить уникальные имена в массив.

    NSFetchRequest *nameRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Log" inManagedObjectContext:self.managedObjectContext];
    nameRequest.entity = entity;
    nameRequest.resultType = NSDictionaryResultType;        
    [nameRequest setPropertiesToFetch:[NSArray arrayWithObject:[[entity propertiesByName] objectForKey:@"name"]]];
    NSArray *allNames = [self.managedObjectContext executeFetchRequest:nameRequest error:nil];
    names = [allNames valueForKeyPath:@"@distinctUnionOfObjects.name"];
    [nameRequest release];
    NSLog(@"%@", names);

Не очень эффективно или удобно. В конце концов, Core Data - это не база данных, а граф объектов.

Затем вы можете просмотреть их и выбрать только верхнюю.

    NSMutableArray *mutableResults = [NSMutableArray array];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    request.entity = [NSEntityDescription entityForName:@"Log" inManagedObjectContext:self.managedObjectContext];
    NSSortDescriptor *numberSort = [NSSortDescriptor sortDescriptorWithKey:@"number" ascending:NO];
    request.sortDescriptors = [NSArray arrayWithObject:numberSort];
    request.fetchLimit = 1;
    for (NSString *s in names) {
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"name = %@", s];
        request.predicate = pred;
        NSArray *results = [self.managedObjectContext executeFetchRequest:request error:nil];
        [mutableResults addObject:[results objectAtIndex:0]];
    }
    [request release];
    NSLog(@"%@", mutableResults);
...