임의의 수의 열을 가진 DataTable
의 쌍이 있고 DataTable
두 개 각각에서 적절한 유형의 그룹화 값을 생성 할 수있는 함수가 있으면 Linq를 사용하여 대부분의 작업을 수행 할 수 있습니다. 당신.
DataTable
에서 조인 키를 추출하는 기능부터 시작해 보겠습니다. object[]
을 반환하는 것이 좋겠지 만 비교가 잘되지 않습니다. 그러나 우리는 Tuple<object, object>
으로 처리 할 수 있습니다. 더 많은 열이 필요하면 열을 더 추가하면됩니다. P
// Produces a JoinKey as Tuple containing columns 'A' and 'C' (0 and 2)
public Tuple<object, object> GetJoinKey(DataRow row)
{
return Tuple.Create(row[0], row[2]);
}
이제 조인을하십시오. 우리는 완전 외부에 직접 가입 할 수는 없지만, 우리는 외부 두 가지와 Union
결과에 가입 할 수 있습니다까지 당신이 적당한 출력 형식을 만들 필요가
// given DataTables table1 & table2:
var outerjoin =
(
from row1 in table1.AsEnumerable()
join row2 in table2.AsEnumerable()
on GetJoinKey(row1) equals GetJoinKey(row2)
into matches
from row2 in matches.DefaultIfEmpty()
select new { key = GetJoinKey(row1), row1, row2 }
).Union(
from row2 in table2.AsEnumerable()
join row1 in table1.AsEnumerable()
on GetJoinKey(row2) equals GetJoinKey(row1)
into matches
from row1 in matches.DefaultIfEmpty()
select new { key = GetJoinKey(row2), row1, row2 }
);
다음 - 모든 행이있는 DataTable
을 두 소스, 플러스 필드에서 키에 대한 몇 가지 정보 보유 : C의
var row1def = new object[table1.Columns.Count];
var row2def = new object[table2.Columns.Count];
foreach (var src in outerjoin)
{
// extract values from each row where present
var data1 = (src.row1 == null ? row1def : src.row1.ItemArray);
var data2 = (src.row2 == null ? row2def : src.row2.ItemArray);
// create row with key string and row values
result.Rows.Add(new object[] { src.key.ToString() }.Concat(data1).Concat(data2).ToArray());
}
:
DataTable result = new DataTable();
// add column for string value of key:
result.Columns.Add("__key", typeof(string));
// add columns from table1:
foreach (var col in table1.Columns.OfType<DataColumn>())
result.Columns.Add("T1_" + col.ColumnName, col.DataType);
// add columns from table2:
foreach (var col in table2.Columns.OfType<DataColumn>())
result.Columns.Add("T2_" + col.ColumnName, col.DataType);
마지막을 쿼리에서 테이블을 채우기 우리는 우리에게 99 %의 작업을 수행하는 단일 Linq 쿼리를 얻기 위해 몇 가지 작업을 단락시킬 수 있습니다. 나는 재미있게 들릴지 모르겠지만, 너와 함께 놀아 두겠다.
여기에 합리적으로 일반적인 제작, 조인 키 생성기에 대한 일반적인 기능 확장으로 수행 전체 방법입니다 : 이제
public static DataTable FullOuterJoin<T>(this DataTable table1, DataTable table2, Func<DataRow, T> keygen)
{
// perform inital outer join operation
var outerjoin =
(
from row1 in table1.AsEnumerable()
join row2 in table2.AsEnumerable()
on keygen(row1) equals keygen(row2)
into matches
from row2 in matches.DefaultIfEmpty()
select new { key = keygen(row1), row1, row2 }
).Union(
from row2 in table2.AsEnumerable()
join row1 in table1.AsEnumerable()
on keygen(row2) equals keygen(row1)
into matches
from row1 in matches.DefaultIfEmpty()
select new { key = keygen(row2), row1, row2 }
);
// Create result table
DataTable result = new DataTable();
result.Columns.Add("__key", typeof(string));
foreach (var col in table1.Columns.OfType<DataColumn>())
result.Columns.Add("T1_" + col.ColumnName, col.DataType);
foreach (var col in table2.Columns.OfType<DataColumn>())
result.Columns.Add("T2_" + col.ColumnName, col.DataType);
// fill table from join query
var row1def = new object[table1.Columns.Count];
var row2def = new object[table2.Columns.Count];
foreach (var src in outerjoin)
{
// extract values from each row where present
var data1 = (src.row1 == null ? row1def : src.row1.ItemArray);
var data2 = (src.row2 == null ? row2def : src.row2.ItemArray);
// create row with key string and row values
result.Rows.Add(new object[] { src.key.ToString() }.Concat(data1).Concat(data2).ToArray());
}
return result;
}
, 테이블이 같은 스키마를 (이 경우 어떤 위 아무튼 ' T는 신경 쓰지 않는다면 거의 똑같은 일을 할 수있다. 결과 테이블 생성을 수정하여 테이블 중 하나를 복제 한 다음로드 루프에 병합 로직을 추가한다.
Here's a Gist 위의 내용은 테스트와 검증을 통해 확인되었습니다. 컴파일러에서 그 것을 버리고 나간다.
정말 완전 결합입니까, 병합입니까? – Corey
*는 하드 코딩 된 SQL 문과 같습니다. * <--- 그리고 SQL 문을 포함하는 문자열 리터럴은 무엇입니까? –
@Corey : 전체 외부 조인이 필요합니다 (두 워크 시트의 누락 된 데이터에 대해 null이 표시됨). – JessStuart