{"id":4733,"date":"2008-01-31T14:37:00","date_gmt":"2008-01-31T14:37:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2008\/01\/31\/converting-sql-to-linq-part-8-leftright-outer-join-bill-horst\/"},"modified":"2024-07-05T14:33:31","modified_gmt":"2024-07-05T21:33:31","slug":"converting-sql-to-linq-part-8-leftright-outer-join-bill-horst","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/converting-sql-to-linq-part-8-leftright-outer-join-bill-horst\/","title":{"rendered":"Converting SQL to LINQ, Part 8: Left\/Right Outer Join (Bill Horst)"},"content":{"rendered":"<p class=\"MsoNoSpacing\"><span>This post assumes you&rsquo;ve read the <a class=\"\" title=\"previous posts\" href=\"http:\/\/blogs.msdn.com\/vbteam\/archive\/tags\/Converting+SQL+to+LINQ\/default.aspx\">previous posts<\/a> in this series.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>After my post on <a class=\"\" title=\"joins\" href=\"http:\/\/blogs.msdn.com\/vbteam\/archive\/2007\/12\/31\/converting-sql-to-linq-part-6-joins-bill-horst.aspx\">joins<\/a>, I&rsquo;ve had some questions about outer joins.<span>&nbsp; <\/span>As you can see in part 6, VB9 doesn&rsquo;t have smooth support for Left or Right join.<span>&nbsp; <\/span>I showed how to get similar functionality with Group Join, but I&rsquo;ve looked into the subject some more, and want to give everyone a more extensive explanation of how to get left, right, and full outer join results accurately with VB LINQ.<span>&nbsp; <\/span>Admittedly, these queries are very complex for a relatively simple concept, but unfortunately the VB team didn&rsquo;t have the resources to implement these features in VB9.<span>&nbsp; <\/span>If this support is important to you, you can submit a suggestion to the Visual Studio team to have it included for a future release on our&nbsp;<a class=\"\" title=\"feedback page\" href=\"http:\/\/connect.microsoft.com\/feedback\/default.aspx?SiteID=210\">feedback page<\/a><strong>.<\/p>\n<p><\/strong><\/span><\/p>\n<p class=\"MsoNoSpacing\"><b><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/b><\/p>\n<p class=\"MsoNoSpacing\"><span>I&rsquo;ll cover Left and Right Outer Join in this post and hopefully put up an additional post for Full Outer Join next week.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><span>&nbsp;<\/span><\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><b><span>Assumptions<\/p>\n<p><\/span><\/b><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>For my code examples, I&rsquo;ll be using a slightly modified version of the classes I defined in my first post.<span>&nbsp; <\/span>In the below declarations, I&rsquo;ve declared some <a class=\"\" title=\"nullable\" href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/bb981315(VS.80).aspx\">nullable<\/a> types on members which previously couldn&rsquo;t have a value of Nothing (e.g. Integer -&gt; Integer?).<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<table class=\"MsoTableGrid\" cellspacing=\"0\" cellpadding=\"0\" border=\"1\">\n<tbody>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\"><span><br \/><\/span><\/p>\n<p class=\"MsoNormal\"><span>Class<\/span><span> Customer<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> CustomerID <span>As<\/span> <span>Integer<\/span>?<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> ContactName <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> Phone <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> Address <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> City <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> State <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> Zip <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span>End<\/span><span> <span>Class<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Class<\/span><span> Order<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> OrderID <span>As<\/span> <span>Integer<\/span>?<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> CustomerID <span>As<\/span> <span>Integer<\/span>?<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> Cost <span>As<\/span> <span>Single<\/span>?<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> Phone <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> OrderDate <span>As<\/span> DateTime?<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> ShippingZip <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> ItemName <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>End<\/span><span> <span>Class<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNoSpacing\"><b><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/b><\/p>\n<p class=\"MsoNoSpacing\"><span>I&rsquo;ve also declared CustomerTable and OrderTable variables as follows, to show some example results:<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<table class=\"MsoTableGrid\" cellspacing=\"0\" cellpadding=\"0\" border=\"1\">\n<tbody>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\">\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Dim<\/span><span> CustomerTable <span>As<\/span> Customer() = { _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>New<\/span> Customer <span>With<\/span> {.ContactName = <span>&#8220;Bill Horst&#8221;<\/span>, .CustomerID = 112}, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>New<\/span> Customer <span>With<\/span> {.ContactName = <span>&#8220;John Doe&#8221;<\/span>, .CustomerID = 354}, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>New<\/span> Customer <span>With<\/span> {.ContactName = <span>&#8220;Jane Doe&#8221;<\/span>, .CustomerID = 938}}<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Dim<\/span><span> OrderTable <span>As<\/span> Order() = { _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>New<\/span> Order <span>With<\/span> {.OrderDate = #3\/25\/1982#, .CustomerID = 112}, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>New<\/span> Order <span>With<\/span> {.OrderDate = #3\/13\/2005#, .CustomerID = 112}, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>New<\/span> Order <span>With<\/span> {.OrderDate = #9\/29\/2007#, .CustomerID = 938}, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>New<\/span> Order <span>With<\/span> {.OrderDate = #1\/31\/2008#, .CustomerID = 444}}<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNoSpacing\"><b><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/b><\/p>\n<p class=\"MsoNoSpacing\"><b><span><\/p>\n<p><\/span><\/b><\/p>\n<p class=\"MsoNoSpacing\"><b><span>Left Join<\/p>\n<p><\/span><\/b><\/p>\n<p class=\"MsoNormal\"><b><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/b><\/p>\n<p class=\"MsoNormal\"><span>A SQL LEFT OUTER JOIN is like a standard Inner Join, but it returns results in the &ldquo;Left Table&rdquo; even if there is no matching result in the &ldquo;Right Table&rdquo;.<span>&nbsp; <\/span>For example:<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<table class=\"MsoTableGrid\" cellspacing=\"0\" cellpadding=\"0\" border=\"1\">\n<tbody>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\">\n<p class=\"MsoNoSpacing\"><b><span>SQL<\/p>\n<p><\/span><\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\">\n<p class=\"MsoNoSpacing\"><span>SELECT Contact.ContactName, Shipment.OrderDate<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>FROM CustomerTable Contact<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>LEFT OUTER JOIN OrderTable Shipment<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><span>&nbsp;&nbsp; <\/span>ON Contact.CustomerID = Shipment.CustomerID<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Assuming the above data in CustomerTable and OrderTable, this query would give me results like the following:<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<table class=\"MsoTableGrid\" cellspacing=\"0\" cellpadding=\"0\" border=\"1\">\n<tbody>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\">\n<p class=\"MsoNoSpacing\"><span>Results:<\/p>\n<p><\/span><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\">\n<p class=\"MsoNoSpacing\"><b><span>ContactName<span>&nbsp;&nbsp;&nbsp;&nbsp; <\/span>OrderDate<\/p>\n<p><\/span><\/b><\/p>\n<p class=\"MsoNoSpacing\"><span>Bill Horst<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>3\/25\/1982<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>Bill Horst<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>3\/13\/2005<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>John Doe<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>NULL<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>Jane Doe<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>9\/29\/2007<\/p>\n<p><\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>If I want to re-create this query in VB code, I can start by setting up a Group Join between CustomerTable and OrderTable.<span>&nbsp; <\/span>I don&rsquo;t want to calculate any aggregate values, so I&rsquo;ll use the Group keyword to provide an entry for each member of CustomerTable with a corresponding array of entries from OrderTable.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<table class=\"MsoTableGrid\" cellspacing=\"0\" cellpadding=\"0\" border=\"1\">\n<tbody>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\">\n<p class=\"MsoNoSpacing\"><b><span>VB<\/p>\n<p><\/span><\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\">\n<p class=\"MsoNormal\"><span>From<\/span><span> Contact <span>In<\/span> CustomerTable _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Group<\/span><span> <span>Join<\/span> Shipment <span>In<\/span> OrderTable _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp; <\/span><span>On<\/span> Contact.CustomerID <span>Equals<\/span> Shipment.CustomerID _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><span>&nbsp; <\/span><span>Into<\/span> RightTableResults = <span>Group<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>Results:<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>{Contact={Customer}, RightTableResults = {Grouping}}<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>{Contact={Customer}, RightTableResults = {Order[]}}<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span>{Contact={Customer}, RightTableResults = {Grouping}}<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"MsoNoSpacing\"><i><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/i><\/p>\n<p class=\"MsoNormal\"><span>However, I don&rsquo;t want a series of arrays, so I&rsquo;ll add a From clause to cross-join each Contact with the individual members of the corresponding array.<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNoSpacing\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<table class=\"MsoTableGrid\" cellspacing=\"0\" cellpadding=\"0\" border=\"1\">\n<tbody>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\">\n<p class=\"MsoNoSpacing\"><b><span>VB<\/p>\n<p><\/span><\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td class=\"\" valign=\"top\" width=\"638\">\n<p class=\"MsoNormal\"><span>From<\/span><span> Contact <span>In<\/span> CustomerTable _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Group<\/span><span> <span>Join<\/span> Shipment <span>In<\/span> OrderTable _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp; <\/span><span>On<\/span> Contact.CustomerID <span>Equals<\/span> Shipment.CustomerID _<\/p>\n<p><\/span><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>This post assumes you&rsquo;ve read the previous posts in this series. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; After my post on joins, I&rsquo;ve had some questions about outer joins.&nbsp; As you can see in part 6, VB9 doesn&rsquo;t have smooth support for Left or Right join.&nbsp; I showed how to get similar functionality with Group Join, but I&rsquo;ve looked into [&hellip;]<\/p>\n","protected":false},"author":260,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[20,195],"tags":[41,49,94,166],"class_list":["post-4733","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-converting-sql-to-linq","category-visual-basic","tag-bill-horst","tag-converting-sql-to-linq","tag-linqvb9","tag-vb2008"],"acf":[],"blog_post_summary":"<p>This post assumes you&rsquo;ve read the previous posts in this series. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; After my post on joins, I&rsquo;ve had some questions about outer joins.&nbsp; As you can see in part 6, VB9 doesn&rsquo;t have smooth support for Left or Right join.&nbsp; I showed how to get similar functionality with Group Join, but I&rsquo;ve looked into [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/4733","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/260"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=4733"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/4733\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=4733"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=4733"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=4733"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}