C#에서 DataTable.Compute
메서드는 string
형식의 컬럼을 직접 합산할 때 "집계 함수 sum() 및 형식 string 사용이 잘못되었습니다"가 발생합니다.
Compute
는 숫자 데이터에만 적용되기 때문에, GroupBy
와 Select
구조를 사용할 때, string
형식의 데이터를 숫자로 변환한 후 합산하는 방식이 필요해요.
해당 오류가 발생하는 여러가지 케이스가 있을 텐데요, 이번 예제에서는 GroupBy와 Select 시 발생하는 예제를 다루어 볼게요.
해결 방법
int.TryParse
로 string
컬럼을 숫자로 변환한 뒤 합산하는 방법을 사용할 수 있습니다. 아래 예제는 DataTable
내 string
형식의 컬럼을 그룹별로 합산하는 방식으로, 숫자가 아닌 값이 있어도 오류를 방지하고 그룹 합계를 계산할 수 있도록 해보았어요.
예제 코드: DataTable
에서 부서별 SAL
과 COMM
합산하기
Oracle의 EMP
테이블을 기반으로 DataTable
을 만들고, DEPTNO
별 SAL
(급여) 및 COMM
(커미션) 컬럼을 그룹 합산합니다. 각 컬럼은 string
형식으로 저장되며, 합산 시 숫자로 변환하여 계산됩니다. *샐러리와 커미션을 스트링으로 하였습니다~
using System;
using System.Data;
using System.Linq;
public class Program
{
public static void Main()
{
// EMP 테이블 구조를 반영한 DataTable 생성
DataTable dataTable = new DataTable();
dataTable.Columns.Add("EMPNO", typeof(int)); // 직원 번호
dataTable.Columns.Add("ENAME", typeof(string)); // 직원 이름
dataTable.Columns.Add("JOB", typeof(string)); // 직무
dataTable.Columns.Add("MGR", typeof(int)); // 관리자 번호
dataTable.Columns.Add("HIREDATE", typeof(DateTime)); // 고용 날짜
dataTable.Columns.Add("SAL", typeof(string)); // 급여 (string 형식으로 가정)
dataTable.Columns.Add("COMM", typeof(string)); // 커미션 (string 형식으로 가정)
dataTable.Columns.Add("DEPTNO", typeof(int)); // 부서 번호
// 예시 데이터 추가
dataTable.Rows.Add(7369, "SMITH", "CLERK", 7902, DateTime.Parse("1980-12-17"), "800", "0", 20);
dataTable.Rows.Add(7499, "ALLEN", "SALESMAN", 7698, DateTime.Parse("1981-02-20"), "1600", "300", 30);
dataTable.Rows.Add(7521, "WARD", "SALESMAN", 7698, DateTime.Parse("1981-02-22"), "1250", "500", 30);
dataTable.Rows.Add(7566, "JONES", "MANAGER", 7839, DateTime.Parse("1981-04-02"), "2975", "0", 20);
dataTable.Rows.Add(7698, "BLAKE", "MANAGER", 7839, DateTime.Parse("1981-05-01"), "2850", "0", 30);
dataTable.Rows.Add(7782, "CLARK", "MANAGER", 7839, DateTime.Parse("1981-06-09"), "2450", "0", 10);
dataTable.Rows.Add(7788, "SCOTT", "ANALYST", 7566, DateTime.Parse("1982-12-09"), "3000", null, 20);
dataTable.Rows.Add(7839, "KING", "PRESIDENT", null, DateTime.Parse("1981-11-17"), "5000", null, 10);
// 부서별 SAL 및 COMM 합산 (DEPTNO 기준)
var groupedData = dataTable.AsEnumerable()
.GroupBy(x => x["DEPTNO"])
.Select(group =>
{
DataRow newRow = dataTable.NewRow();
newRow["ENAME"] = "합계";
newRow["DEPTNO"] = group.Key;
foreach (DataColumn column in dataTable.Columns)
{
if (column.ColumnName == "SAL" || column.ColumnName == "COMM")
{
int sum = group
.Select(row => row[column.ColumnName]?.ToString())
.Where(value => int.TryParse(value, out _))
.Select(int.Parse)
.Sum();
newRow[column.ColumnName] = sum;
}
}
return newRow;
}).CopyToDataTable();
dataTable.Merge(groupedData);
// 결과 출력
foreach (DataRow row in dataTable.Rows)
{
Console.WriteLine($"{row["EMPNO"]}, {row["ENAME"]}, {row["JOB"]}, {row["MGR"]}, {row["HIREDATE"]}, {row["SAL"]}, {row["COMM"]}, {row["DEPTNO"]}");
}
}
}
출력 결과
7369, SMITH, CLERK, 7902, 1980-12-17 오전 12:00:00, 800, 0, 20
7499, ALLEN, SALESMAN, 7698, 1981-02-20 오전 12:00:00, 1600, 300, 30
7521, WARD, SALESMAN, 7698, 1981-02-22 오전 12:00:00, 1250, 500, 30
7566, JONES, MANAGER, 7839, 1981-04-02 오전 12:00:00, 2975, 0, 20
7698, BLAKE, MANAGER, 7839, 1981-05-01 오전 12:00:00, 2850, 0, 30
7782, CLARK, MANAGER, 7839, 1981-06-09 오전 12:00:00, 2450, 0, 10
7788, SCOTT, ANALYST, 7566, 1982-12-09 오전 12:00:00, 3000, , 20
7839, KING, PRESIDENT, , 1981-11-17 오전 12:00:00, 5000, , 10
, 합계, , , , 6775, 0, 20
, 합계, , , , 5700, 800, 30
, 합계, , , , 7450, 0, 10
코드 설명
DataTable 생성 및 EMP 테이블 구조 설정
DataTable
에EMPNO
,ENAME
,JOB
,MGR
,HIREDATE
,SAL
,COMM
,DEPTNO
컬럼을 추가하여EMP
테이블과 유사한 구조를 구성합니다.SAL
과COMM
컬럼은string
형식으로 지정하고, 합산 시 숫자로 변환하여 처리합니다.샘플 데이터 추가
예시 데이터를 사용해DEPTNO
별로 그룹화하고, 그룹 내SAL
과COMM
컬럼을 합산합니다.그룹화 및 합계 계산
GroupBy
를 통해DEPTNO
를 기준으로 데이터를 그룹화하고, 각 그룹의SAL
과COMM
컬럼을int
로 변환하여 합산합니다. 변환 불가한 값은 합산에서 제외하여 오류를 방지합니다.병합 및 출력
계산된 합계 행을 기존DataTable
에 병합하여 최종 결과를 생성합니다. 새로운 합계 행에는 각 부서의SAL
과COMM
총합이 표시됩니다.