I have to create a NSFetchRequest for my iPhone App that returns the same results as the following SQL statement:
SELECT week
, year
, SUM(duration) AS totalDuration
FROM myTable
GROUP BY year
, week
I’ve tried to solve that with the following code:
NSExpression * durationExpression = [NSExpression expressionForFunction:@"sum:" arguments:[NSArray arrayWithObject:[NSExpression expressionForKeyPath:@"duration"]]];
NSExpressionDescription * durationExpressionDescription = [[[NSExpressionDescription alloc] init] autorelease];
[durationExpressionDescription setExpression:durationExpression];
[durationExpressionDescription setExpressionResultType:NSDoubleAttributeType];
[durationExpressionDescription setName:@"totalDuration"];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext];
NSArray *propertiesToFetch = [[NSArray alloc] initWithObjects:@"year", @"week", durationExpressionDescription, nil];
[fetchRequest setEntity:entity];
[fetchRequest setReturnsDistinctResults:YES];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setPropertiesToFetch:propertiesToFetch];
But that will group all results to one single row. Any hints how to solve it?
Edit: The source table has the following data:
year | month | duration
2011 | 7 | 10
2011 | 7 | 15
2011 | 6 | 15
2011 | 5 | 10
The SQL statement returns the correct result I’d like to achieve:
year | month | duration
2011 | 7 | 25
2011 | 6 | 15
2011 | 5 | 10
The NSFetchRequest returns:
year | month | duration
2011 | 7 | 50
Pretty sure your single return is triggered by the NSExpression which can only return a single value. Otherwise, you would get an array of dictionaries like this:
… which wouldn’t actually reflect the state of the data.
The expression is configured to return the sum of all the
durationvalues in every instance ofMyEntitygiven to it. Since you have no fetch predicate, it will be given every existing instance ofMyEntityavailable to the context. Nevertheless, it can only return a single value and that means a single dictionary when fetching by property.The best solution for this is to create a separate fetch for just the expression since it really has nothing to do with the other values being fetched i.e. the summed value isn’t associated with any particular year or month value. In any case, simple fetches run faster so separating the expression out will give you a overall speed boost even through you have two fetches instead of one.
I would caution you to avoid trying to use Core Data as you would SQL. It is a cardinal error to think of Core Data as a SQL wrapper. Core Data is not SQL. Entities are not tables. Objects are not rows. Attributes are not columns. Relationships are not joins. Core Data is an object graph management system that may or may not persist the object graph and may or may not use SQL far behind the scenes to do so. There is surprisingly little that translates directly from SQL to Core Data.