2011-01-20 24 views
5

CoreDataで基本的なクエリを書く方法を探していますが、ドキュメントには例がありません。以下は私のクエリです:CoreDataクエリのヘルプ

  1. 私はExpenseオブジェクトを持っていて、それにはexpenseAmountフィールドがあります。
  2. 費用は、ExpenseCategoryオブジェクトにリンクできます。
  3. 費用は、費用のカテゴリ(例:食品)を定義するだけでも、単価(例:マイレージ)を設定することもできます。単なる名前の場合、費用値はExpenseオブジェクトのexpenseAmountであり、それ以外の場合はExpenseCategoryのexpenseAmount * unitRateです。
  4. 費用への費用のリンクはオプションであるため、最終的な費用はカテゴリの有無と単価に基づいています。

だから、総費用を計算するためのSQLクエリは次のようになります。これはCoreDataで

select 
    TOTAL(e.amount * IFNULL(c.rate, 1)) 
from EXPENSE e 
LEFT OUTER join CATEGORY c on 
    e.category = c.id 

を行うことができますか?

+0

ありがとうございます。私も同様の問題があり、NSExpressionは私のためには機能しませんでした - 私は倍精度とタイムスタンプで作業しています。何らかの理由でdivide:by:関数が奇妙な結果を生成します。あなたの最終的な解決策については私の計算に複数のレコードを含める必要があるので、私は興味があります。 –

答えて

2

簡単な解決策は、適切に計算された金額を与えるExpenseクラスの別のメソッドを実装することです。

など。

- (NSDecimalNumber *) calculatedExpenseAmount { 

    NSDecimalNumber *actualAmount = self.expenseAmount; 

    // Pseudo-code begins 
    if (self.expenseCategory != nil) { 
    actualAmount = self.expenseAmount * self.expenseCategory.unitRate; 
    } 

    return actualAmount; 
} 

私は私の前の回答にに追加しています。

すべての管理オブジェクトを取得しないようにするには、NSDictionary-resultクエリを使用して、expenseAmountおよびexpenseCategory.unitRate値を引き出すことができます。

- (NSDecimalNumber *) totalExpenses 
{ 
    // Fetch all of the expense amounts and unit rate of any related category. 

    NSFetchRequest *request = ...; 
    [request setManagedObjectContext:<...>]; 
    [request setEntity:<ExpenseAccountDescription>]; 
    [request setResultType:NSDictionaryResultType]; 
    NSArray *props = [NSArray arrayWithObjects:@"expenseAmount", @"category.unitRate", nil]; 
    [request setPropertiesToFetch:props]; 

    NSArray *amounts = [request executeRequest:...]; 
    // amounts is an array of dictionaries, each hold the desired property values. 

    // Loop and sum the individual amounts 

    NSDecimal *total = [[NSDecimalNumber zero] decimalNumber]; 
    NSAutoreleasePool *pool = nil; // contain the mess 

    NSCalculationError err = NSCalculationNoError; 

    for (NSDictionary *result in amounts) 
    { 
     pool = [NSAutoreleasePool new]; 

     NSDecimal newTotal = [[NSDecimalNumber zero] decimalNumber]; 
     NSDecimalNumber *expenseAmount = [result valueForKeyPath:@"expenseAmount"]; 
     NSDecimalNumber *unitRate = [result valueForKeyPath:@"category.unitRate"]; 

     if (unitRate != nil) { 
      // do the unit rate multiplication and accumulate the result in the total 

      NSDecimal calculated = [[NSDecimalNumber zero] decimalNumber]; 
      err = NSDecimalMultiply (&calculated, [expenseAmount decimalNumber], [unitRate decimalNumber], NSRoundBankers); 
      if (err == NSCalculationNoError) { 
       err = NSDecimalAdd (&newTotal, total, calculated, NSRoundBankers); 
      } 
     } 
     else { 
      // just accumulate the result in the total 

      err = NSDecimalAdd (&newTotal, total, [expenseAmount decimalNumber], NSRoundBankers); 
     } 

     // Keep the new total 
     NSDecimalCopy(&total, newTotal); 

     [pool drain]; 
    } 

    return [NSDecimalNumber decimalNumberWithDecimal:total]; 
} 

費用エントリが10000件ある場合、このフェッチと計算には1MB未満のRAMが必要です。インストゥルメントはそれを測定する際にあなたの友人となります

+0

これは単一の費用のために働くでしょう。私はDB内のすべての経費を照合して、それらのすべてをメモリに読み込まずにしようとしています。 – siasl

+0

助けてくれてありがとう。私は乗算を使用してみました:by:NSExpressionクラスからsqlite自体でこの計算を行う。シミュレータはRT例外を投げたので、まだiPhoneでは利用できません。私がここで理解していないことは、CoreDataがそのような単純なことを支持しない理由です。うん、私はCDがオブジェクトグラフの観点から考えていることを知っています。 – siasl

+0

私はCDに任意のSQLを実行させる方法がないと確信しています。もしあなたが本当に永続的であれば、SQLiteに直接行くことができます。それはあなたがしたいすべてのものをサポートしています。 –