LINQのGroupJoin()メソッドを使って、SQLの外部結合(outer join)に相当するデータ操作を行ってみよう。以下のようなテーブルデータがあるとして、それをLINQで結合してみることにする。
Persons
| Id | Name | Age | JobId |
|---|---|---|---|
| 1 | John | 56 | 1 |
| 2 | Mike | 23 | NULL |
| 3 | Ken | 64 | 2 |
| 4 | Alice | 41 | 4 |
| 5 | Tom | 22 | NULL |
Jobs
| Id | Name |
|---|---|
| 1 | Programmer |
| 2 | Engineer |
| 3 | Sportman |
| 4 | King |
| 5 | Slave |
前回の内部結合(inner join)の例と違うのは、PersonsテーブルのJobIdにNULLの場合があることである。
まず、この例を Persons.JobId と Jobs.Id で内部結合した場合について示す。結果は以下のようになる。
PersonId:1 Name:John Age:56 Job:Programmer
PersonId:3 Name:Ken Age:64 Job:Engineer
PersonId:4 Name:Alice Age:41 Job:King
このように、内部結合(inner join)では結合条件に合致しないデータは結果から除かれる。
これに対し、以下のように左側のデータを残しつつ結合した結果を得たいときは外部結合(outer join)を使う。
PersonId:1 Name:John Age:56 Job:Programmer
PersonId:2 Name:Mike Age:23 Job:Null
PersonId:3 Name:Ken Age:64 Job:Engineer
PersonId:4 Name:Alice Age:41 Job:King
PersonId:5 Name:Tom Age:22 Job:Null
それでは、プログラムを見ていこう。
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LinqJoinLessonOuter
{
class Program
{
class Person
{
public int Id { get; set; }
public String Name { get; set; }
public int Age { get; set; }
public int? JobId { get; set; }
}
class Job
{
public int Id { get; set; }
public String Name { get; set; }
}
static void Main(string[] args)
{
var persons = new Person[]{
new Person{ Id = 1,Name = "John", Age = 56, JobId = 1},
new Person{ Id = 2,Name = "Mike", Age = 23, JobId = null},
new Person{ Id = 3,Name = "Ken", Age = 64, JobId = 2},
new Person{ Id = 4,Name = "Alice", Age = 41, JobId = 4},
new Person{ Id = 5,Name = "Tom", Age = 22, JobId = null},
};
var jobs = new Job[] {
new Job{ Id = 1, Name = "Programmer" },
new Job{ Id = 2, Name = "Engineer" },
new Job{ Id = 3, Name = "Sportman" },
new Job{ Id = 4, Name = "King" },
new Job{ Id = 5, Name = "Slave" }
};
// 外部結合を行うメソッド式
var outerJoin =
persons.GroupJoin(jobs, p => p.JobId, j => j.Id, (p, j) => new
{
PersonId = p.Id,
Name = p.Name,
Age = p.Age,
Jobs = j.DefaultIfEmpty()
})
.SelectMany(x => x.Jobs, (x, j) => new
{
PersonId = x.PersonId,
Name = x.Name,
Age = x.Age,
JobName = j != null ? j.Name : "<unemployed>"
});
foreach (var j in outerJoin)
{
Console.WriteLine(
"PersonId:{0}\tName:{1}\tAge:{2}\tJob:{3}", j.PersonId, j.Name, j.Age, j.JobName);
}
}
}
}
PersonsクラスのJobIdは、nullを使うためnull許容型とした。
プログラムの実行結果は以下のようになった。
PersonId:1 Name:John Age:56 Job:Programmer
PersonId:2 Name:Mike Age:23 Job:<unemployed>
PersonId:3 Name:Ken Age:64 Job:Engineer
PersonId:4 Name:Alice Age:41 Job:King
PersonId:5 Name:Tom Age:22 Job:<unemployed>
続行するには何かキーを押してください . . .
参考に、以上の操作をクエリ式で書いた場合とSQLで書いた場合について示す。
クエリ式
var outerJoin =
from p in persons
join j in jobs on p.JobId equals j.Id into gs
from g in gs.DefaultIfEmpty()
select new { PersonId = p.Id, Name = p.Name, Age = p.Age, JobName = g != null ? g.Name : "<unemployed>" };
SQL
SELECT
p.Id AS PersonID
p.Name AS Name
p.Age AS Age
j.Name As JobName
FROM
Persons AS p
LEFT OUTER JOIN
Jobs AS j
ON p.JobId = j.Id
これだと、Groupの機能が使われてませんね。
ピンバック: 【C#/LINQ】Join()を使って内部結合(inner join)を行う – ザワプロ!