方法 : 内部結合を実行する (C# プログラミング ガイド)

更新 : 2007 年 11 月

リレーショナル データベース用語の内部結合では、2 番目のコレクション内の一致するすべての要素に対して、最初のコレクションの各要素が一度に表示される結果セットが生成されます。2 番目のコレクションと一致する要素が最初のコレクションにない場合、その要素は結果セットに表示されません。Join メソッドは、C# の join 句または Visual Basic の Join 句で呼び出され、内部結合を実装します。

このトピックでは、次の 4 種類の内部結合を実行する方法を示します。

  • 簡単なキーに基づいて、2 つのデータ ソースの要素を関連付ける単純な内部結合。

  • 複合キーに基づいて、2 つのデータ ソースの要素を関連付ける内部結合。複合キーは複数の値で構成され、複数のプロパティに基づいて要素を関連付けることができます。

  • 一連の結合操作が相互に連結された複数の結合。

  • グループ結合を使用して実装された内部結合。

使用例

簡単なキーの結合の例

次の例は、2 つのユーザー定義型 Person と Pet のオブジェクトが含まれた 2 つのコレクションを作成します。クエリは、C# の join 句または Visual Basic の Join 句を使用して、Person オブジェクトと、Owner がその Person の Pet オブジェクトが一致するかどうかを確認します。C# の select 句または Visual Basic の Select 句は、クエリ結果のオブジェクトの表示内容を定義します。この例では、クエリ結果のオブジェクトは、飼い主の姓とペットの名前で構成された匿名型です。

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Pet
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}

/// <summary>
/// Simple inner join.
/// </summary>
public static void InnerJoinExample()
{
    Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
    Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
    Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
    Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
    Person rui = new Person { FirstName = "Rui", LastName = "Raposo" };

    Pet barley = new Pet { Name = "Barley", Owner = terry };
    Pet boots = new Pet { Name = "Boots", Owner = terry };
    Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
    Pet bluemoon = new Pet { Name = "Blue Moon", Owner = rui };
    Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

    // Create two lists.
    List<Person> people = new List<Person> { magnus, terry, charlotte, arlene, rui };
    List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };

    // Create a collection of person-pet pairs. Each element in the collection
    // is an anonymous type containing both the person's name and their pet's name.
    var query = from person in people
                join pet in pets on person equals pet.Owner
                select new { OwnerName = person.FirstName, PetName = pet.Name };

    foreach (var ownerAndPet in query)
    {
        Console.WriteLine("\"{0}\" is owned by {1}", ownerAndPet.PetName, ownerAndPet.OwnerName);
    }
}

// This code produces the following output:
//
// "Daisy" is owned by Magnus
// "Barley" is owned by Terry
// "Boots" is owned by Terry
// "Whiskers" is owned by Charlotte
// "Blue Moon" is owned by Rui

LastName が "Huff" の Person オブジェクトは、Pet.Owner がその Person に等しい Pet オブジェクトがないため、結果セットに表示されません。

複合キーの結合の例

1 つのプロパティだけに基づいて要素を関連付ける代わりに、複合キーを使用して、複数のプロパティに基づいて要素を比較できます。これを行うには、各コレクションに対してキー セレクタ関数を指定し、比較するプロパティで構成された匿名型を返します。プロパティにラベルを付ける場合は、各キーの匿名型に同じラベルを付ける必要があります。また、プロパティは、同じ順序で表示する必要があります。

次の例は、Employee オブジェクトのリストと Student オブジェクトのリストを使用して、学生でもある社員を調べます。これらの型の両方に、String 型の FirstName プロパティと LastName プロパティがあります。それぞれのリストの要素から結合キーを作成する関数が、各要素の FirstName プロパティと LastName プロパティで構成された匿名型を返します。結合操作で、これらの複合キーが等しいかどうか比較され、それぞれのリストの氏名が一致するオブジェクトのペアが返されます。

class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int EmployeeID { get; set; }
}

class Student
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int StudentID { get; set; }
}

