{"id":822,"date":"2021-01-21T09:34:17","date_gmt":"2021-01-21T17:34:17","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=822"},"modified":"2021-01-23T18:11:25","modified_gmt":"2021-01-24T02:11:25","slug":"solving-the-river-crossing-problem-with-sql-graph","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/solving-the-river-crossing-problem-with-sql-graph\/","title":{"rendered":"Solving the River Crossing problem with SQL Graph"},"content":{"rendered":"<p>Are you are familiar with the classic \u201c<a href=\"https:\/\/en.wikipedia.org\/wiki\/River_crossing_puzzle\" target=\"_blank\" rel=\"noopener noreferrer\">river crossing<\/a>\u201d problem? If not, an easy 4 minutes introduction using Wildebeest and Lions as the actors in the problem, is presented in this <a href=\"https:\/\/www.ted.com\/talks\/lisa_winer_can_you_solve_the_river_crossing_riddle\" target=\"_blank\" rel=\"noopener noreferrer\">TED-Ed talk<\/a>. If you observe carefully, the video briefly mentions using an enumeration approach to list all the possible transitions, and for each transition, the end state. It so happens that this is the classic algorithmic approach as well to solve such problems \u2013 to create a graph of all possible states (represented by vertices \/ nodes in the graph) and the transitions (represented by edges) which result into those states.\u00a0If you search online, there are plenty of references showing you how to use Breadth-First-Search (BFS) to find the shortest path to solve the problem. David Kopec\u2019s <a href=\"https:\/\/classicproblems.com\/\" target=\"_blank\" rel=\"noopener noreferrer\">Classic Computer Science Problems<\/a> books also present implementations of this problem in Python and other languages.<\/p>\n<p>Let\u2019s see if we can solve this classic problem, using T-SQL and the <a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/graphs\/sql-graph-overview?view=sql-server-ver15\" target=\"_blank\" rel=\"noopener noreferrer\">graph capabilities<\/a> in Azure SQL \/ SQL Server!<\/p>\n<h2>Governing Rules<\/h2>\n<p>Let\u2019s present the main \u201crules\u201d of this problem, as presented in the TED talk:<\/p>\n<ol>\n<li>There are 3 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Wildebeest\" target=\"_blank\" rel=\"noopener noreferrer\">wildebeest<\/a> and 3 <a href=\"https:\/\/en.wikipedia.org\/wiki\/Lion\" target=\"_blank\" rel=\"noopener noreferrer\">lions<\/a>, all located on one bank (for completeness, we have the West bank, and the East bank) of a river. They are trying to cross the other river bank.<\/li>\n<li>As it turns out, wildebeest are a natural prey for the lions. Therefore, there is a \u201crule\u201d which states that if the number of wildebeest either equal, or outnumber the number of lions, on the same bank of the river, they are safe. In our context, we will call this a \u201csafe\u201d state.<\/li>\n<li>Conversely, If the number of wildebeest are lesser than the number of lions, they are unsafe. In our context, we will refer to this as an \u201cunsafe\u201d or \u201cdisallowed\u201d state, as we don\u2019t want the wildebeest to come to harm!<\/li>\n<li>Let\u2019s also imagine, that these animals know how to use a raft, to cross the river \ud83d\ude0a However, the raft can only take 2 animals at any time, and obviously, the raft is not \u201cautonomous\u201d, and needs an animal or 2 animals on board to move from one bank of the river to the other.<\/li>\n<li>At any given point in time, rules 2 and 3 must continuously be applied, even when 2 animals are on the raft!<\/li>\n<\/ol>\n<h2>Notation for states (nodes \/ vertices)<\/h2>\n<p>We will represent the current \u201cstate\u201d of this situation by using simple notations:<\/p>\n<ul>\n<li>The letter <strong>W<\/strong> will be the prefixed with a number representing the number of wildebeest.<\/li>\n<li>Similarly, the letter <strong>L<\/strong> will be the prefixed with a number representing the number of lions.<\/li>\n<li>For each bank of the river, we will use notation like <em>n<\/em>W<em>m<\/em>L to represent the number of animals of each type on that bank. For example, 2W1L means that there are 2 wildebeest, and 1 lion on that side of the river.<\/li>\n<li>If there are no animals of a given type on that bank of the river, the number 0 will be prefixed to the letter representing that type of animal.<\/li>\n<li>The raft can only be on one bank of the river at any given point in time. To conveniently represent this in our notation, we will use an asterisk (*) character to denote the bank of the river where the raft is located.<\/li>\n<li>Putting everything together, we can conveniently depict the complete state. As an example, the notation below, means that the raft is on the west bank of the river, there are 1 each of wildebeest and lion on the west bank, and finally, 2 each of wildebeest and lion on the east bank:<\/li>\n<\/ul>\n<p style=\"padding-left: 80px;\"><strong>* 1W1L | 2W2L<\/strong><\/p>\n<h2>Notation for transitions (edges)<\/h2>\n<ul>\n<li>We will show the movement of the boat using a <strong>&gt;<\/strong> or <strong>&lt;<\/strong>\u00a0character, representing if the raft moved from the west bank, to the east bank, or east to west.<\/li>\n<li>Further, we will prefix the above character with the number of, and type of, animal(s) that are on the raft. For example, <strong>&lt; 1W1L<\/strong> means that 1 wildebeest was on the raft with 1 lion and they went from east to west.<\/li>\n<\/ul>\n<h2>Boiling the ocean (river)<\/h2>\n<p>With the above rules and notations in hand, it is possible to enumerate all possible states and transitions, and create a true graph. If we draw out this graph on a large piece of paper, we would use some more conventions to make it readable:<\/p>\n<ul>\n<li>Some states are \u201cunsafe\u201d as defined previously, as they would result in wildebeest being harmed. Let\u2019s denote those states with an orange fill color.<\/li>\n<li>Correspondingly, transitions which lead into that state, are deemed as impossible transitions, and are represented by dotted lines.<\/li>\n<li>Transitions which are safe are denoted by solid lines.<\/li>\n<li>The desired start and end states are when all 6 animals are safely on either bank of the river. So, you could have <strong>* 3W3L | 0W0L<\/strong> as a valid start, or end state, representing the case when they are all on the west bank.<\/li>\n<li>Correspondingly, <strong> 0W0L | 3W3L *<\/strong> represents another potential start, or end state, wherein all 6 animals are on the east bank!<\/li>\n<\/ul>\n<p>Drawing this out by hand can take a while, but if you patiently do this, you will end up with a large graph like the one below:<\/p>\n<p><figure id=\"attachment_823\" aria-labelledby=\"figcaption_attachment_823\" class=\"wp-caption alignnone\" ><img decoding=\"async\" class=\"wp-image-823\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image.png\" alt=\"river crossing problem - complete set of states and transitions\" width=\"1226\" height=\"1352\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image.png 1226w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image-272x300.png 272w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image-929x1024.png 929w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image-768x847.png 768w\" sizes=\"(max-width: 1226px) 100vw, 1226px\" \/><figcaption id=\"figcaption_attachment_823\" class=\"wp-caption-text\">The river crossing problem &#8211; complete set of states and transitions<\/figcaption><\/figure><\/p>\n<p>I don\u2019t think we want to draw this by hand, or even try enumerating the states and transitions manually. It is tedious, time consuming, and error prone. Let\u2019s see how we can use T-SQL to do this, and eventually produce the \u201cpretty picture\u201d graph shown above!<\/p>\n<h2>SQL Graph Implementation<\/h2>\n<h3>The placement table<\/h3>\n<p>We first create a NODE table in SQL to represent the current state. Note that while we formally name this table as <strong>placement<\/strong>, we may interchangeably refer to it as the <strong>state<\/strong> table as well:<\/p>\n<pre class=\"prettyprint\">CREATE TABLE placement (\r\n    w_w            SMALLINT,\r\n    l_w            SMALLINT,\r\n    w_e            SMALLINT,\r\n    l_e            SMALLINT,\r\n    boat_pos       CHAR (1),\r\n    is_valid_state BIT,\r\n    summary        AS       CONCAT(CASE WHEN boat_pos = 'w' THEN '* ' ELSE '' END, w_w, 'W', l_w, 'L | ', w_e, 'W', l_e, 'L', CASE WHEN boat_pos = 'e' THEN ' *' ELSE '' END)\r\n) AS NODE;<\/pre>\n<p>The columns in the table should be self-explanatory, keeping in mind the previously described notations. The _w and _e suffixes are for the west and east banks, respectively. The computed column, <strong>summary<\/strong>, will be used to print out the same notation as we previously described.<\/p>\n<h3>Populating all possible states<\/h3>\n<p>At any given time, the possible numbers of each type of animal on a bank can be {0, 1, 2, 3}. We also have the constraint that the total number of animals of each type is 3, even if they are split across the riverbanks. So, keeping these in mind, it is easy to implement a CROSS JOIN in T-SQL to populate all the possible states into the <strong>placement<\/strong> table. The code shown below does exactly that and determines if the state is a \u201cvalid\u201d or safe one (as a reminder, when the number of wildebeest is &gt;= the number of lions, it is safe \/ valid state).<\/p>\n<pre class=\"prettyprint\">DECLARE @possible_numbers TABLE (\r\n    val SMALLINT);\r\n\r\nINSERT  INTO @possible_numbers\r\nVALUES (0),\r\n(1),\r\n(2),\r\n(3);\r\n\r\nINSERT placement (w_w, l_w, w_e, l_e, boat_pos, is_valid_state)\r\nSELECT w_w.val AS w_w,\r\n       l_w.val AS l_w,\r\n       w_e.val AS w_e,\r\n       l_e.val AS l_e,\r\n       river_bank AS boat_pos,\r\n       CASE WHEN (((w_w.val &gt; 0\r\n                    AND w_w.val &gt;= l_w.val)\r\n                   OR w_w.val = 0)\r\n                  AND ((w_e.val &gt; 0\r\n                        AND w_e.val &gt;= l_e.val)\r\n                       OR w_e.val = 0)) THEN 1 ELSE 0 END AS is_valid_state\r\nFROM   @possible_numbers AS w_w CROSS JOIN @possible_numbers AS l_w CROSS JOIN @possible_numbers AS w_e CROSS JOIN @possible_numbers AS l_e CROSS JOIN (VALUES ('w'), ('e')) AS boat_pos(river_bank)\r\nWHERE  w_w.val + w_e.val = 3\r\n       AND l_w.val + l_e.val = 3\r\n       AND ((river_bank = 'w'\r\n             AND (w_w.val + l_w.val &gt; 0))\r\n            OR (river_bank = 'e'\r\n                AND (w_e.val + l_e.val &gt; 0)));\r\n<\/pre>\n<h3>The &#8220;transition&#8221; table<\/h3>\n<p>This table represents the transitions i.e., the movement of a given number of animal(s) across the river. This is implemented as a SQL Graph EDGE table as shown below:<\/p>\n<pre class=\"prettyprint\">CREATE TABLE transition (\r\n    pre                 VARCHAR (20),\r\n    post                VARCHAR (20),\r\n    transition          VARCHAR (20),\r\n    is_valid_transition BIT         \r\n) AS EDGE;<\/pre>\n<h3>Populating the transition table<\/h3>\n<p>The code may look daunting, but in simple terms is using a CROSS JOIN to evaluate each possible state against each other state in the previously populated <strong>placement<\/strong>\u00a0table. For each such combination, it calculates if there is a feasible transition based on simple rules:<\/p>\n<ul>\n<li>The raft should be on the same bank as the start of the transition.<\/li>\n<li>At least 1 but not more than 2 animals on the raft at any given time.<\/li>\n<li>The end state and the start state should be different, etc.<\/li>\n<\/ul>\n<pre class=\"prettyprint\">WITH transitions_1\r\nAS   (SELECT f.$NODE_ID AS f_node_id,\r\n             t.$NODE_ID AS t_node_id,\r\n             f.summary AS pre,\r\n             t.summary AS post,\r\n             f.boat_pos AS f_boat_pos,\r\n             t.boat_pos AS t_boat_pos,\r\n             f.w_w AS f_w_w,\r\n             f.w_e AS f_w_e,\r\n             f.l_w AS f_l_w,\r\n             f.l_e AS f_l_e,\r\n             t.w_w AS t_w_w,\r\n             t.w_e AS t_w_e,\r\n             t.l_w AS t_l_w,\r\n             t.l_e AS t_l_e,\r\n             abs(f.w_w - t.w_w) AS w_diff,\r\n             abs(f.l_w - t.l_w) AS l_diff,\r\n             f.w_w + f.l_w AS pre_nuw_w,\r\n             f.w_e + f.l_e AS pre_nuw_e,\r\n             t.w_w + t.l_w AS post_nuw_w,\r\n             t.w_e + t.l_e AS post_nuw_e,\r\n             f.is_valid_state AS f_is_valid_state,\r\n             t.is_valid_state AS t_is_valid_state\r\n      FROM   placement AS f CROSS JOIN placement AS t),\r\n     transitions_2\r\nAS   (SELECT *,\r\n             CONCAT(CASE WHEN pre_nuw_w &lt; post_nuw_w THEN '&lt; ' ELSE '' END, CASE WHEN w_diff &gt; 0 THEN CONCAT(w_diff, 'W') ELSE '' END, CASE WHEN l_diff &gt; 0 THEN CONCAT(l_diff, 'L') ELSE '' END, CASE WHEN pre_nuw_w &gt; post_nuw_w THEN ' &gt;' ELSE '' END) AS transition,\r\n             CASE WHEN f_is_valid_state = 1\r\n                       AND t_is_valid_state = 1 THEN 1 ELSE 0 END AS is_valid_transition\r\n      FROM   transitions_1\r\n      WHERE  pre != post\r\n             AND pre_nuw_w != post_nuw_w\r\n             AND l_diff + w_diff BETWEEN 1 AND 2\r\n             AND f_boat_pos = CASE WHEN pre_nuw_w &lt; post_nuw_w THEN 'e' ELSE 'w' END\r\n             AND t_boat_pos = CASE WHEN pre_nuw_w &lt; post_nuw_w THEN 'w' ELSE 'e' END)\r\nINSERT transition ($FROM_ID, $TO_ID, pre, post, transition, is_valid_transition)\r\nSELECT f_node_id,\r\n       t_node_id,\r\n       pre,\r\n       post,\r\n       transition,\r\n       is_valid_transition\r\nFROM   transitions_2;<\/pre>\n<h3>Finding a solution!<\/h3>\n<p>Once the graph is populated with the above steps, it is trivial to find a valid solution to the river crossing problem. SQL Graph provides the SHORTEST_PATH intrinsic (available in Azure SQL DB and SQL Server 2019 onwards), which implements BFS. Shreya Verma presents a good introduction to this capability <a href=\"https:\/\/channel9.msdn.com\/Shows\/Data-Exposed\/Exploding-Bill-of-Materials-using-Graph-Shortest-Path\">in her webcast<\/a>. The query below is all it takes to find a legal set of transitions to take all the animals, safely from the west bank (start state) to the east bank! And it takes less than 20 milliseconds even on a 2-vCore Azure SQL Hyperscale database.<\/p>\n<pre class=\"prettyprint\">DECLARE @start_state AS VARCHAR (20) = '* 3W3L | 0W0L';\r\nDECLARE @end_state AS VARCHAR (20) = '0W0L | 3W3L *';\r\n\r\nSELECT   *\r\nFROM     (SELECT LAST_VALUE(p2.summary) WITHIN GROUP ( GRAPH PATH) AS end_state,\r\n                 STRING_AGG(t.transition, ', ') WITHIN GROUP ( GRAPH PATH) AS steps,\r\n                 COUNT(t.transition) WITHIN GROUP ( GRAPH PATH) AS num_trips\r\n          FROM   placement AS p1, (SELECT *\r\n                                   FROM   transition\r\n                                   WHERE  is_valid_transition = 1) FOR PATH AS t, placement FOR PATH AS p2\r\n          WHERE  MATCH(SHORTEST_PATH(p1(-(t)-&gt;p2)+))\r\n                 AND p1.summary = @start_state) AS q\r\nWHERE    q.end_state = @end_state;<\/pre>\n<p>Here\u2019s the output of that query:<\/p>\n<table>\n<tbody>\n<tr>\n<td>end_state<\/td>\n<td>steps<\/td>\n<td>num_trips<\/td>\n<\/tr>\n<tr>\n<td>0W0L | 3W3L *<\/td>\n<td>2L &gt;, &lt; 1L, 2L &gt;, &lt; 1L, 2W &gt;, &lt; 1W1L, 2W &gt;, &lt; 1L, 2L &gt;, &lt; 1L, 2L &gt;<\/td>\n<td>11<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>In human-readable terms, these steps can be interpreted as:<\/p>\n<ul>\n<li>2 lions go from west to east.<\/li>\n<li>1 lion comes back to west.<\/li>\n<li>2 lions again go west to east.<\/li>\n<li>1 lion comes back west. At this point in time, there are 3 wildebeest and 1 lion on the west bank.<\/li>\n<li>Now, leaving the 1 lion on the west bank, 2 wildebeest make the trip east.<\/li>\n<li>1 wildebeest comes back with 1 lion to the west bank.<\/li>\n<li>2 wildebeest go west to east.<\/li>\n<li>1 lion now comes back from east to west.<\/li>\n<li>That lion picks up one more lion from the west, and those 2 lions move east.<\/li>\n<li>One lion comes back west.<\/li>\n<li>The 2 lions go back east, completing the epic set of trips!<\/li>\n<\/ul>\n<p>This is just one way to solve the problem. There are other sets of transitions \/ trips which all result in the same end state, but you need a minimum of 11 trips to do so. Here\u2019s the visualization of the graph, filtering and showing only valid transitions and states, and with the above path taken, highlighted.<\/p>\n<p><figure id=\"attachment_824\" aria-labelledby=\"figcaption_attachment_824\" class=\"wp-caption alignnone\" ><img decoding=\"async\" class=\"wp-image-824\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image-1.png\" alt=\"river crossing problem - valid states and transitions, and the solution\" width=\"1031\" height=\"1850\" srcset=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image-1.png 1031w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image-1-167x300.png 167w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image-1-571x1024.png 571w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image-1-768x1378.png 768w, https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2021\/01\/word-image-1-856x1536.png 856w\" sizes=\"(max-width: 1031px) 100vw, 1031px\" \/><figcaption id=\"figcaption_attachment_824\" class=\"wp-caption-text\">The river crossing problem &#8211; valid states and transitions, and the solution!<\/figcaption><\/figure><\/p>\n<h3>Visualization<\/h3>\n<p>If you were wondering how we generate these neat visualizations, it is very easy. We output <a href=\"https:\/\/graphviz.org\/\">Graphviz<\/a> DOT language notation for the directed graph, and then use Graphviz to render the visualization. A very convenient way to render these without any installation, is to use one of the many Graphviz Online viewers like <a href=\"https:\/\/dreampuf.github.io\/GraphvizOnline\/\">this one<\/a>. The code to produce Graphviz DOT syntax for the above (unfiltered) graph is shown below. Note that we leverage many of the powerful (yet simple) <a href=\"https:\/\/graphviz.org\/doc\/info\/attrs.html\">attributes<\/a> provided by Graphviz DOT syntax, to style (colors, line styles etc.) the graph visual representation.<\/p>\n<pre class=\"prettyprint\">DECLARE @start_state AS VARCHAR (20) = '* 3W3L | 0W0L';\r\nDECLARE @end_state AS VARCHAR (20) = '0W0L | 3W3L *';\r\n\r\n-- OPTIONAL visualization using GraphViz's DOT syntax\r\n-- paste the result of the below query into https:\/\/dreampuf.github.io\/GraphvizOnline\/\r\nSELECT 'digraph G \r\n{\r\nnode [style=filled]' AS s\r\nUNION ALL\r\nSELECT CONCAT (\r\n\t\t'\"', summary, '\" [label=&lt; ', CASE \r\n\t\t\tWHEN summary = @start_state\r\n\t\t\t\tOR summary = @end_state\r\n\t\t\t\tTHEN '&lt;B&gt;'\r\n\t\t\tELSE ''\r\n\t\t\tEND, summary, CASE \r\n\t\t\tWHEN summary = @start_state\r\n\t\t\t\tOR summary = @end_state\r\n\t\t\t\tTHEN '&lt;\/B&gt;'\r\n\t\t\tELSE ''\r\n\t\t\tEND, ' &gt;', CASE \r\n\t\t\tWHEN summary = @start_state\r\n\t\t\t\tOR summary = @end_state\r\n\t\t\t\tTHEN ' fontsize=36 '\r\n\t\t\tELSE ''\r\n\t\t\tEND, ' fillcolor = \"', CASE \r\n\t\t\tWHEN summary = @start_state\r\n\t\t\t\tOR summary = @end_state\r\n\t\t\t\tTHEN 'lawngreen'\r\n\t\t\tELSE CASE \r\n\t\t\t\t\tWHEN is_valid_state = 1\r\n\t\t\t\t\t\tTHEN 'azure'\r\n\t\t\t\t\tELSE 'orange'\r\n\t\t\t\t\tEND\r\n\t\t\tEND, '\"]'\r\n\t\t)\r\nFROM placement\r\nUNION ALL\r\nSELECT CONCAT (\r\n\t\t'\"', pre, '\" -&gt; \"', post, '\"[label=\"', transition, '\" style=\"', CASE \r\n\t\t\tWHEN is_valid_transition = 1\r\n\t\t\t\tTHEN 'solid'\r\n\t\t\tELSE 'dashed'\r\n\t\t\tEND, '\" color=\"', CASE \r\n\t\t\tWHEN is_valid_transition = 1\r\n\t\t\t\tTHEN 'black'\r\n\t\t\tELSE 'lightgray'\r\n\t\t\tEND, '\"]'\r\n\t\t)\r\nFROM transition\r\nUNION ALL\r\nSELECT '}';<\/pre>\n<h2>Conclusion<\/h2>\n<p>Graph theory and techniques are some of the most powerful tools at hand for a developer. As seen in this walkthrough, graph theoretic approaches to solving problems usually are very elegant and performant. With its built-in support for representing relational data as graphs, and traversal through that graph using simple MATCH predicates, or even more complex SHORTEST_PATH algorithms, Azure SQL and SQL Server present a convenient option for developers. We hope you found this example a fun and easy way to understand what SQL Graph can do for you. Please do leave your questions and feedback in the comments! Looking forward to your interaction!<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Graph theory and associated techniques are extremely powerful. Azure SQL allows native representation of graphs as node and edge tables, and provides breadth-first-search traversal for native path finding. This blog post demonstrates the ease of use, and great power of, these features by using them to solve the classic river crossing riddle!<\/p>\n","protected":false},"author":32627,"featured_media":823,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[465,33,34],"class_list":["post-822","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sql","tag-azuresql","tag-graph","tag-t-sql"],"acf":[],"blog_post_summary":"<p>Graph theory and associated techniques are extremely powerful. Azure SQL allows native representation of graphs as node and edge tables, and provides breadth-first-search traversal for native path finding. This blog post demonstrates the ease of use, and great power of, these features by using them to solve the classic river crossing riddle!<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/822","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/users\/32627"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/comments?post=822"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/822\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/823"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=822"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=822"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=822"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}