2012/09/01

【LINQ】LEFT OUTER JOIN(左外部結合)の話【C#】

 まぁ、MSDN(方法 : 左外部結合を実行する)見りゃ分かる話ですが一応メモっときます。単純な内部結合の場合は「join~on~equals~」でOKですが、相手先が存在しないの場合でもレコードを取得したい場合は左外部結合が必要となります。
 とりあえずサンプルデータ。
Users
ID Name
1
Yamada
2
Tanaka
Cards
ID UserId CardNo
1
1
999999

 相変わらず手抜きなデータですが、見ての通りUsersテーブルには2つのレコードがありますが、Cardsテーブルに一つのレコードしかありません。
 これを内部結合すると…。
コード
from p in Users
join g in Cards
on p.Id equals g.UserId
select new
{
    p.Id,
    p.Name,
    g.CardNo
};

結果
IDNameCardNo

1

Yamada

999999


 当然ながら結合可能なのはYamadaさんのみなのでそれしか表示されません。んでここから本題。Cardsテーブルが結合できんくてもとにかくUsersテーブルにあるレコードは全件引っ張りたいんだけどって場合にどうするかという話です。そこで登場するのがLEFT OUTER JOIN(左外部結合)ってわけです(何か話がSQLの初歩をやってる感じになってますが、まぁいいかってことで…)。

 LINQで左外部結合を実現する場合、簡単に言ってしまえばDefaultIfEmptyメソッドを利用し、存在しないものにnull値を割り当ててもらっちゃいます(こんな表現で正しいのか?)。

 早速、実験します。

コード
from p in Users
join g in Cards
on p.Id equals g.UserId into gg
from ggg in gg.DefaultIfEmpty()
select new
{
    p.Id,
    p.Name,
    CardNo = (ggg != null ? ggg.CardNo : null)
};

結果
IDNameCardNo

1

Yamada

999999

2

Tanaka

(null)


 この結果って<table>タグで書いてるだけなんで「ほらできた」って言うわけにはいきませんが…。ggとかgggとかってなんやねん?って感じですが、他に良い書き方が思いつかなかったので…。into句とDefaultIfEmptyメソッドを使うことでgggにはUsersテーブルに対して結合されるレコードと存在しないものには初期値が用意されるわけです。その後、select句でnull値を判定することでCardNoにCardNoかnullを代入してます。

 以上、LINQでLEFT OUTER JOIN(左外部結合)を利用する方法でした。
pagetop