/// <summary>
/// Performs a join operation using a composite key.
/// </summary>
public static void CompositeKeyJoinExample()
{
    // Create a list of employees.
    List<Employee> employees = new List<Employee> {
        new Employee { FirstName = "Terry", LastName = "Adams", EmployeeID = 522459 },
         new Employee { FirstName = "Charlotte", LastName = "Weiss", EmployeeID = 204467 },
         new Employee { FirstName = "Magnus", LastName = "Hedland", EmployeeID = 866200 },
         new Employee { FirstName = "Vernette", LastName = "Price", EmployeeID = 437139 } };

    // Create a list of students.
    List<Student> students = new List<Student> {
        new Student { FirstName = "Vernette", LastName = "Price", StudentID = 9562 },
        new Student { FirstName = "Terry", LastName = "Earls", StudentID = 9870 },
        new Student { FirstName = "Terry", LastName = "Adams", StudentID = 9913 } };

    // Join the two data sources based on a composite key consisting of first and last name,
    // to determine which employees are also students.
    IEnumerable<string> query = from employee in employees
                                join student in students
                                on new { employee.FirstName, employee.LastName }
                                equals new { student.FirstName, student.LastName }
                                select employee.FirstName + " " + employee.LastName;

    Console.WriteLine("The following people are both employees and students:");
    foreach (string name in query)
        Console.WriteLine(name);
}

// This code produces the following output:
//
// The following people are both employees and students:
// Terry Adams
// Vernette Price

複数の結合の例

任意の数の結合操作を相互に連結して、複数の結合を実行できます。C# の各 join 句または Visual Basic の各 Join 句で、指定されたデータ ソースを前の結合の結果と関連付けます。

次の例は、Person オブジェクトのリスト、Cat オブジェクトのリスト、および Dog オブジェクトのリストの 3 つのコレクションを作成します。

最初の C# の join 句または Visual Basic の Join 句は、Person オブジェクトと Cat.Owner を照合して、飼い主と猫が一致するかどうかを確認します。この操作で、Person オブジェクトと Cat.Name が含まれた匿名型のシーケンスが返されます。

2 番目の、C# の join 句または Visual Basic の Join 句は、最初の結合で返された匿名型を、指定された犬のリストの Dog オブジェクトと関連付けます。この操作では、型が Person の Owner プロパティの複合キーと動物の名前の先頭の文字に基づいて関連付けが行われます。この操作で、一致するそれぞれのペアの Cat.Name プロパティと Dog.Name プロパティが含まれた匿名型のシーケンスが返されます。これは内部結合であるため、2 番目のデータ ソースと一致する、最初のデータ ソースのオブジェクトのみが返されます。

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Pet
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}

class Cat : Pet
{ }

class Dog : Pet
{ }

public static void MultipleJoinExample()
{
    Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
    Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
    Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
    Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };
    Person rui = new Person { FirstName = "Rui", LastName = "Raposo" };
    Person phyllis = new Person { FirstName = "Phyllis", LastName = "Harris" };

    Cat barley = new Cat { Name = "Barley", Owner = terry };
    Cat boots = new Cat { Name = "Boots", Owner = terry };
    Cat whiskers = new Cat { Name = "Whiskers", Owner = charlotte };
    Cat bluemoon = new Cat { Name = "Blue Moon", Owner = rui };
    Cat daisy = new Cat { Name = "Daisy", Owner = magnus };

    Dog fourwheeldrive = new Dog { Name = "Four Wheel Drive", Owner = phyllis };
    Dog duke = new Dog { Name = "Duke", Owner = magnus };
    Dog denim = new Dog { Name = "Denim", Owner = terry };
    Dog wiley = new Dog { Name = "Wiley", Owner = charlotte };
    Dog snoopy = new Dog { Name = "Snoopy", Owner = rui };
    Dog snickers = new Dog { Name = "Snickers", Owner = arlene };

    // Create three lists.
    List<Person> people =
        new List<Person> { magnus, terry, charlotte, arlene, rui, phyllis };
    List<Cat> cats =
        new List<Cat> { barley, boots, whiskers, bluemoon, daisy };
    List<Dog> dogs =
        new List<Dog> { fourwheeldrive, duke, denim, wiley, snoopy, snickers };

    // The first join matches Person and Cat.Owner from the list of people and
    // cats, based on a common Person. The second join matches dogs whose names start
    // with the same letter as the cats that have the same owner.
    var query = from person in people
                join cat in cats on person equals cat.Owner
                join dog in dogs on 
                new { Owner = person, Letter = cat.Name.Substring(0, 1) }
                equals new { dog.Owner, Letter = dog.Name.Substring(0, 1) }
                select new { CatName = cat.Name, DogName = dog.Name };

    foreach (var obj in query)
    {
        Console.WriteLine(
            "The cat \"{0}\" shares a house, and the first letter of their name, with \"{1}\".", 
            obj.CatName, obj.DogName);
    }
}

