{"id":2149,"date":"2023-05-17T12:00:00","date_gmt":"2023-05-17T19:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sql\/?p=2149"},"modified":"2023-06-08T12:12:46","modified_gmt":"2023-06-08T19:12:46","slug":"graphdb-part2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sql\/graphdb-part2\/","title":{"rendered":"Model your Supply Chain in a Graph Database | Part 2"},"content":{"rendered":"<p><div class=\"alert alert-primary\"><p class=\"alert-divider\"><i class=\"fabric-icon fabric-icon--Info\"><\/i><strong>One of four parts<\/strong><\/p>Welcome to part 2 of a four-part series on Supply Chains and Graph Databases. Each part explores different concepts that build upon the examples discussed in the other parts. You can use the following links to navigate directly to each part of the article.<\/div><\/p>\n<ul>\n<li>Part One: <a href=\"..\/graphdb-part1\">Understanding Supply Chains<\/a><\/li>\n<li>Part Two: <a href=\"..\/graphdb-part2\">Enabling SQL Graph<\/a> \u2b05\ufe0f You are here.<\/li>\n<li>Part Three: <a href=\"..\/graphdb-part3\">Reaping Graph Rewards<\/a><\/li>\n<li>Part Four: <a href=\"..\/graphdb-part4\">Visualizing a Graph<\/a><\/li>\n<\/ul>\n<h2>Part 2: Enabling SQL Graph<\/h2>\n<h2>Creating tables<\/h2>\n<p>In Azure SQL, nodes and edges are tables, emphasizing the simplicity of the process. When creating these tables, you append &#8220;AS NODE&#8221; and &#8220;AS EDGE&#8221; respectively to their create statements. The engine takes care of the rest, generating the necessary columns behind the scenes to enable graph functionality. In practical terms, nothing else changes. These tables function like any other tables, but they are ready for graph operations.<\/p>\n<p><!-- ![](p2-01-CREATETABLE.png) --><\/p>\n<pre><code class=\"language-SQL\">CREATE TABLE Plant (Id INT, Name VARCHAR(50)) AS NODE;\nCREATE TABLE Product (Id INT, Name VARCHAR(50)) AS NODE;\nCREATE TABLE Warehouse (Id INT, Name VARCHAR(50)) AS NODE;\nCREATE TABLE Store (Id INT, Name VARCHAR(50)) AS NODE;\n\nCREATE TABLE produces AS EDGE;\nCREATE TABLE delivers_to (Miles INT NOT NULL) AS EDGE;\nCREATE TABLE ships_to (Miles INT NOT NULL) AS EDGE;\nCREATE TABLE stocks (Miles INT NOT NULL) AS EDGE;<\/code><\/pre>\n<blockquote>\n<p><em>Read more at<\/em>: <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/t-sql\/statements\/create-table-sql-graph?view=sql-server-ver16\">SQL Graph CREATE TABLE Online Documentation<\/a><\/p>\n<\/blockquote>\n<p>Interestingly, edge tables can have zero custom columns, representing an edge in your graph without any custom properties. It is unique in SQL to have a table with zero columns, made possible by the &#8220;ON EDGE&#8221; notation. <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-content\/uploads\/sites\/56\/2023\/06\/p2-02-NODEID.png\" alt=\"\" \/><\/p>\n<p>How does it work? These tables have graph columns under the hood. A node has $node_id, and an edge has, at a minimum, two: $from_id and $to_id. Each column is autogenerated and graph specific. We&#8217;ll look into more details about these special columns later.<\/p>\n<p><!-- ![](p2-03-CONSTRAINT.png) --><\/p>\n<pre><code class=\"language-SQL\">ALTER TABLE produces ADD CONSTRAINT EC_PRODUCES CONNECTION (Plant TO Product)\nALTER TABLE delivers_to ADD CONSTRAINT EC_DELIVERSTO CONNECTION (Plant TO Warehouse)\nALTER TABLE ships_to ADD CONSTRAINT EC_SHIPSTO CONNECTION (Warehouse TO Warehouse)\nALTER TABLE stocks ADD CONSTRAINT EC_STOCKS CONNECTION (Warehouse TO Store)<\/code><\/pre>\n<blockquote>\n<p><em>Read more at<\/em>: <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/relational-databases\/tables\/graph-edge-constraints?view=sql-server-ver16\">SQL Graph EDGE CONSTRAINT Online Documentation<\/a><\/p>\n<\/blockquote>\n<p>An edge represents the relationship between two nodes. Like any data in SQL, referential integrity ensures that data engineers use tables correctly and that the data can be trusted. With edge constraints, SQL restricts which nodes an edge can reference. For example, &#8220;Plant-(produces)-&gt;Product&#8221; works, but &#8220;Plant-(produces)-&gt;Store&#8221; does not. These constraints are optional, similar to foreign key constraints in SQL Server. However, having a mechanism to help ensure data quality can be beneficial.<\/p>\n<h2>Inserting data<\/h2>\n<p>Inserting data into a graph table follows the same principles as inserting data into any other table. That said, inserting into an edge table is a bit unique. SQL Graph has three special columns across nodes and edges, each prefixed with a dollar sign. For nodes, the node key is represented by $node_id. As for edges, they have $from_id and $to_id. The edge columns define the &#8220;To&#8221; and &#8220;From&#8221; nodes, respectively. It may require some finesse in data engineering to write clean edge queries, but it is achievable. <\/p>\n<p><!-- ![](p2-04-INSERT.png) --><\/p>\n<pre><code class=\"language-SQL\">INSERT INTO Plant VALUES (1, 'TX'), (2, 'CO'), (3, 'KS'), (4, 'NM')\nINSERT INTO Product VALUES (1, 'Fish Tank'), (2, 'Dog House'), (3, 'Bird House')\nINSERT INTO Warehouse VALUES (1, 'NM'), (2, 'MN'), (3, 'WY'), (4, 'MO')\nINSERT INTO Store VALUES (1, 'KS'), (2, 'AR'), (3, 'AZ'), (4, 'NE')\n\nINSERT INTO produces ($from_id, $to_id)\nSELECT (SELECT $node_id FROM Plant WHERE Id = 1),\n       (SELECT $node_id FROM Product WHERE Id = 1)<\/code><\/pre>\n<blockquote>\n<p><em>Read more at<\/em>: <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/t-sql\/statements\/insert-sql-graph?view=sql-server-ver16\">SQL Graph INSERT DATA Online Documentation<\/a><\/p>\n<\/blockquote>\n<h2>One more question<\/h2>\n<p>You may be wondering about the additional data related to products, which typically goes beyond just an ID and name. That&#8217;s true. However, in this graph, the graph tables reside in your SQL database, alongside all your other data. This single-product solution saves you from the headache of extensive ETL processes. When using the graph to discover trends or gain insights, it&#8217;s simple to join back to the products table, which stores the extensive metadata with its 10, 100, or even 1,000 columns. The graph doesn&#8217;t require all that information. It just needs to know how to connect back to the core data that you already use in your current reports and models. <\/p>\n<h2>Querying with MATCH<\/h2>\n<p>With graph tables, foreign key constraints become unnecessary. Edges can establish relationships between nodes in various ways, including one-to-one, one-to-many, many-to-one, and many-to-many. Once your data is inserted and relationships are established, you can utilize the graph&#8217;s new MATCH keyword in the WHERE clause of your T-SQL queries.<\/p>\n<p><!-- ![](p2-05-MATCH.png) --><\/p>\n<pre><code class=\"language-SQL\">DECLARE @product INT = 1;\n\n-- which plant makes @product?\nSELECT DISTINCT plant.Id, plant.Name AS warehouse\nFROM plant, produces, product\nWHERE MATCH(Plant-(produces)-&gt;Product)\n  AND Product.Id = @product\n\n-- which warehouse stores @product?\nSELECT DISTINCT Warehouse.Id, Warehouse .Name AS Warehouse\nFROM Plant, produces, product, delivers_to, Warehouse\nWHERE MATCH(Plant-(produces)-&gt;Product and Plant-(delivers_to)-&gt;Warehouse)\n  AND product.Id = @product\n\n-- which store sells @product?\nSELECT DISTINCT store.Id, store.Name AS store\nFROM Plant, produces, Product, delivers_to, warehouse, stocks, Store\nWHERE MATCH(Plant-(produces)-&gt;Product and Plant-(delivers_to)-&gt;Warehouse-(stocks)-&gt;Store)\n  AND product.Id = @product<\/code><\/pre>\n<blockquote>\n<p><em>Read more at<\/em>: <a href=\"https:\/\/learn.microsoft.com\/en-us\/sql\/t-sql\/queries\/match-sql-graph?view=sql-server-ver16\">SQL Graph MATCH Online Documentation<\/a><\/p>\n<\/blockquote>\n<h2>Declarative join statements<\/h2>\n<p>Note that the MATCH syntax mirrors the graph notation we discussed earlier. It is straightforward to write, easy to debug, and\u2014honestly\u2014convenient to explain verbally to stakeholders. It acts as a conditional predicate that, behind the scenes, generates the JOIN statements you would anticipate. MATCH serves as a declarative join syntax, simplifying the JOIN operation and minimizing the potential for errors. The engine, equipped with real-time knowledge of every data object and the current execution plan, excels at crafting JOIN statements compared to a data engineer doing it manually. Declarative joins provide a remarkable advantage of using graphs.<\/p>\n<p><!-- ![](p2-06-MATCH.png) --><\/p>\n<pre><code class=\"language-SQL\">WHERE MATCH(Plant-(produces)-&gt;Product and Plant-(delivers_to)-&gt;Warehouse-(stocks)-&gt;Store)\n  AND product.Id = @product<\/code><\/pre>\n<p>Also notice that MATCH supports both compound notation, using the &#8220;and&#8221; keyword, and complex notation that traverses multiple relationships in various directions. The syntax remains readable and straightforward. Additionally, you can include multiple MATCH clauses within the WHERE clause to enhance relationship descriptions if needed. As with most T-SQL statements, there is a high degree of flexibility available.<\/p>\n<h2>Conclusion<\/h2>\n<p>In Part 2, we explored the process of creating tables in Azure SQL to store nodes and edges for our graph database. The simplicity of this process allows us to leverage the power of graph functionality without significant changes to our existing infrastructure. We learned about the special columns generated behind the scenes, such as $node_id for nodes and $from_id and $to_id for edges, which play a crucial role in establishing relationships between entities.<\/p>\n<p>Additionally, we discussed inserting data into graph tables, noting the unique aspects of inserting into edge tables. While it may require some finesse in data engineering, the principles remain consistent with inserting data into any other table. We also addressed the question of additional product data and emphasized the value of storing extensive metadata in separate tables, allowing the graph to focus on the core data required for relationships and connectivity.<\/p>\n<p>Looking ahead to Part 3, we will explore the clarity, validation, discovery, and simplification that come with working with graph data. We&#8217;ll discover how the use of graph databases enables clear communication with stakeholders using their language and concepts, as well as how graph visualization facilitates discovery and simplifies complex relationships. Stay tuned to unlock the full potential of graph databases in optimizing supply chains and gaining valuable insights into your business processes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Part 2 of our series, we explore the practical aspects of enabling SQL Graph for modeling supply chains, including creating tables for nodes and edges and inserting data into them. We also introduce the MATCH keyword for querying graph data, simplifying the retrieval of information based on relationships between entities.<\/p>\n","protected":false},"author":96788,"featured_media":2148,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[465,33,34],"class_list":["post-2149","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>In Part 2 of our series, we explore the practical aspects of enabling SQL Graph for modeling supply chains, including creating tables for nodes and edges and inserting data into them. We also introduce the MATCH keyword for querying graph data, simplifying the retrieval of information based on relationships between entities.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/2149","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\/96788"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/comments?post=2149"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/posts\/2149\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media\/2148"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/media?parent=2149"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/categories?post=2149"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sql\/wp-json\/wp\/v2\/tags?post=2149"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}