내부 조인 수행
관계형 데이터베이스 용어에서 내부 조인은 첫 번째 컬렉션의 각 요소가 두 번째 컬렉션에서 일치하는 모든 요소에 대해 한 번 표시되는 결과 집합을 생성합니다. 첫 번째 컬렉션의 요소에 일치하는 요소가 없는 경우에는 결과 집합에 표시되지 않습니다. C#에서 join
절에 의해 호출되는 Join 메서드는 내부 조인을 구현합니다.
이 문서에서는 내부 조인의 네 가지 변환을 수행하는 방법을 보여 줍니다.
단순 키에 따라 두 데이터 소스의 요소를 상호 연결하는 간단한 내부 조인
복합 키에 따라 두 데이터 소스의 요소를 상호 연결하는 내부 조인. 둘 이상의 값으로 구성된 키인 복합 키를 사용하면 둘 이상의 속성에 따라 요소를 상호 연결할 수 있습니다.
연속 조인 작업이 서로 추가되는 여러 조인
그룹 조인을 사용하여 구현되는 내부 조인
참고
이 항목의 예제에서는 다음 데이터 클래스를 사용합니다.
record Person(string FirstName, string LastName);
record Pet(string Name, Person Owner);
record Employee(string FirstName, string LastName, int EmployeeID);
record Cat(string Name, Person Owner) : Pet(Name, Owner);
record Dog(string Name, Person Owner) : Pet(Name, Owner);
및 개체 컬렉션Student
쿼리의 클래스입니다.
예제 - 단순 키 조인
다음 예제에서는 두 개의 사용자 정의 형식인 Person
및 Pet
의 개체를 포함하는 두 개의 컬렉션을 만듭니다. 쿼리는 C#의 join
절을 사용하여 Person
개체를 Owner
가 해당 Person
인 Pet
개체와 일치시킵니다. C#의 select
절은 결과 개체의 모양을 정의합니다. 이 예제에서 결과 개체는 소유자의 이름과 애완 동물의 이름으로 구성된 무명 형식입니다.
Person magnus = new(FirstName: "Magnus", LastName: "Hedlund");
Person terry = new("Terry", "Adams");
Person charlotte = new("Charlotte", "Weiss");
Person arlene = new("Arlene", "Huff");
Person rui = new("Rui", "Raposo");
List<Person> people = new() { magnus, terry, charlotte, arlene, rui };
List<Pet> pets = new()
{
new(Name: "Barley", Owner: terry),
new("Boots", terry),
new("Whiskers", charlotte),
new("Blue Moon", rui),
new("Daisy", magnus),
};
// 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($"\"{ownerAndPet.PetName}\" is owned by {ownerAndPet.OwnerName}");
}
/* 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
개체가 없기 때문에 결과 집합에 표시되지 않습니다.
예제 - 복합 키 조인
속성 하나만 기준으로 요소를 상호 연결하는 대신 복합 키를 사용하여 여러 속성을 기준으로 요소를 비교할 수 있습니다. 이렇게 하려면 비교하려는 속성으로 구성된 무명 형식을 반환할 각 컬렉션에 대한 키 선택기 함수를 지정합니다. 속성에 레이블을 지정하는 경우 각 키의 무명 형식에 동일한 레이블이 있어야 합니다. 또한 속성은 동일한 순서로 나타나야 합니다.
다음 예제에서는 Employee
개체 목록과 Student
개체 목록을 사용하여 학생이기도 한 직원을 확인합니다. 이러한 형식에는 둘 다 String 형식의 FirstName
및 LastName
속성이 있습니다. 각 목록의 요소에서 조인 키를 만드는 함수는 각 요소의 FirstName
및 LastName
속성으로 구성된 무명 형식을 반환합니다. 조인 작업은 이러한 복합 키가 같은지 비교하고 각 목록에서 이름과 성이 둘 다 일치하는 개체 쌍을 반환합니다.
List<Employee> employees = new()
{
new(FirstName: "Terry", LastName: "Adams", EmployeeID: 522459),
new("Charlotte", "Weiss", 204467),
new("Magnus", "Hedland", 866200),
new("Vernette", "Price", 437139)
};
List<Student> students = new()
{
new(FirstName: "Vernette", LastName: "Price", StudentID: 9562),
new("Terry", "Earls", 9870),
new("Terry", "Adams", 9913)
};
// Join the two data sources based on a composite key consisting of first and last name,
// to determine which employees are also students.
var 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);
}
/* Output:
The following people are both employees and students:
Terry Adams
Vernette Price
*/
예제 - 여러 조인
개수에 제한없이 조인 작업을 서로 추가하여 여러 조인을 수행할 수 있습니다. C#의 각 join
절은 지정된 데이터 소스를 이전 조인의 결과와 상호 연결합니다.
다음 예제에서는 Person
개체 목록, Cat
개체 목록, Dog
개체 목록의 세 가지 컬렉션을 만듭니다.
C#의 첫 번째 join
절은 Cat.Owner
와 일치하는 Person
을 기준으로 사람과 고양이를 일치시킵니다. Person
개체 및 Cat.Name
을 포함하는 무명 형식의 시퀀스를 반환합니다.
C#의 두 번째 join
절은 Person
형식의 Owner
속성과 동물 이름의 첫 글자로 구성된 복합 키를 기준으로 제공된 개 목록의 Dog
개체와 첫 번째 조인에서 반환된 무명 형식을 상호 연결합니다. 일치하는 각 쌍의 Cat.Name
및 Dog.Name
속성을 포함하는 무명 형식의 시퀀스를 반환합니다. 내부 조인이기 때문에 두 번째 데이터 소스에 일치 항목이 있는 첫 번째 데이터 소스의 개체만 반환됩니다.
Person magnus = new(FirstName: "Magnus", LastName: "Hedlund");
Person terry = new("Terry", "Adams");
Person charlotte = new("Charlotte", "Weiss");
Person arlene = new("Arlene", "Huff");
Person rui = new("Rui", "Raposo");
Person phyllis = new("Phyllis", "Harris");
List<Person> people = new() { magnus, terry, charlotte, arlene, rui, phyllis };
List<Cat> cats = new()
{
new(Name: "Barley", Owner: terry),
new("Boots", terry),
new("Whiskers", charlotte),
new("Blue Moon", rui),
new("Daisy", magnus),
};
List<Dog> dogs = new()
{
new(Name: "Four Wheel Drive", Owner: phyllis),
new("Duke", magnus),
new("Denim", terry),
new("Wiley", charlotte),
new("Snoopy", rui),
new("Snickers", arlene),
};
// 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 \"{obj.CatName}\" shares a house, and the first letter of their name, with \"{obj.DogName}\"."
);
}
/* 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
절을 쿼리에 추가하여 이 시퀀스의 시퀀스를 더 긴 시퀀스에 결합(또는 평면화)할 수 있습니다. 최종 시퀀스의 요소 형식은 select
절에 의해 지정됩니다. 이 예제에서 해당 형식은 일치하는 각 쌍의 Person.FirstName
및 Pet.Name
속성으로 구성된 무명 형식입니다.
query1
의 결과는 into
절 없이 join
절을 사용해서 내부 조인을 수행하여 얻은 결과 집합과 같습니다. query2
변수는 이와 동일한 쿼리를 보여 줍니다.
Person magnus = new(FirstName: "Magnus", LastName: "Hedlund");
Person terry = new("Terry", "Adams");
Person charlotte = new("Charlotte", "Weiss");
Person arlene = new("Arlene", "Huff");
List<Person> people = new() { magnus, terry, charlotte, arlene };
List<Pet> pets = new()
{
new(Name: "Barley", Owner: terry),
new("Boots", terry),
new("Whiskers", charlotte),
new("Blue Moon", terry),
new("Daisy", magnus),
};
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($"{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();
Console.WriteLine("The equivalent operation using Join():");
foreach (var v in query2)
{
Console.WriteLine($"{v.OwnerName} - {v.PetName}");
}
/* 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
*/