SUBQUERYを使って
CoreDataで対多関連を検索
@masaichi
自己紹介
• 市川 勝
• Twitter: @masaichi, github: @masarusanjp
• エンジニア (love obj-c, ruby)
• iOSアプリを仕事で開発してます
よろしくお願いします
SUBQUERYとは?
CoreDataで、
あるエンティティの対多関連に対する
副問い合わせをするための構文
リファレンス
• NSExpression Class Referenceに書いてある
(not NSPredicate)
• https://developer.apple.com/library/ios/
documentation/cocoa/reference/
foundation/Classes/NSExpression_Class/
Reference/NSExpression.html
構文
SUBQUERY(
collection_expression,
variable_expression,
predicate
)
構文
[NSPredicate predicateWithFormat:@
SUBQUERY(
collection_expression,
variable_expression,
predicate
).@count == 0
];
構文
[NSPredicate predicateWithFormat:@
SUBQUERY(
collection_expression,
variable_expression,
predicate
).@count == 0
];
<- コレクションとして扱われる
例
アルバムと曲の関連について
レーティングが1以上、4以下
の曲を含むアルバムを検索
[NSPredicate predicateWithFormat:

@ SUBQUERY(songs, 

$s, 

$s.rating >= 1 AND 

$s.rating <= 4

).@count > 0 

];
レーティングが1以上、4以下
の曲を含むアルバムを検索
[NSPredicate predicateWithFormat:

@ SUBQUERY(songs, <- 関連の名前 

$s, 

$s.rating >= 1 AND 

$s.rating <= 4

).@count > 0 

];
レーティングが1以上、4以下
の曲を含むアルバムを検索
[NSPredicate predicateWithFormat:

@ SUBQUERY(songs, 

$s, <- 条件内で使う変数名

$s.rating >= 1 AND 

$s.rating <= 4

).@count > 0 

];
レーティングが1以上、4以下
の曲を含むアルバムを検索
[NSPredicate predicateWithFormat:

@ SUBQUERY(songs, 

$s, 

$s.rating >= 1 AND 

$s.rating <= 4

).@count > 0 

];
レーティングが1以上、4以下
の曲を含むアルバムを検索
<- 条件
レーティングが1以上、4以下
の曲を含むアルバムを検索
[NSPredicate predicateWithFormat:

@ SUBQUERY(songs, 

$s, 

$s.rating >= 1 AND 

$s.rating <= 4

).@count > 0 <- 評価 

];
なんで使うの?
ANYでも出来ないの?
レーティングが1以上、4以下
の曲を含むアルバムを検索
[NSPredicate predicateWithFormat:

@ ANY songs.rating >= 1 AND 

ANY songs.rating <= 4 

];
レーティングが1以上、4以下
の曲を含むアルバムを検索
SELECT DISTINCT 0, t0.Z_PK FROM ZALBUM t0

JOIN ZSONG t1 ON t0.Z_PK = t1.ZALBUM

JOIN ZSONG t2 ON t0.Z_PK = t2.ZALBUM

WHERE ( t1.ZRATING >= ? AND t2.RATING <= ?)
[NSPredicate predicateWithFormat:

@ SUBQUERY(songs, 

$s, 

$s.rating >= 1 AND 

$s.rating <= 4

).@count > 0 

];
レーティングが1以上、4以下
の曲を含むアルバムを検索
レーティングが1以上、4以下
の曲を含むアルバムを検索
SELECT 0, t0.Z_PK FROM ZALBUM t0
WHERE (
SELECT COUNT(t1.Z_PK) FROM ZSONG t1
WHERE (
t0.Z_PK = t1.ZALBUM AND
(( t1.ZRATING >= ? AND t1.ZRATING <= ?))
)
) > ?
まとめ
• SUBQUERYを使うと対多関連に対して、副問い
合わせが出来る
• 同じ関連に対する条件が複数ある場合、
SUBQUERYを使わないとうまくいかない
• 道具の1つとして状況に応じて使いましょう
• もっと良い表現があれば教えてください
サンプルコード
• https://github.com/masarusanjp/
CoreDataPredicateDemo
• 実行時引数に

「-com.apple.CoreData.SQLDebug 1」

をつけるとSQLが吐かれます
サンプルコード
• https://github.com/masarusanjp/
CoreDataPredicateDemo
• 実行時引数に

「-com.apple.CoreData.SQLDebug 1」

をつけるとSQLが吐かれます
ありがとうございました

CoreDataでのsubqueryの使い方