【C#/LINQ】GroupJoinメソッドを使って外部結合を行う

By | 2012年5月9日

LINQのGroupJoinメソッドを使って、SQLの外部結合に相当するデータ操作を行ってみよう。
以下のようなテーブルデータがあるとして、それを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

前回の内部結合の例と違うのは、
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

このように、内部結合では結合条件に合致しないデータは結果から除かれる。
左側のデータを残しつつ結合した結果を得たいときは外部結合を使う。

それでは、プログラムを見ていこう。

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

【C#/LINQ】GroupJoinメソッドを使って外部結合を行う」への1件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です