현 블로그는 모바일 환경이 아닌 PC환경에 최적화 되어있습니다.

 Mir의 운영환경

 본체

 DeskTop

 O S

 Windows 7 Ultimate K

 Application

 VisualStudio2015

 .Net

 Framework Ver 4.0

부서, 팀별 합계 데이터 삽입하기


C#으로 DataTable의 내용을 Group by Sum 하여 중간에 삽입해보자.


이런 정렬을 어떤정렬이라고 하는지 잘 모르겠네요.

Data를 불러서 일정 조건의 합계를 중간중간 삽입하고 마지막에 총계를 삽입하는 형식입니다.

아래와 같은 방식입니다. (아래는 모두 위로 올렸습니다.)

처음엔 쿼리문으로만 처리할려고 했는데


Select 부서1이하 데이터

Union 부서 1 합계 데이터

Select 부서2이하 데이터

Union 부서2 합계 데이터

.

.

.

Union 전체 합계 데이터


식으로 부서가 동적이니 동적쿼리로 만들어야 되면서 매우 복잡해 지더군요.

(제가 방법을 몰라서.. 쿼리문으로 불러온 데이터를 중간에 삽입할수도 있는가요?)


정렬을 이용하면 안되냐고 물으실수도 있는데... 응?... 음...

아.. Index컬럼을 하나 따로 만들어서 정렬하는 방법도 있겠네요... 


그런데 각 컬럼별 정렬 Index를 따로 사용하는 컬럼들도 있고.. 일반 정렬을 사용하는곳도 있고..

음.. 음.. 제가 쿼리에 아직 약해서 쿼리문이 더 힘들어 보이네요 ㅋㅋㅋ (아 왜 이걸 이제 생각했지..)


아무튼 GetGroupBySum() 메소드와 같이 InsertSumRow()라는 메소드를 만들었습니다.

기본기능은 GetGroupBySum()으로 각 부서, 팀별로 합계를 가진 DataTable을

기존 DataTable에 각 부서, 팀별로 Row가 시작되는 부분 혹은 끝나는 부분에 삽입해줍니다.

(철저히 제가 쓰기 위해서 만든 허접한 메소드라 사용하실려면 조금씩 수정을 가해서 쓰셔야 할겁니다.)


- 기본 데이터 -

- 각 부서별 합계 아래쪽에 삽입 - 

- 각 팀별 합계 위에 삽입 및 그룹별(총계)는 아래 삽입 -

- 그룹별(총계) 아래 삽입, 부서별 합계 위에 삽입, 팀별 합계 아래 삽입 -



주의할점은 GetGroupBySum()으로 데이터를 받을때 마지막 Boolane값을 True로 주어 컬럼을 전체다 가져와야합니다.

(굳이 이렇게 안해도 되게 만들었는데 컬럼수가 많아지니 버퍼가 너무 심해져 바꿨습니다.)


많은 도움되었으면 좋겠습니다.


- 소스 - 

using System;
using System.Data;
using System.Windows.Forms;

namespace GroupbySum
{
    public partial class GroupBySumTest : Form
    {
        public GroupBySumTest()
        {
            InitializeComponent();

            //속도 향상을 위해서 합계데이처를 단계별로 생성한다.
            DataTable dt = Create_Sample();
            DataTable dt_Team = GetGroupBySum(dt, new string[] { "Salary", "Bonus" }, new string[] { "Group", "Dept", "Team" }, true);
            DataTable dt_Dept = GetGroupBySum(dt_Team, new string[] { "Salary", "Bonus" }, new string[] { "Group", "Dept" }, true);
            DataTable dt_Group = GetGroupBySum(dt_Dept, new string[] { "Salary", "Bonus" }, new string[] { "Group" }, true);

            dt = InsertSumRow(dt, dt_Group, "Group", "그룹합계", false);
            dt = InsertSumRow(dt, dt_Dept, "Dept", "부서합계", true );
            dt = InsertSumRow(dt, dt_Team, "Team", "팀합계", false);

            dataGridView1.DataSource = dt;

        }


        DataTable Create_Sample()
        {
            //DataTable 생성 
            DataTable dt = new DataTable { TableName = "TestTbl" };
            //Columns 생성 
            dt.Columns.AddRange(new DataColumn[] {
            new DataColumn { ColumnName = "Group",      Caption = "그룹",        DataType = typeof(string)   }
          , new DataColumn { ColumnName = "Dept",       Caption = "부서",        DataType = typeof(string)   }
          , new DataColumn { ColumnName = "Team",       Caption = "팀",          DataType = typeof(string)   }
          , new DataColumn { ColumnName = "User",       Caption = "사원",        DataType = typeof(string)   }
          , new DataColumn { ColumnName = "Salary",     Caption = "월급",        DataType = typeof(int)      }
          , new DataColumn { ColumnName = "Bonus",      Caption = "보너스",      DataType = typeof(string)   }
            });

            DataRow dr = dt.NewRow();
            dt.Rows.Add(new object[] { "기획그룹", "기획부", "기획팀", "기획1", 100, "10" });
            dt.Rows.Add(new object[] { "기획그룹", "기획부", "기획팀", "기획2", 200, "20" });

            dt.Rows.Add(new object[] { "기획그룹", "기획부", "보조", "기획보조1", 10, "20" });
            dt.Rows.Add(new object[] { "기획그룹", "기획부", "보조", "기획보조2", 20, "20" });
            dt.Rows.Add(new object[] { "기획그룹", "기획부", "보조", "기획보조3", 30, "20" });

            dt.Rows.Add(new object[] { "기획그룹", "생산부", "생산팀", "생산1", 110, "10" });
            dt.Rows.Add(new object[] { "기획그룹", "생산부", "생산팀", "생산2", 220, "20" });
            dt.Rows.Add(new object[] { "기획그룹", "생산부", "생산팀", "생산3", 330, "30" });

            dt.Rows.Add(new object[] { "기획그룹", "생산부", "보조", "생산보조1", 11, "10" });
            dt.Rows.Add(new object[] { "기획그룹", "생산부", "보조", "생산보조2", 22, "20" });
            dt.Rows.Add(new object[] { "기획그룹", "생산부", "보조", "생산보조3", 33, "30" });

            return dt;
        }

