3

I have two tables in SQL that I populate into DataTables in C#. They SQL tables are housed on different servers and different DB's.

In the first table I have 5 columns

Name(string), AgentStatus(string), TimeInState(double), TaskHandled(double), Region(string)

The second table I have 3 columns

Name(string), CChats(double), AChats(double)

I have been using this link to merge the tables in C#

Inner join of DataTables in C#

However the issue I am having is this.

Table 1 has 59 rows, 1 for each user.

Table 2 has 25 rows, 2 for each user that has a Chat account.

When I merge them in C# I only get the matches from table 1 that match the 25 rows in table 2. I need to show all rows from table1 and if they have a row in table 2 show that data, otherwise display 0's

I know where the issue is, its in the select statement in the link above, but I am not sure how to fix it in C#

Here is my code that does not work......The listbox is just to see the output for debugging.....

        DataTable dt1 = new DataTable();
        DataTable dt2 = new DataTable();

        dt1.Columns.Add("Name", typeof(string));
        dt1.Columns.Add("Status", typeof(string));
        dt1.Columns.Add("Time", typeof(double));
        dt1.Columns.Add("Calls", typeof(double));
        dt1.Columns.Add("Region", typeof(string));

        dt2.Columns.Add("Name", typeof(string));
        dt2.Columns.Add("CChats", typeof(double));
        dt2.Columns.Add("AChats", typeof(double));

        foreach(DataRow dr in _agentStates.Rows)
        {
            DataRow row = dt1.NewRow();
            row["Name"] = dr[0].ToString();
            row["Status"] = dr[1].ToString();
            row["Time"] = Convert.ToDouble(dr[2].ToString());
            row["Calls"] = Convert.ToDouble(dr[3].ToString());
            row["Region"] = dr[4].ToString();
            dt1.Rows.Add(row);
        }
        foreach(DataRow dr in _chatCount.Rows)
        {
            DataRow row = dt2.NewRow();
            row["Name"] = dr[0].ToString();
            row["CChats"] = Convert.ToDouble(dr[1].ToString());
            row["AChats"] = Convert.ToDouble(dr[2].ToString());
            dt2.Rows.Add(row);

        }

        var result = from table1 in dt1.AsEnumerable()
                     join table2 in dt2.AsEnumerable() on (string)table1["Name"] equals (string)table2["Name"]
                     select new
                     {
                         Name = (string)table2["Name"],
                         Status = (string)table1["Status"],
                         Time = (double)table1["Time"],
                         Calls = (double)table1["Calls"],
                         Region = (string)table1["Region"],
                         CChats = (double)table2["CChats"]
                     };
        foreach (var item in result)
        {
           listBox1.Items.Add(item.Name + " " + item.CChats.ToString());

        }
Community
  • 1
  • 1
JD Roberson
  • 589
  • 3
  • 7
  • 25

1 Answers1

5

You want to do a LEFT JOIN conceptually (which is an OUTER JOIN, not an INNER JOIN).

The result of a left outer join (or simply left join) for table A and B always contains all records of the "left" table (A), even if the join-condition does not find any matching record in the "right" table (B).

Source: http://en.wikipedia.org/wiki/Join_(SQL)#Left_outer_join

Jeff Atwood has also posted a decent visual explanation of the different joins.

In LINQ this is done a bit more awkwardly than SQL, and is something like:

var LeftJoin = from user in Users
join chat in Chats
on user.Name equals user.Name into JoinedTables
from row in JoinedTables.DefaultIfEmpty()
select new                          
{
  Name,
  AgentStatus,
  TimeInState,
  TaskHandled,
  Region,
  CChats = chat != null ? chat.CChats : 0
  AChats = chat != null ? chat.AChats : 0                          
};

Source: http://codingsense.wordpress.com/2009/03/08/left-join-right-join-using-linq/

Of course joining on Name isn't ideal - hopefully you actually have an ID in the real world, or can really guarantee that names are both unique and will be provided consistently (e.g. no trailing whitespace or differences in capitalisation).

// EDIT, Addressing updated code sample

Try this:

var result = from table1 in dt1.AsEnumerable()
             join table2 in dt2.AsEnumerable() 
             on (string)table1["Name"] equals (string)table2["Name"]
             into joinedDt
             from table2 in joinedDt.DefaultIfEmpty()
             select new
             {
                 Name = (string)table1["Name"],
                 Status = (string)table1["Status"],
                 Time = (double)table1["Time"],
                 Calls = (double)table1["Calls"],
                 Region = (string)table1["Region"],
                 CChats = (table2 != null ? (double)table2["CChats"] : 0)
             };
Matt Mitchell
  • 40,943
  • 35
  • 118
  • 185