방법: 내부 조인 수행(C# 프로그래밍 가이드)
업데이트: 2007년 11월
관계형 데이터베이스에서 말하는 내부 조인이란 첫 번째 컬렉션의 각 요소가 두 번째 컬렉션에서 일치하는 모든 요소에 대해 한 번만 표시되는 결과 집합을 생성하는 것입니다. 첫 번째 컬렉션의 요소와 일치하는 요소가 없는 경우 해당 요소가 결과 집합에 표시되지 않습니다. Join 메서드는 C#의 join 절에 의해 호출되거나 Visual Basic의 Join 절에 의해 호출되어 내부 조인을 구현합니다.
이 항목에서는 다음과 같은 내부 조인의 네 가지 변형을 수행하는 방법을 보여 줍니다.
간단한 키를 기준으로 두 데이터 소스의 요소를 연관시키는 간단한 내부 조인
복합 키를 기준으로 두 데이터 소스의 요소를 연관시키는 내부 조인. 둘 이상의 값으로 구성된 복합 키를 사용하면 둘 이상의 속성을 기준으로 요소를 연관시킬 수 있습니다.
연속된 조인 작업이 서로에게 추가되는 여러 조인
그룹 조인을 사용하여 구현된 내부 조인
예제
간단한 키 조인 예제
다음 예제에서는 두 사용자 정의 형식(Person 및 Pet)의 개체를 포함하는 두 컬렉션을 만듭니다. 쿼리에서는 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
Person에 일치하는 Pet.Owner를 갖는 Pet 개체가 없으므로 LastName이 "Huff"인 Person 개체는 결과 집합에 나타나지 않습니다.
복합 키 조인 예제
하나의 속성을 기준으로 요소를 연관시키는 대신에 복합 키를 사용하여 여러 가지 속성을 기준으로 요소를 비교할 수 있습니다. 이를 위해 각 컬렉션에서 사용자가 비교할 속성으로 구성된 익명 형식을 반환하도록 키 선택기 함수를 지정합니다. 속성에 레이블을 지정하는 경우 각 키의 익명 형식에 동일한 레이블을 가져야 합니다. 또한 속성은 동일한 순서로 나타나야 합니다.
다음 예제에서는 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 개체 목록을 만듭니다.
C#의 첫 번째 join 절 또는 Visual Basic의 Join 절에서는 Cat.Owner에 일치하는 Person을 기준으로 사람과 고양이를 나열합니다. Person 개체와 Cat.Name을 포함하는 익명 형식의 시퀀스를 반환합니다.
C#의 두 번째 join 절 또는 Visual Basic의 Join 절은 Person 형식의 Owner 속성 및 동물 이름의 처음 문자로 구성된 복합 키를 기준으로 첫 번째 조인에서 반환된 익명 형식을 제공된 개 목록에 있는 Dog 개체와 연관시킵니다. 일치하는 각 쌍에서 Cat.Name 및 Dog.Name 속성을 포함하는 익명 형식의 시퀀스를 반환합니다. 이 조인은 내부 조인이므로 두 번째 데이터 소스에 일치하는 항목이 있는 첫 번째 데이터 소스의 해당 개체만 반환됩니다.
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 개체의 시퀀스로 구성된 중간 그룹의 컬렉션을 만듭니다.
쿼리에 두 번째 from 절(Visual Basic에서는 From 절)을 추가하여 시퀀스의 해당 시퀀스를 보다 긴 시퀀스에 결합합니다. 마지막 시퀀스 요소의 형식은 select 절(Visual Basic에서는 Select 절)에 의해 지정됩니다. 이 예제에서 형식은 Person.FirstName 및 일치하는 각 쌍에 대한 Pet.Name 속성으로 구성된 익명 형식입니다.
query1의 결과는 내부 조인을 수행하기 위해 C#의 into 절 또는 Visual Basic의 Join 절을 사용하지 않고 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.Linq 네임스페이스를 포함합니다.
예제에서 코드를 복사하여 Main 메서드 아래의 program.cs 파일에 붙여넣습니다. Main 메서드에 코드 줄을 추가하여 붙여넣은 메서드를 호출합니다.
프로그램을 실행합니다.