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)を行う – ザワプロ!