diff --git a/samples/features/sql-big-data-cluster/bootstrap-sample-db.sh b/samples/features/sql-big-data-cluster/bootstrap-sample-db.sh index b88d7794..9cce1f50 100644 --- a/samples/features/sql-big-data-cluster/bootstrap-sample-db.sh +++ b/samples/features/sql-big-data-cluster/bootstrap-sample-db.sh @@ -25,8 +25,7 @@ KNOX_PASSWORD=${KNOX_PASSWORD:=$SQL_MASTER_SA_PASSWORD} SQL_MASTER_INSTANCE=$SQL_MASTER_IP,31433 KNOX_ENDPOINT=$KNOX_IP:30443 - -for util in sqlcmd.exe bcp.exe kubectl.exe curl.exe +for util in sqlcmd bcp kubectl curl do echo Verifying $util is in path & which $util 1>/dev/nul 2>/dev/nul || (echo Unable to locate $util && exit 1) done diff --git a/samples/features/sql-big-data-cluster/deployment/aks/deploy-sql-big-data-aks.py b/samples/features/sql-big-data-cluster/deployment/aks/deploy-sql-big-data-aks.py index 99c9c858..01b333f9 100644 --- a/samples/features/sql-big-data-cluster/deployment/aks/deploy-sql-big-data-aks.py +++ b/samples/features/sql-big-data-cluster/deployment/aks/deploy-sql-big-data-aks.py @@ -68,7 +68,7 @@ command="az group create --name "+GROUP_NAME+" --location "+AZURE_REGION executeCmd (command) print("Creating AKS cluster: "+CLUSTER_NAME) -command = "az aks create --name "+CLUSTER_NAME+" --resource-group "+GROUP_NAME+" --generate-ssh-keys --node-vm-size "+VM_SIZE+" --node-count "+AKS_NODE_COUNT+" --kubernetes-version 1.10.7" +command = "az aks create --name "+CLUSTER_NAME+" --resource-group "+GROUP_NAME+" --generate-ssh-keys --node-vm-size "+VM_SIZE+" --node-count "+AKS_NODE_COUNT+" --kubernetes-version 1.10.8" executeCmd (command) command = "az aks get-credentials --name "+CLUSTER_NAME+" --resource-group "+GROUP_NAME+" --admin" diff --git a/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/DerivedTablesAndViewsInGraphMatch.sql b/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/DerivedTablesAndViewsInGraphMatch.sql new file mode 100644 index 00000000..0b8a58fb --- /dev/null +++ b/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/DerivedTablesAndViewsInGraphMatch.sql @@ -0,0 +1,90 @@ +drop view if exists OperatesIn, CUstomer, Novelty_supplier, Novelty_customer +go + +---------------------------------------------------------------------------- +-- Querying heterogeneous edges +---------------------------------------------------------------------------- +CREATE VIEW OperatesIn AS +SELECT *, 'located' AS relation FROM locatedIn +UNION ALL +SELECT *, 'delivery' FROM deliveryIn +GO + +SELECT SupplierID, SupplierName, PhoneNumber, relation + FROM Supplier, + City, + OperatesIn + WHERE MATCH(Supplier-(OperatesIn)->City) + AND City.CityName = 'San Francisco' + +---------------------------------------------------------------------------- +-- Querying heterogeneous nodes +---------------------------------------------------------------------------- + +CREATE VIEW Customer AS +SELECT SupplierID AS ID, + SupplierName AS NAME, + SupplierCategory AS CATEGORY + FROM Supplier +UNION ALL +SELECT CustomerID, + CustomerName, + CustomerCategory + FROM Customers +GO + + +SELECT Customer.ID, Customer.NAME, Customer.CATEGORY + FROM Customer, + City, + locatedIn + WHERE MATCH(Customer-(locatedIn)->City) + AND City.CityName = 'San Francisco' + + SELECT Customer.ID, Customer.NAME, Customer.CATEGORY + FROM Customer, + City, + OperatesIn + WHERE MATCH(Customer-(OperatesIn)->City) + AND City.CityName = 'San Francisco' + + +---------------------------------------------------------------------------- +-- Querying heterogeneous nodes and edges +---------------------------------------------------------------------------- + + +CREATE VIEW Novelty_Supplier AS +SELECT SupplierID, + SupplierName , + SupplierCategory , + ValidTo + FROM Supplier + WHERE SupplierCategory LIKE '%Novelty%' OR SupplierCategory LIKE '%Toy%' +GO + +CREATE VIEW Novelty_Customer AS + SELECT CustomerID, + CustomerName, + CustomerCategory, + ValidTo + FROM Customers + WHERE CustomerCategory LIKE '%Novelty%' OR CustomerCategory LIKE '%Gift%' +GO + +SELECT Name, ID, Category + FROM +(SELECT SupplierID AS ID, SupplierName AS Name, + SupplierCategory AS Category, ValidTo + FROM Novelty_Supplier WHERE ValidTo > getdate() +UNION ALL + SELECT CustomerID, CustomerName, CustomerCategory, ValidTo + FROM Novelty_Customer WHERE ValidTo > getdate()) AS NoveltyCust, +StockItems, +bought, +OperatesIn, +City + WHERE MATCH(City<-(OperatesIn)-NoveltyCust-(bought)->Stockitems) + AND StockItemName = 'White chocolate snow balls 250g' + AND city.cityname = 'San Francisco' +GO diff --git a/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/README.md b/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/README.md new file mode 100644 index 00000000..eab2f721 --- /dev/null +++ b/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/README.md @@ -0,0 +1,81 @@ +# Derived Tables and Views in Graph Match Queries +SQL Server (starting with SQL Server 2017) and Azure SQL Database now let you create a graph database, to hold your entities and complex many to many relationships. There are several examples on github which demonstrate how the new graph features work. This example shows how you can use derived tables and views created on graph node or edge tables in graph match queries. This feature is in public preview on Azure SQL Database and SQL Server 2019 CTP2.1. + + +To demonstrate the functionality, we will be using WideWorldImporters as our sample database. + +## Contents +[About this sample](#about-this-sample)
+[Before you begin](#before-you-begin)
+[Run this sample](#run-this-sample)
+[Related links](#related-links) + +## About this sample +1. **Applies to:** + - Azure SQL Database v12 (or higher) + - SQL Server 2019 CTP2.1 (or higher) +2. **Demos:** + - Build and populate graph node and edge tables + - Use derived tables and views in graph match queries. +3. **Workload:** Queries executed on [WideWorldImporters](https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0) +4. **Programming Language:** T-SQL +5. **Author:** Shreya Verma + +## Before you begin +To run these demo scripts, you need the following prerequisites. + +**Account and Software prerequisites:** + +1. Either + - Azure SQL Database v12 (or higher) + - SQL Server 2019 CTP2.1 (or higher) +2. SQL Server Management Studio 17.x (or higher) + +**Azure prerequisites:** + +1. An Azure subscription. If you don't already have an Azure subscription, you can get one for free here: [get Azure free trial](https://azure.microsoft.com/en-us/free/) + +2. When your Azure subscription is ready to use, you have to create an Azure SQL Database, to do that, you must have completed the first three steps explained in [Design your first Azure SQL database](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-design-first-database) + +## Run This Sample + +### Setup +#### Azure SQL Database Setup + +1. Download the **WideWorldImporters-Standard.bacpac** from the WideWorldImporters database [page](https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0) + +2. Import the **WideWorldImporters-Standard.bacpac** bacpac file to your Azure subscription. [This document](https://docs.microsoft.com/en-us/azure/sql-database/sql-database-import) describes how you can restore a bacpac file to your Azure SQL Database. + +3. Launch SQL Server Management Studio and connect to the newly created WideWorldImporters database + + +#### SQL Server Setup + +1. Download [**WideWorldImporters-Full.bak**](https://github.com/Microsoft/sql-server-samples/releases/tag/wide-world-importers-v1.0) + +2. Launch SQL Server Management Studio, connect to your SQL Server instance (2017) and restore **WideWorldImporters-Full.bak**. This document describes how to [Restore a Database Backup Using SSMS](https://docs.microsoft.com/en-us/sql/relational-databases/backup-restore/restore-a-database-backup-using-ssms). + + +#### Running the Sample Scripts +1. Once the database is restored, run the *setup-wwi-graph.sql* script to create the necessary graph node and edge tables. We will be using these tables to run our sample queries. The setup file creates the following graph schema + +![DerivedTablesAndViewsInGraphMatch Schema](graph-layout.png) + + +2. Run the *DerivedTablesAndViewsInGraphMatch.sql* script to create derived tables and views on nodes and edges, that can be then used in graph match queries to generate insights. The script demonstrates: + + 1. How to query heterogeneous edges in match query. + 2. How to query heterogeneous nodes in match query. + 3. How to query heterogeneous nodes and edges in match query. + +## Related Links + +For more information about Graph DB in SQL Server 2017, see these articles: + +1. [Graph processing with SQL Server and Azure SQL Database](https://docs.microsoft.com/en-us/sql/relational-databases/graphs/sql-graph-overview) + +2. [SQL Graph Architecture](https://docs.microsoft.com/en-us/sql/relational-databases/graphs/sql-graph-architecture) + +3. [Using MATCH in MERGE DML](https://blogs.msdn.microsoft.com/sqlserverstorageengine/2018/07/16/match-support-in-merge-dml-for-graph-tables/) +4. [Edge Constraints on graph tables](https://blogs.msdn.microsoft.com/sqlserverstorageengine/2018/09/28/public-preview-of-graph-edge-constraints-on-sql-server-2019/) + diff --git a/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/graph-layout.png b/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/graph-layout.png new file mode 100644 index 00000000..dc5f6513 Binary files /dev/null and b/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/graph-layout.png differ diff --git a/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/setup-wwi-graph.sql b/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/setup-wwi-graph.sql new file mode 100644 index 00000000..317ba54c --- /dev/null +++ b/samples/features/sql-graph/DerivedTablesAndViewsInGraphMatch/setup-wwi-graph.sql @@ -0,0 +1,440 @@ +-- Create StockItems node + +DROP TABLE IF EXISTS StockItems; +GO +DROP TABLE IF EXISTS Customers; +GO +DROP TABLE IF EXISTS Bought; +GO +DROP TABLE IF EXISTS FriendOf; +GO + + +CREATE TABLE StockItems +( + StockItemID INTEGER IDENTITY(1, 1) NOT NULL, + StockItemName NVARCHAR(100) NOT NULL, + Barcode NVARCHAR(50) NULL, + Photo VARBINARY(MAX), + LastEditedBy INTEGER NOT NULL +) AS NODE +GO + +-- Create the Customers node +-- This node holds the main details of the Customer +CREATE TABLE Customers +( + [CustomerID] INTEGER NOT NULL, + [CustomerName] NVARCHAR(100) NOT NULL, + [WebsiteURL] NVARCHAR(256) NOT NULL, + [CustomerCategory] NVARCHAR(50) NOT NULL, + [ValidFrom] datetime2(7) NOT NULL, + [ValidTo] datetime2(7) NOT NULL +) AS NODE +GO + + +-- Create the edge from nodes Customers and StockItems +CREATE TABLE Bought +( + [PurchasedCount] BIGINT +) +AS EDGE; +GO + + +-- Create FriendOf edge, which connects each customer +-- to 3 other customers as 'friends' +CREATE TABLE FriendOf AS EDGE +GO + + + +------------------------------------------------------------------------------------- +---- Populate StockItems table. +------------------------------------------------------------------------------------- +SET IDENTITY_INSERT StockItems ON; +GO +INSERT INTO StockItems +( + StockItemID, + StockItemName, + LastEditedBy +) SELECT + StockItemID, + StockItemName, + LastEditedBy +FROM + Warehouse.StockItems; +GO +SET IDENTITY_INSERT StockItems OFF; +GO + + +------------------------------------------------------------------------------------- +---- Populate Customers table. +------------------------------------------------------------------------------------- +INSERT INTO Customers +( + [CustomerID], + [CustomerName], + [WebsiteURL], + [CustomerCategory], + [ValidFrom], + [ValidTo] +) SELECT + [CustomerID], + [CustomerName], + [WebsiteURL], + [CustomerCategoryName], + C.[ValidFrom], + C.[ValidTo] +FROM + Sales.Customers AS C, + Sales.CustomerCategories AS SC +WHERE C.CustomerCategoryID = SC.CustomerCategoryID; +GO + +------------------------------------------------------------------------------------- +---- Create Supplier Table +------------------------------------------------------------------------------------- +drop table if exists supplier; +drop table if exists city; +drop table if exists locatedIn; +drop table if exists deliveryIn; + + +CREATE TABLE Supplier ( + SupplierID integer not null, + SupplierName nvarchar(100) not null, + PhoneNumber nvarchar(20), + SupplierCategory nvarchar(50), + ValidFrom datetime2(7) not null, + ValidTo datetime2(7) not null +) AS NODE +GO + +CREATE TABLE City( + CityID integer, + CityName nvarchar(50), + StateProvinceID integer, + StateProvinceName nvarchar(50) +) AS NODE +GO + +CREATE TABLE locatedIn AS EDGE +GO + +CREATE TABLE deliveryIn AS EDGE +GO + + +------------------------------------------------------------------------------------- +---- Populate Supplier table. +------------------------------------------------------------------------------------- +INSERT INTO Supplier +( + [SupplierID], + [SupplierName], + [PhoneNumber], + [SupplierCategory], + [ValidFrom], + [ValidTo] +) SELECT + [SupplierID], + [SupplierName], + [PhoneNumber], + [SupplierCategoryName], + S.[ValidFrom], + S.[ValidTo] +FROM + Purchasing.Suppliers S, + Purchasing.SupplierCategories SC +WHERE + S.SupplierCategoryID = SC.SupplierCategoryID +GO + +------------------------------------------------------------------------------------- +---- Populate City table. +------------------------------------------------------------------------------------- +INSERT INTO City +( + [CityID], + [CityName], + [StateProvinceID], + [StateProvinceName] +) SELECT + [CityID], + [CityName], + C.StateProvinceID, + S.StateProvinceName +FROM + Application.Cities C, + Application.StateProvinces S +WHERE C.StateProvinceID = S.StateProvinceID; +GO + +------------------------------------------------------------------------------------- +---- Populate Bought edge table. +------------------------------------------------------------------------------------- +-- Insert Customers-bought->StockItems data in the bought edge. +INSERT INTO Bought +( + $from_id, + $to_id, + [PurchasedCount] +) +SELECT + C.$node_id, + P.$node_id, + PurchasedCount = COUNT(OD.OrderLineID) +FROM + Sales.OrderLines AS OD +JOIN + Sales.Orders AS OH ON OH.OrderID = OD.OrderID +JOIN + Customers AS C ON C.CustomerID = OH.CustomerID +JOIN + StockItems AS P ON P.StockItemID = OD.StockItemID +GROUP BY + C.$node_id, P.$node_id +GO + +-- Insert Supplier-bought->StockItems data in the bought edge. +INSERT INTO Bought +( + $from_id, + $to_id, + [PurchasedCount] +) +SELECT + S.$node_id, + P.$node_id, + PurchasedCount = COUNT(OD.OrderLineID) +FROM + Sales.OrderLines AS OD +JOIN + Sales.Orders AS OH ON OH.OrderID = OD.OrderID +JOIN + Supplier AS S ON S.SupplierID = OH.CustomerID +JOIN + StockItems AS P ON P.StockItemID = OD.StockItemID +GROUP BY + S.$node_id, P.$node_id +GO + + +------------------------------------------------------------------------------------- +---- Populate FriendOf edge table. +------------------------------------------------------------------------------------- +DECLARE @j INTEGER; +DECLARE @lower INTEGER; +DECLARE @upper INTEGER; +DECLARE @i INTEGER; +DECLARE @random INTEGER; + +SET @upper = 1061 +SET @i = 1 +WHILE (@i <= @upper) +BEGIN + SET @j = 0 + WHILE (@j < 3) + BEGIN + SELECT @random = ROUND(((@Upper - @i) * RAND() + @j), 0) + + INSERT FriendOf($from_id, $to_id) + SELECT C1.$node_id, C2.$node_id + FROM Customers AS C1, Customers AS C2 + WHERE C2.CustomerID = @random --$to_id + AND C1.CustomerID = @i --$from_id + SET @j = @j + 1 + END + SET @i = @i + 1 +END; +GO + + +-- Insert some fixed records in FriendOf table, +-- to be used later in shortest path query +INSERT INTO FriendOf($from_id, $to_id) +SELECT C1.$node_id , C2.$node_id +FROM Customers C1, Customers C2 +where C1.customerID = 1037 +and C2.customerID = 1040 +GO + +INSERT INTO FriendOf($from_id, $to_id) +SELECT C1.$node_id , C2.$node_id +FROM Customers C1, Customers C2 +where C1.customerID = 1040 +and C2.customerID = 1042 +GO + +INSERT INTO FriendOf($from_id, $to_id) +SELECT C1.$node_id , C2.$node_id +FROM Customers C1, Customers C2 +where C1.customerID = 1042 +and C2.customerID = 1028 +GO + +INSERT INTO FriendOf($from_id, $to_id) +SELECT C1.$node_id , C2.$node_id +FROM Customers C1, Customers C2 +where C1.customerID = 1028 +and C2.customerID = 1054 +GO + + + + +------------------------------------------------------------------------------------- +---- Populate locatedIn edge table. +------------------------------------------------------------------------------------- +INSERT INTO locatedIn +( + $from_id, + $to_id +) +SELECT + S.$node_id, + C.$node_id +FROM + Purchasing.Suppliers AS PS +JOIN + Application.Cities AS AC ON PS.PostalCityID = AC.CityID +JOIN + Supplier AS S ON S.SupplierID = PS.SupplierID +JOIN + City AS C ON C.CityID = AC.CityID + + +-- Insert customer - city data +INSERT INTO locatedIn +( + $from_id, + $to_id +) +SELECT + CUS.$node_id, + C.$node_id +FROM + Sales.Customers AS SC +JOIN + Application.Cities AS AC ON SC.PostalCityID = AC.CityID +JOIN + Customers AS CUS ON CUS.CustomerID = SC.CustomerID +JOIN + City AS C ON C.CityID = AC.CityID + + +-- Insert customer locatedIn San Francisco. +-- We will use this data later in queries. +INSERT INTO locatedIn +( + $from_id, + $to_id +) +SELECT + CUS.$node_id, + C.$node_id +FROM + Customers AS CUS, City AS C +WHERE + CUS.CustomerID IN (5,1059,1060,1061,908) + AND + C.cityid = 30378 + + +INSERT INTO locatedIn +( + $from_id, + $to_id +) +SELECT + S.$node_id, + C.$node_id +FROM + Supplier AS S, City AS C +WHERE + S.SupplierID = 2 +AND + C.CityID = 30378 + + + +------------------------------------------------------------------------------------- +---- Populate deliveryIN edge table. +------------------------------------------------------------------------------------- +INSERT INTO deliveryIn +( + $from_id, + $to_id +) +SELECT + S.$node_id, + C.$node_id +FROM + Purchasing.Suppliers AS PS +JOIN + Application.Cities AS AC ON PS.DeliveryCityID = AC.CityID +JOIN + Supplier AS S ON S.SupplierID = PS.SupplierID +JOIN + City AS C ON C.CityID = AC.CityID + + +-- Insert customer - city data +INSERT INTO deliveryIn +( + $from_id, + $to_id +) +SELECT + CUS.$node_id, + C.$node_id +FROM + Sales.Customers AS SC +JOIN + Application.Cities AS AC ON SC.DeliveryCityID = AC.CityID +JOIN + Customers AS CUS ON CUS.CustomerID = SC.CustomerID +JOIN + City AS C ON C.CityID = AC.CityID + + +-- Insert customer deliveryIn San Francisco. +-- We will use this data later in queries. +INSERT INTO deliveryIn +( + $from_id, + $to_id +) +SELECT + CUS.$node_id, + C.$node_id +FROM + Customers AS CUS, City AS C +WHERE + CUS.CustomerID IN (5,1059,1060,1061,908) + AND + C.cityid = 30378 + + +INSERT INTO deliveryIn +( + $from_id, + $to_id +) +SELECT + S.$node_id, + C.$node_id +FROM + Supplier AS S, City AS C +WHERE + S.SupplierID = 2 +AND + C.CityID = 30378 +GO + +------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------- \ No newline at end of file