        /// 
        /// DataTable의 Data로 SQL Group by Sum 효과 메소드
        /// 
        /// Data
        /// Sum Columns
        /// Group Columns
        /// 리턴시 기존 DataTable의 컬럼을 모두 받을것인지
        /// false시 Sum Column과 Group Column만 리턴<
        /// /param>
        /// 
        private DataTable GetGroupBySum(DataTable dt, string[] sumColumnNames, string[] groupByColumnNames, bool reAllColumn)
        {

            DataTable dt_Return = null;

            try
            {
                //Check datatable
                if (dt == null || dt.Rows.Count < 1) { return dt; }
                //Check sum columns
                if (sumColumnNames == null || sumColumnNames.Length < 1) { return dt; }
                //Check group columns
                if (groupByColumnNames == null || groupByColumnNames.Length < 1) { return dt; }

                //Create return datatable
                dt_Return = dt.DefaultView.ToTable(true, groupByColumnNames);

                //Set return Columns
                if (reAllColumn)
                {
                    for (int i = 0; i < dt.Columns.Count; i++)
                    {
                        if (!dt_Return.Columns.Contains(dt.Columns[i].ColumnName))
                        {
                            DataColumn dc = new DataColumn(dt.Columns[i].ColumnName, dt.Columns[i].DataType);
                            dt_Return.Columns.Add(dc);
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < sumColumnNames.Length; i++)
                    {
                        if (dt.Columns.Contains(sumColumnNames[i]))
                        {
                            DataColumn dc = new DataColumn(sumColumnNames[i], dt.Columns[sumColumnNames[i]].DataType);
                            dt_Return.Columns.Add(dc);
                        }
                    }
                }

                //Summary Rows
                for (int i = 0; i < dt_Return.Rows.Count; i++)
                {
                    var sQuery = " 1=1 ";

                    foreach (var col in groupByColumnNames)
                    {
                        sQuery += "AND " + col + " = '" + dt_Return.Rows[i][col].ToString() + "'";
                    }
                    DataRow[] drs = dt.Select("(" + sQuery + ")");

                    foreach (var dr in drs)
                    {
                        foreach (var col in sumColumnNames)
                        {
                            int sum, val = 0;
                            int.TryParse(dt_Return.Rows[i][col].ToString(), out sum);
                            int.TryParse(dr[col].ToString(), out val);
                            dt_Return.Rows[i][col] = sum + val;
                        }
                    }

                }
            }
            catch (Exception ex)
            { }

            return dt_Return;
        }

        /// 
        /// DataTable의 compare_Column값을 이용하여 Summary Row를 삽입해준다.
        /// 
        /// 기본 Data
        /// 삽입할 Data
        /// 비교 컬럼(컬럼값이 달라지면 해당 Row에 값을 삽입)
        /// 삽입 Row Title
        /// 삽입을 해당 Row 시작점에 할지(true) 맨 아래 할지(false) 여부
        /// 
        private DataTable InsertSumRow(DataTable dt_Base, DataTable dt_Insert, string compare_Column, string Title, bool isTop)
        {
            int iRow = (isTop)?0:dt_Base.Rows.Count - 1;

            for (int i = (isTop) ? 0 : dt_Insert.Rows.Count - 1; (isTop) ? i < dt_Insert.Rows.Count : i > -1; i = (isTop) ? i + 1 : i - 1)
            {
                for (int j = iRow; (isTop) ? j < dt_Base.Rows.Count : i > -1; j =(isTop) ? j + 1 : j - 1)
                {
                    if (dt_Base.Rows[j][compare_Column].ToString() == dt_Insert.Rows[i][compare_Column].ToString())
                    {
                        DataRow dr = dt_Base.NewRow();
                        dr.ItemArray = dt_Insert.Rows[i].ItemArray;
                        //비교 컬럼 한칸뒤의 컬럼에 Title을 넣어줍니다. (뒤에 컬럼이 하나도 없으면 합계가 사라지니 주의)
                        dr[dt_Base.Columns.IndexOf(compare_Column) + 1] = Title;
                        if (isTop) { dt_Base.Rows.InsertAt(dr, j); }
                        else if (j > dt_Base.Rows.Count - 2) { dt_Base.Rows.Add(dr); }
                        else { dt_Base.Rows.InsertAt(dr, j + 1); }
                        
                        iRow = j++;
                        break;
                    }
                }
            }
            return dt_Base;
        }
    }
}

혹시 Exception이 일어나거나 또는 좀 더 좋은 소스가 있으면 공유 부탁드려요~ ㅠ


(보통 아래쪽에 총계를 내는데 위쪽에 총계를 내는 소스를 만든 이유는 버튼컬럼 삽입으로 Row를 펼쳤다 닫았다 하는 로직이 들어있어서 그렇습니다. 이건 FarPoint를 이용하는거라 따로 올리기가 힘드네요 ㅠ)


 

※ 관련글


+ Recent posts