1

I have this datatable result in c#

Date    Employee Job1   Job2   Job3
1/1/2012    a    1      1      1 
1/1/2012    b    2      2      2
1/1/2012    c    2      1      4
1/1/2012    d    4      2      1
1/2/2012    a    3      2      5
1/2/2012    b    2      2      2
1/2/2012    c    3      3      3
1/2/2012    d    1      1      1
1/3/2012    a    5      5      5
1/3/2012    b    2      2      6
1/3/2012    c    1      1      1
1/3/2012    d    2      3      4
2/1/2012    a    2      2      2
2/1/2012    b    5      5      2
2/1/2012    c    2      2      2
2/2/2012    a    3      3      3
2/2/2012    b    2      3      3
3/1/2012    a    4      4      2

Now I want a result like this:

Job1:

Employee      January       February            March
A             9             5                   4
B             6             7
C             6             2
D             7

Please, can anybody suggest me how to do this with "Linq" in c#?

user1254053
  • 755
  • 3
  • 19
  • 55

1 Answers1

0

This might work (or give you at least an idea):

var monthEmpGroups = tblEmpJobs.AsEnumerable()
    .Select(r => new
    {
        Row = r,
        Employee = r.Field<String>("Employee"),
        Year = r.Field<DateTime>("Date").Year,
        Month = r.Field<DateTime>("Date").Month
    })
    .GroupBy(x => x.Employee);

DataTable tblMonthResultJob1 = new DataTable();
tblMonthResultJob1.Columns.Add("Employee", typeof(string));
var dtf = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat;

foreach (var empGroup in monthEmpGroups)
{
    string employee = empGroup.Key;
    var newRow = tblMonthResultJob1.Rows.Add();
    newRow["Employee"] = employee;
    var empMonthGroup = empGroup.GroupBy(mg => new { mg.Year, mg.Month });

    foreach (var empYearMonthGroup in empMonthGroup)
    {
        int year = empYearMonthGroup.Key.Year;
        int month = empYearMonthGroup.Key.Month;
        string colName = string.Format("{0} {1}", dtf.GetMonthName(month), year);
        if (!tblMonthResultJob1.Columns.Contains(colName))
            tblMonthResultJob1.Columns.Add(colName, typeof(int));
        int empJob1Count = empYearMonthGroup.Sum(x => x.Row.Field<int>("Job1"));
        newRow[colName] = empJob1Count;
    }
}

// do the same for the other job types

Update If you need to add a "total-row" at the "end" as commented:

DataRow totalRow = tblMonthResultJob1.Rows.Add();
totalRow["Employee"] = "ALL";
var monthGroups = tblEmpJobs.AsEnumerable()
    .Select(r => new {
        Row = r,
        Year = r.Field<DateTime>("Date").Year,
        Month = r.Field<DateTime>("Date").Month
    })
    .GroupBy(x => new { x.Year, x.Month });
foreach (var monthGroup in monthGroups)
{
    int yearAll = monthGroup.Key.Year;
    int monthAll = monthGroup.Key.Month;
    string colName = string.Format("{0} {1}", dtf.GetMonthName(monthAll), yearAll);
    if (!tblMonthResultJob1.Columns.Contains(colName))
        tblMonthResultJob1.Columns.Add(colName, typeof(int));
    int allJob1Count = monthGroup.Sum(x => x.Row.Field<int>("Job1"));
    totalRow[colName] = allJob1Count;
}

Update2

I am getting error system.dbnull on this line int

empJob1Count = empYearMonthGroup.Sum(x => x.Row.Field<int>("Job1"));

I think there are some null values and it is not able to cast null values while doing sum. Please help, how should i resolve this

You can use this code to default an int? to zero:

var empYearMonthCount = empYearMonthGroup.Sum(x => 
{ 
    int? job1 = x.Row.Field<int?>("Job1"); 
    int value = 0; 
    if(job1.HasValue) value = job1.Value; 
    return value; 
});
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Thank you Tim for your quick reply. I'll try and will let you knwo if it works. Thank you! – user1254053 Jan 21 '13 at 13:17
  • Hi Tim, I am getting this error "Specified cast is not valid.." on foreach (var empGroup in **monthEmpGroups**). Do you think this might be because this datatable is exported from the excel file and the date is "Date" type column so it is not able to cast it into datetime. Should i create a new datatable with columns and datatypes specified and then put this datatable values into this new one. Please share your thoughts. Thanks a ton! – user1254053 Jan 21 '13 at 14:55
  • @user1254053: `Date` is `DateTime` in C#, are you sure that it's not a `string`? Then you need to parse it with `Year = DateTime.Parse(r.Field("Date")).Year`. You can use the debugger to see what type it is(`tblEmpJobs.Columns["Date"].DataType`). – Tim Schmelter Jan 21 '13 at 14:59
  • Hey Tim, You are genius! You were right, though in excel sheet it was a date column but when I exported from worksheet in datatable it showed a string datatype. Thank you, thank you very much for your suggestions and quick reply. It worked and I am elated. Bless you. – user1254053 Jan 22 '13 at 06:08
  • I want a "Grand Total" row at the end to show the total for each month. Do we have to make changes in this function or should we write another line to get the total for every month and add that to datatable. Please can you suggest how to go about this? – user1254053 Jan 22 '13 at 07:59
  • Do your really need to add a "total-row" at the "end" of a `DataTable`? Understood a `DataTable` as a table in a database. You wouldn't store an aggregated value in a table either. – Tim Schmelter Jan 22 '13 at 08:07
  • @user1254053: Edited my answer to provide the total row (of course untested). – Tim Schmelter Jan 22 '13 at 08:22
  • Perfect!! I have to put this datatable values in excel sheet with grand total at the end and it is working fine. Thanks a lot, much appreciated. – user1254053 Jan 22 '13 at 09:55
  • Tim, I am getting error system.dbnull on this line int empJob1Count = empYearMonthGroup.Sum(x => x.Row.Field("Job1")); I think there are some null values and it is not able to cast null values while doing sum. Please help, how should i resolve this. – user1254053 Feb 25 '13 at 10:44
  • 1
    You can use this code to default an `int?` to zero: `var empYearMonthCount = empYearMonthGroup.Sum(x => { int? job1 = x.Row.Field("Job1"); int value = 0; if(job1.HasValue) value = job1.Value; return value; });` – Tim Schmelter Feb 25 '13 at 11:21
  • @user1254053: Edited also my answer. – Tim Schmelter Feb 25 '13 at 11:23
  • Tim -can you look into my another question here: http://stackoverflow.com/questions/15448936/datatable-get-maxdate-from-string-type-column thanks. – user1254053 Mar 16 '13 at 12:36
  • Tim -can you help me with this one - i have edited my question with new requirement. Thanks – user1254053 Apr 03 '13 at 12:17
  • @user1254053: If your requirement changes you should ask a different question and not edit your old question. That applies all the more to a question with an accepted answer. All my updates above are not the way Stackoverflow works, so i won't edit my answer anymore. Ask a specific question and wait for specific answers. – Tim Schmelter Apr 03 '13 at 12:29
  • Ok, understood, Thnaks – user1254053 Apr 03 '13 at 12:39