2013-07-11 2 views
5

Предположим, что у меня есть 2 объекта, Person и Transaction.NSExpression относится к подзапросу NSPredicate

Person имеют отношение ко многим с TransactionTransaction и предприятие имеет amount и date. Моя цель состояла в том, чтобы иметь NSFetchRequest на основе Person, но я хочу знать только тех, у кого есть транзакции между определенными датами и суммой транзакций SUM.

Мой код выглядит следующим образом:

NSExpression *amountKeyPath = [NSExpression expressionForKeyPath:@"transactions.amount"]; 
NSExpression *sumAmountExpression = [NSExpression expressionForFunction:@"sum:" arguments:@[amountKeyPath]]; 

// Create the expression description for that expression. 
NSExpressionDescription *description = [[NSExpressionDescription alloc] init]; 
[description setName:@"sum"]; 
[description setExpression:sumAmountExpression]; 
[description setExpressionResultType:NSDecimalAttributeType]; 

// Create the sum amount fetch request, 
self.sumAmountFetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"]; 
self.sumAmountFetchRequest.resultType = NSDictionaryResultType; 
self.sumAmountFetchRequest.predicate = [NSPredicate predicateWithFormat:@"SUBQUERY(transactions, $t, $t.date >= %@ AND $t.date <= %@)[email protected] > 0", self.startDate, self.endDate]; 
self.sumAmountFetchRequest.propertiesToFetch = @[@"name", description]; 

Все, кажется, хорошо, но ... Когда я посмотрел на SQL-запроса генерируется, выглядит следующим образом:

SELECT t0.ZPERSONID, t0.ZNAME, 
    (SELECT TOTAL(t2.ZAMOUNT) FROM ZTRANSACTION t2 WHERE (t0.Z_PK = t2.ZPERSON)) 
FROM ZPERSON t0 
WHERE (SELECT COUNT(t1.Z_PK) FROM ZTRANSACTION t1 WHERE (t0.Z_PK = t1.ZPERSON AND ((t1.ZDATE >= ? AND t1.ZDATE <= ?)))) > ? 

Таким образом, кажется, что в NSExpression объявлено, не уважает созданный файл fetchRequest NSPredicate.

Можно ли сделать выражение также уважающим предикат, связанный с fetchRequest? Или с NSExpression стоит сам по себе, я должен приложить к нему еще один предикат?

+0

SQLite заявление выглядит хорошо для меня. Предикат преобразуется в последний «ГДЕ» и применяется ко всему оператору. Получаете ли вы ожидаемый результат? –

+0

Нет, я получил количество транзакций, принадлежащих этому лицу (не ограниченное временным интервалом - предложение WHERE) – Rpranata

+0

ОК, теперь я понимаю, что вы имеете в виду, и мой комментарий выше. –

ответ

5

У меня нет ничего, что могло бы поддержать мой собственный ответ, но после битвы с этим часами. Я думал, что это не то, что NSExpression не уважает fetchRequest NSPredicate, но его больше того, что предикат fetchRequest является подзапросом.

SELECT t0.ZPERSONID, t0.ZNAME, 
    (SELECT TOTAL(t2.ZAMOUNT) FROM ZTRANSACTION t2 WHERE (t0.Z_PK = t2.ZPERSON)) 
FROM ZPERSON t0 
WHERE 
    (SELECT COUNT(t1.Z_PK) FROM ZTRANSACTION t1 WHERE (t0.Z_PK = t1.ZPERSON AND ((t1.ZDATE >= ? AND t1.ZDATE <= ?)))) > ? 

Итак, подзапрос в предикате не на самом деле превращается в п WHERE я хочу. Я думаю, что если бы это создавало JOIN, это сработало бы.

Мое решение, в конце концов, должно работать наоборот. Если я создаю fetchRequest от Transaction, то это отлично работает.

NSExpression *amountKeyPath = [NSExpression expressionForKeyPath:@"amount"]; 
NSExpression *sumAmountExpression = [NSExpression expressionForFunction:@"sum:" arguments:@[amountKeyPath]]; 

// Create the expression description for that expression. 
NSExpressionDescription *description = [[NSExpressionDescription alloc] init]; 
[description setName:@"sum"]; 
[description setExpression:sumAmountExpression]; 
[description setExpressionResultType:NSDecimalAttributeType]; 

// Create the sum amount fetch request, 
self.sumAmountFetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Transaction"]; 
self.sumAmountFetchRequest.resultType = NSDictionaryResultType; 
self.sumAmountFetchRequest.predicate = [NSPredicate predicateWithFormat:@"date >= %@ AND date <= %@", self.startDate, self.endDate]; 
self.sumAmountFetchRequest.propertiesToFetch = @[@"person.name", description]; 
self.sumAmountFetchRequest.propertiesToGroupBy = @[@"person.name"]; 

Это работает отлично. Он должен быть сгруппирован по "person.name", так что он будет использовать sum: по желанию.

SQL, генерироваться будет

SELECT t1.ZPERSONID, total(t0.ZAMOUNT) 
FROM ZTRANSACTION t0 
     LEFT OUTER JOIN ZPERSON t1 ON t0.ZPERSON = t1.Z_PK 
WHERE (t0.ZDATE >= ? AND t0.ZDATE <= ?) GROUP BY t1.ZPERSONID 

Cheers,

Смежные вопросы