// This code produces the following output:
//
// The cat "Daisy" shares a house, and the first letter of their name, with "Duke".
// The cat "Whiskers" shares a house, and the first letter of their name, with "Wiley".

グループ結合を使用した内部結合の例

グループ結合を使用して内部結合を実装する方法を次の例に示します。

query1 で、Person オブジェクトのリストは、Pet.Owner プロパティと一致する Person に基づいて、Pet オブジェクトのリストにグループ結合されます。グループ結合によって、それぞれのグループが Person オブジェクトおよび一致する Pet オブジェクトのシーケンスで構成された、中間グループのコレクションが作成されます。

2 番目の from 句 (Visual Basic では From 句) をクエリに追加すると、シーケンスのこのシーケンスが、1 つの長いシーケンスに結合 (または平坦化) されます。最後のシーケンスの要素の型は、select 句 (Visual Basic では Select 句) で指定されます。この例では、この型は、一致する各ペアの Person.FirstName プロパティと Pet.Name プロパティで構成された匿名型です。

query1 の結果は、C# で into 句のない join 句を使用するか、または Visual Basic で Join 句を使用して内部結合を実行することにより得られる結果セットと同じです。query2 変数は、これと同等のクエリを示しています。

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class Pet
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}

/// <summary>
/// Performs an inner join by using GroupJoin().
/// </summary>
public static void InnerGroupJoinExample()
{
    Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
    Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
    Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
    Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

    Pet barley = new Pet { Name = "Barley", Owner = terry };
    Pet boots = new Pet { Name = "Boots", Owner = terry };
    Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
    Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
    Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

    // Create two lists.
    List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
    List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };

    var query1 = from person in people
                 join pet in pets on person equals pet.Owner into gj
                 from subpet in gj
                 select new { OwnerName = person.FirstName, PetName = subpet.Name };

    Console.WriteLine("Inner join using GroupJoin():");
    foreach (var v in query1)
    {
        Console.WriteLine("{0} - {1}", v.OwnerName, v.PetName);
    }

    var query2 = from person in people
                 join pet in pets on person equals pet.Owner
                 select new { OwnerName = person.FirstName, PetName = pet.Name };

    Console.WriteLine("\nThe equivalent operation using Join():");
    foreach (var v in query2)
        Console.WriteLine("{0} - {1}", v.OwnerName, v.PetName);
}

// This code produces the following output:
//
// Inner join using GroupJoin():
// Magnus - Daisy
// Terry - Barley
// Terry - Boots
// Terry - Blue Moon
// Charlotte - Whiskers
//
// The equivalent operation using Join():
// Magnus - Daisy
// Terry - Barley
// Terry - Boots
// Terry - Blue Moon
// Charlotte - Whiskers

コードのコンパイル方法

  • Visual Studio で新しいコンソール アプリケーション プロジェクトを作成します。

  • System.Core.dll がまだ参照されていない場合は、System.Core.dll への参照を追加します。

  • System.Linq 名前空間を含めます。

  • 例からコードをコピーし、program.cs ファイルの Main メソッドの下に貼り付けます。貼り付けたメソッドを呼び出すコード行を Main メソッドに追加します。

  • プログラムを実行します。

参照

処理手順

方法 : グループ化結合を実行する (C# プログラミング ガイド)

方法 : 左外部結合を実行する (C# プログラミング ガイド)

概念

結合演算

匿名型

参照

Join

GroupJoin

匿名型 (C# プログラミング ガイド)