Merge remote-tracking branch 'refs/remotes/Microsoft/master'

This commit is contained in:
Jovan Popovic
2017-09-29 13:24:33 +02:00
36 changed files with 1694 additions and 178 deletions
+4
View File
@@ -9,3 +9,7 @@ The new sample database for SQL Server 2016 and Azure SQL Database. It illustrat
__[contoso-data-warehouse](contoso-data-warehouse/)__
Sample data warehouse that illustrates loading data into Azure SQL Data Warehouse.
__[AdventureWorks2014](https://github.com/Microsoft/sql-server-samples/releases/tag/adventureworks2014)__
Sample databases and Analysis Services models for use with SQL Server 2014 and later.
@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
<PreserveCompilationContext>true</PreserveCompilationContext>
<AssemblyName>force-last-good-plan</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>force-last-good-plan</PackageId>
<RuntimeFrameworkVersion>1.0.4</RuntimeFrameworkVersion>
<PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;portable-net45+win8</PackageTargetFallback>
</PropertyGroup>
<ItemGroup>
<None Update="wwwroot\**\*">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="1.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.0.2" />
<PackageReference Include="System.Data.SqlClient" Version="4.3.0" />
<PackageReference Include="Belgrade.Sql.Client" Version="0.7.0" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.1" />
</ItemGroup>
</Project>
@@ -1,60 +1,74 @@
/********************************************************
* SETUP - clear everything
********************************************************/
EXEC [dbo].[initialize]
ALTER DATABASE current SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = OFF);
EXEC dbo.initialize;
/********************************************************
* PART I
* Plan regression identification.
* Plan regression identification & manual tuning
********************************************************/
-- 1. Start workload - execute procedure 30-300 times:
begin
declare @packagetypeid int = 7;
exec dbo.report @packagetypeid
end
go 300
-- Queries should be fast
-- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Hash Aggregate)
-- Execute the query and include "Actual execution plan" in SSMS and show the plan - it should have Hash Match (Aggregate) operator with Columnstore Index Scan
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
from Sales.OrderLines
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
GO 60
-- 1. Execute this query 45-300 times to setup the baseline.
-- If you have QUERY_STORE CAPTURE_POLICY=AUTO increase number in GO <number> to at least 60
-- 2. Execute procedure that causes plan regression
-- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Stream Aggregate)
exec dbo.regression
-- 2. Execute the procedure that causes plan regression
-- Optionally, include "Actual execution plan" in SSMS and show the plan - it should have Stream Aggregate, Index Seek & Nested Loops
EXEC dbo.regression;
-- 3. Start workload again - verify that is slower.
begin
declare @packagetypeid int = 7;
exec dbo.report @packagetypeid
end
-- 3. Start the workload again - verify that is slower.
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
from Sales.OrderLines
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
go 20
-- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Stream Aggregate)
-- Optionally, include "Actual execution plan" in SSMS and show the plan - it should have Stream Aggregate with Non-clustered index seek.
-- 4. Find recommendation recommended by database:
SELECT planForceDetails.query_id, reason, score,
JSON_VALUE(details, '$.implementationDetails.script') [correction script],
planForceDetails.[new plan_id], planForceDetails.[recommended plan_id]
FROM sys.dm_db_tuning_recommendations
CROSS APPLY OPENJSON (Details, '$.planForceDetails')
WITH ( [query_id] int '$.queryId',
[new plan_id] int '$.regressedPlanId',
[recommended plan_id] int '$.recommendedPlanId'
) as planForceDetails;
-- 4. Find a recommendation that can fix this issue:
SELECT reason, score,
script = JSON_VALUE(details, '$.implementationDetails.script')
FROM sys.dm_db_tuning_recommendations;
-- 4.1. Optionally get more detailed information about the regression and recommendation.
SELECT reason, score,
script = JSON_VALUE(details, '$.implementationDetails.script'),
planForceDetails.[query_id],
planForceDetails.[new plan_id],
planForceDetails.[recommended plan_id],
estimated_gain = (regressedPlanExecutionCount+recommendedPlanExecutionCount)*(regressedPlanCpuTimeAverage-recommendedPlanCpuTimeAverage)/1000000,
error_prone = IIF(regressedPlanErrorCount>recommendedPlanErrorCount, 'YES','NO')
FROM sys.dm_db_tuning_recommendations
CROSS APPLY OPENJSON (Details, '$.planForceDetails')
WITH ( [query_id] int '$.queryId',
[new plan_id] int '$.regressedPlanId',
[recommended plan_id] int '$.recommendedPlanId',
regressedPlanErrorCount int,
recommendedPlanErrorCount int,
regressedPlanExecutionCount int,
regressedPlanCpuTimeAverage float,
recommendedPlanExecutionCount int,
recommendedPlanCpuTimeAverage float ) as planForceDetails;
-- IMPORTANT NOTE: check is estimated_gain > 10.
-- If estimated_gain < 10 THEN FLGP=ON will not automatically force the plan!!!
-- In that case increase the number of executions in initial workload.
-- Make sure that SQL Engine uses columnstore in original plan and nonclustered index in regressed plan.
-- Note: User can apply script and force the recommended plan to correct the error.
<<Insert T-SQL from the script column here and execute the script>>
-- e.g.: exec sp_query_store_force_plan @query_id = 3, @plan_id = 1
-- 5. Start workload again - verify that is faster.
begin
declare @packagetypeid int = 7;
exec dbo.report @packagetypeid
end
go 20
-- Optionally, include "Actual execution plan" in SSMS and show the plan (it should have Hash Aggregate again)
-- 5. Execute the query again - verify that it is faster.
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
from Sales.OrderLines
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
GO 20
-- Optionally, include "Actual execution plan" in SSMS and show the plan - it should have Hash Aggregate & Columnstore again
-- In part II will be shown better approach - automatic tuning.
@@ -74,29 +88,26 @@ ALTER DATABASE current
SET AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = ON);
-- Verify that actual state on FLGP is ON:
SELECT name, desired_state_desc, actual_state_desc, reason_desc
FROM sys.database_automatic_tuning_options;
SELECT name, actual_state_desc, status = IIF(desired_state_desc <> actual_state_desc, reason_desc, 'Status:OK')
FROM sys.database_automatic_tuning_options
WHERE name = 'FORCE_LAST_GOOD_PLAN';
-- 1. Start workload - execute procedure 30-300 times like in the phase I
begin
declare @packagetypeid int = 7;
exec dbo.report @packagetypeid
end
go 300
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
from Sales.OrderLines
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
GO 60
-- 2. Execute the procedure that causes plan regression
-- 2. Execute the procedure that causes the plan regression
exec dbo.regression;
-- 3. Start workload again - verify that it is slower.
begin
declare @packagetypeid int = 7;
exec dbo.report @packagetypeid;
end
go 20
-- 3. Start the workload again - verify that it is slower.
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
from Sales.OrderLines
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
go 30
-- 4. Find recommendation that returns query perf regression
-- and check is it in Verifying state:
-- 4. Find a recommendation and check is it in "Verifying" or "Success" state:
SELECT reason, score,
JSON_VALUE(state, '$.currentValue') state,
JSON_VALUE(state, '$.reason') state_transition_reason,
@@ -110,11 +121,11 @@ FROM sys.dm_db_tuning_recommendations
) as planForceDetails;
-- 5. Wait until recommendation is applied and start workload again - verify that it is faster.
begin
declare @packagetypeid int = 7;
exec dbo.report @packagetypeid
end
go 30
-- 5. Recommendation is in "Verifying" state, but the last good plan is forced, so the query will be faster:
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
from Sales.OrderLines
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid = 7;
-- Open Query Store/"Top Resource Consuming Queries" dialog in SSMS and show that the better plan is forced.
-- Open Query Store/"Top Resource Consuming Queries" dialog in SSMS and show that better plan is forced.
@@ -0,0 +1,64 @@
/***************************************************************************
* Run this script on a empty database if you don't have WWI database and
* you want to use new database instead of full WWI
* If you are using SSMS, use Ctrl+Shift+M to populate parameters.
***************************************************************************/
ALTER DATABASE <database_name, sysname, flgp> MODIFY (EDITION = 'Premium', SERVICE_OBJECTIVE = '<azuredb_service_objective, varchar(6), P4>');
SELECT DATABASEPROPERTYEX('<database_name, sysname, flgp>', 'ServiceObjective');
-- Create minimal WWI schema required to run the sample:
DROP TABLE IF EXISTS [Sales].[OrderLines];
GO
DROP SEQUENCE IF EXISTS [Sequences].[OrderLineID];
GO
DROP SCHEMA IF EXISTS [Sequences];
GO
DROP SCHEMA IF EXISTS [Sequences];
GO
CREATE SCHEMA [Sequences];
GO
CREATE SEQUENCE [Sequences].[OrderLineID]
AS [int]
START WITH 231413
INCREMENT BY 1
MINVALUE -2147483648
MAXVALUE 2147483647
CACHE
GO
CREATE TABLE [Sales].[OrderLines](
[OrderLineID] [int] PRIMARY KEY,
[OrderID] [int] NOT NULL,
[StockItemID] [int] NOT NULL,
[Description] [nvarchar](100) NOT NULL,
[PackageTypeID] [int] NOT NULL,
[Quantity] [int] NOT NULL,
[UnitPrice] [decimal](18, 2) NULL,
[TaxRate] [decimal](18, 3) NOT NULL,
[PickedQuantity] [int] NOT NULL,
[PickingCompletedWhen] [datetime2](7) NULL,
[LastEditedBy] [int] NOT NULL,
[LastEditedWhen] [datetime2](7) NOT NULL
)
GO
ALTER TABLE [Sales].[OrderLines]
ADD CONSTRAINT [DF_Sales_OrderLines_OrderLineID]
DEFAULT (NEXT VALUE FOR [Sequences].[OrderLineID]) FOR [OrderLineID]
GO
ALTER TABLE [Sales].[OrderLines]
ADD CONSTRAINT [DF_Sales_OrderLines_LastEditedWhen]
DEFAULT (sysdatetime()) FOR [LastEditedWhen]
GO
DROP INDEX IF EXISTS [FK_Sales_OrderLines_PackageTypeID]
ON [Sales].[OrderLines]
CREATE NONCLUSTERED INDEX [FK_Sales_OrderLines_PackageTypeID]
ON [Sales].[OrderLines]([PackageTypeID] ASC)
GO
-- Export Sales.OrderLines from WWI database using bcp:
-- bcp WideWorldImporters.Sales.OrderLines out OrderLines.dat -T -c -U <wwi_user_name, nvarchar(50), WWIUSERNAME> -P <wwi_password, nvarchar(50), WWIPASSWORD> -S <wwi server/instance, nvarchar(50), .//SQLEXPRESS>
-- Import data in new database using bcp:
-- bcp <database_name, sysname, flgp>.Sales.OrderLines in OrderLines.dat -c -U <demo_user_name, nvarchar(50), DEMOUSERNAME> -P <demo_password, nvarchar(50), DEMOPASSWORD> -S <demo server/instance, nvarchar(50), .//SQLEXPRESS>
@@ -1,6 +1,10 @@
DROP INDEX IF EXISTS [NCCX_Sales_OrderLines] ON [Sales].[OrderLines]
-- Insert one OrderLine that with PackageTypeID=(0) will cause regression
INSERT INTO Sales.OrderLines(OrderId, StockItemID, Description, PAckageTypeID, quantity, unitprice, taxrate, PickedQuantity,LastEditedBy)
SELECT TOP 1 OrderID, StockItemID, Description, PackageTypeID = 0, Quantity, UnitPrice, taxrate , PickedQuantity,LastEditedBy
FROM Sales.OrderLines;
DROP INDEX IF EXISTS [NCCX_Sales_OrderLines] ON [Sales].[OrderLines]
/****** Object: Index [NCCX_Sales_OrderLines] Script Date: 4/20/2017 11:27:27 AM ******/
CREATE NONCLUSTERED COLUMNSTORE INDEX [NCCX_Sales_OrderLines] ON [Sales].[OrderLines]
(
[OrderID],
@@ -10,72 +14,74 @@ CREATE NONCLUSTERED COLUMNSTORE INDEX [NCCX_Sales_OrderLines] ON [Sales].[OrderL
[UnitPrice],
[PickedQuantity],
[PackageTypeID] -- adding package type id for demo purpose
)WITH (DROP_EXISTING = OFF, COMPRESSION_DELAY = 0) ON [USERDATA]
)WITH (DROP_EXISTING = OFF, COMPRESSION_DELAY = 0)
GO
CREATE OR ALTER PROCEDURE [dbo].[initialize]
as begin
AS BEGIN
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
ALTER DATABASE current SET QUERY_STORE CLEAR ALL;
ALTER DATABASE current SET AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = OFF);
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
ALTER DATABASE current SET QUERY_STORE CLEAR ALL;
end
END
GO
CREATE OR ALTER PROCEDURE [dbo].[report] (@packagetypeid int)
as begin
AS BEGIN
select avg([UnitPrice]*[Quantity])
from Sales.OrderLines
where PackageTypeID = @packagetypeid
EXEC sp_executesql N'select avg([UnitPrice]*[Quantity])
from Sales.OrderLines
where PackageTypeID = @packagetypeid', N'@packagetypeid int', @packagetypeid;
end
END
GO
CREATE OR ALTER PROCEDURE [dbo].[regression]
as begin
AS BEGIN
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
begin
declare @packagetypeid int = 1;
BEGIN
declare @packagetypeid int = 0;
exec report @packagetypeid;
end
END
end
END
GO
CREATE OR ALTER PROCEDURE [dbo].[auto_tuning_on]
as begin
AS BEGIN
ALTER DATABASE current SET AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = ON);
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
ALTER DATABASE current SET QUERY_STORE CLEAR ALL;
ALTER DATABASE current SET AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = ON);
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
ALTER DATABASE current SET QUERY_STORE CLEAR ALL;
end
END
GO
CREATE OR ALTER PROCEDURE [dbo].[auto_tuning_off]
as begin
AS BEGIN
ALTER DATABASE current SET AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = OFF);
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
ALTER DATABASE current SET QUERY_STORE CLEAR ALL;
ALTER DATABASE current SET AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = OFF);
ALTER DATABASE SCOPED CONFIGURATION CLEAR PROCEDURE_CACHE;
ALTER DATABASE current SET QUERY_STORE CLEAR ALL;
end
END
GO
/*
CREATE EVENT SESSION [APC - plans that are not corrected] ON SERVER
CREATE EVENT SESSION [APC - plans that are not corrected] ON DATABASE
ADD EVENT qds.automatic_tuning_plan_regression_detection_check_completed(
WHERE ((([is_regression_detected]=(1))
AND ([is_regression_corrected]=(0)))
AND ([option_id]=(1))))
ADD TARGET package0.event_file(SET filename=N'plans_that_are_not_corrected')
-- Use file target only on SQL Server 2017:
-- ADD TARGET package0.event_file(SET filename=N'plans_that_are_not_corrected')
ADD TARGET package0.ring_buffer (SET max_memory = 1000)
WITH (STARTUP_STATE=ON);
GO
ALTER EVENT SESSION [APC - plans that are not corrected] ON SERVER STATE = start;
ALTER EVENT SESSION [APC - plans that are not corrected] ON SERVER STATE = start;
*/
@@ -37,27 +37,37 @@
<div class="col-md-4">
<h1>Automatic tuning</h1>
</div>
<div class="col-md-3">
<div class="col-md-3 hidden">
<div class="btn-group pull-right align-bottom" data-toggle="buttons">
<label class="btn btn-default active">
<input type="radio" name="options" id="off" autocomplete="off" checked> OFF
</label>
<label class="btn btn-default">
<input type="radio" name="options" id="on" autocomplete="off"> ON
<input type="radio" name="options" id="off" autocomplete="off"> OFF
</label>
<label class="btn btn-default active">
<input type="radio" name="options" id="on" autocomplete="off" checked> ON
</label>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<span id="speed">0</span> requests per second.
</div>
<div class="col-md-3">
<button id="regression" type="button" class="btn btn-danger pull-right">Regression</button>
<div class="col-md-12">
<span id="speed">0</span> requests per second. <button id="regression" type="button" class="btn btn-danger pull-right">Regression</button>
</div>
</div>
<div class="row">
<svg width="500" height="500"></svg>
<div class="col-md-6">
<svg width="500" height="500"></svg>
</div>
<div class="col-md-6">
<h3>T-SQL query:</h3>
<pre>
SELECT AVG( UnitPrice * Quantity )
FROM Sales.OrderLines
WHERE PackageTypeID = @packagetypeid;</pre>
<h3>Enable FORCE LAST GOOD PLAN:</h3>
<pre>
ALTER DATABASE current
SET AUTOMATIC_TUNING ( FORCE_LAST_GOOD_PLAN = ON);</pre>
</div>
</div>
<script src="media/d3.v3.min.js"></script>
<script src="media/viz.v1.0.0.min.js"></script>
@@ -66,7 +76,7 @@
<script src="media/GraphVizGauge.js"></script>
<script src="/api/demo/init"></script>
<script>
var gauge = new GraphVizGauge("svg", { to: 150 });
var gauge = new GraphVizGauge("svg", { to: 250 });
var perfData = [];
setInterval(function () {
$.ajax({
@@ -0,0 +1,66 @@
# Power BI Reports for Consolidated Migration Assessments
This contains examples of Power BI reports for consolidated migration assessements. The assessments are generated using Data Migration Assistant, to evaluate moving data to SQL Server or to Azure SQL Database.
### Contents
[About this sample](#about-this-sample)<br/>
[Before you begin](#before-you-begin)<br/>
[Run this sample](#run-this-sample)<br/>
[Sample details](#sample-details)<br/>
[Related links](#related-links)<br/>
<a name=about-this-sample></a>
## About this sample
- **Applies to:** SQL Server 2016 (or higher), Azure SQL Database
- **Key features:** Migration assessments
<a name=before-you-begin></a>
## Before you begin
To run this sample, you need the following prerequisites.
**Software prerequisites:**
1. Power BI
2. SQL Server 2016 (or higher) or an Azure SQL Database
3. Data Migration Assistant
**Azure prerequisites:**
1. Permission to create an Azure SQL Database
<a name=run-this-sample></a>
## Run this sample
<!-- Step by step instructions. Here's a few examples -->
1. Copy the DMA Reports V3.1.pbix file locally.
2. Open the file using Power BI.
<a name=sample-details></a>
## Sample details
This includes the following Power BI reports, for consolidated migration assessments.
- **Dashboard:** Provides snapshot stats and a drill down report.
- **On Premise Upgrade Readiness:** Shows the percentage upgrade success for you assessed databases.
- **On Premise Feature Parity Report -- Details:** Highlights new features that can be used for database in the target SQL Server version.
- **Azure SQL DB Upgrade Readiness:** Shows the percentage upgrade success for databases assessed for Azure SQL DB migrations.
- **Azure SQL DB Unsuppported Features:** Shows features that in your existing databases are not supported in Azure SQL DB (v12).
<a name=related-links></a>
## Related Links
For more information, see these articles:
[Report on your Consolidated Assessments using Power BI (Data Migration Assistant)](https://docs.microsoft.com/sql/dma/dma-powerbiassesreport)
@@ -0,0 +1,926 @@
#This Sample Code is provided for the purpose of illustration only and is not intended to be used in a production environment.
#THIS SAMPLE CODE AND ANY RELATED INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
#INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
#We grant you a nonexclusive, royalty-free right to use and modify the Sample Code and to reproduce and distribute
#the object code form of the Sample Code, provided that you agree:
#(i) to not use Our name, logo, or trademarks to market Your software product in which the Sample Code is embedded;
#(ii) to include a valid copyright notice on Your software product in which the Sample Code is embedded; and
#(iii) to indemnify, hold harmless, and defend Us and our suppliers from and against any claims or lawsuits, including attorneys' fees, that arise or result from the use or distribution of the Sample Code.
# -----------------------------------------------------------------------------
#
# Script: DMA_Processor.ps1
# Author: Chris Lound - Senior Premier Field Engineer - Data Platform.
# Date: 08/02/2017
# Version: 5.0
# Synopsis: Create reporting objects and loads JSON files from DMA output folder into SQL server
# Keywords:
# Notes: A processed folder is created in the root folder of the folder containing the DMA JSON output (user specified). Script currently only supports windows authentication to SQL Server.
# Comments:
# 1.0 Initial Release - 22/11/2016
# 2.0 Refactored JSON shredder for SQL2014 and below. Made this the only shredding function by removing the SQL2016 dependency
# 3.0 Built in weighted breaking changes. Added table to support breaking change weighting and updated view to use it for reporting. Also removed Azure Artifacts
# 3.1 Change importdate type to datetime. Added DBOwner column for reportdata table. - 16/02/2017
# 4.0 Added DMAWarehouse objects. Cleaned up output into console
# 4.1 Added Warehouse views, AssessmentTarget and AssessmentName properties and dependants
# 5.0 Added support for feature parity for azure targets (new table, table type, stored procedure, datatable (ps), shredding loop (ps).
# Added error handling for failed dataset fills. Added support for only moving files when they are actually processed. if they fail they dont get moved.
# Added option to create data warehouse
# Altered UpgradeSuccessRanking view to exclude TargetCompatibilityMode of 'NA' (Azure migrations)
# REMOVED data warehouse scripts from this specific script version
# Split UpgradeSuccessRanking views into 2, 1 for onprem and 1 for azure to fix assessment counts in powerbi
#------------------------------------------------------------------------------------ CREATE FUNCTIONS -------------------------------------------------------------------------------------
#Import JSON to SQL on prem or azure
function dmaProcessor
{
param(
    [parameter(Mandatory)]
    [ValidateNotNullOrEmpty()]
[string] $serverName,
    [parameter(Mandatory)]
    [ValidateNotNullOrEmpty()]
[string] $databaseName,
    [parameter(Mandatory)]
    [ValidateNotNullOrEmpty()]
[string] $jsonDirectory,
    [parameter(Mandatory)]
    [ValidateNotNullOrEmpty()]
[ValidateSet("SQLServer")]
[string] $processTo
)
#Create database objects
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | Out-Null
$srv = New-Object Microsoft.SqlServer.Management.SMO.Server($serverName)
#create reporting database
$dbCheck = $srv.Databases | Where {$_.Name -eq "$databaseName"} | Select Name
if(!$dbCheck)
{
$db = New-Object Microsoft.SqlServer.Management.Smo.Database ($srv, $databaseName)
$db.Create()
Write-Host("Database $databaseName created successfully") -ForegroundColor Green
}
else
{
$db=$srv.Databases.Item($databaseName)
Write-Host ("Database $databaseName already exists") -ForegroundColor Yellow
}
#create ReportData table
$tableCheck = $db.Tables | Where {$_.Name -eq "ReportData"}
if(!$tableCheck)
{
$ReportDatatbl = New-Object Microsoft.SqlServer.Management.Smo.Table($db, "ReportData")
$col1 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "ImportDate", [Microsoft.SqlServer.Management.Smo.DataType]::DateTime)
$col2 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "InstanceName", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col3 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "Status", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(30))
$col4 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "Name", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(255))
$col5 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "SizeMB", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(30))
$col6 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "SourceCompatibilityLevel", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(15))
$col7 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "TargetCompatibilityLevel", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(15))
$col8 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "Category", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(30))
$col9 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "Severity", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(15))
$col10 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "ChangeCategory", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(20))
$col11 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "RuleId", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(100))
$col12 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "Title", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col13 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "Impact", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col14 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "Recommendation", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col15 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "MoreInfo", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col16 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "ImpactedObjectName", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(255))
$col17 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "ImpactedObjectType", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col18 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "ImpactDetail", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col19 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "DBOwner", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(128))
$col20 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "AssessmentTarget", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col21 = New-Object Microsoft.SqlServer.Management.Smo.Column($ReportDatatbl, "AssessmentName", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(128))
$ReportDatatbl.Columns.Add($col1)
$ReportDatatbl.Columns.Add($col2)
$ReportDatatbl.Columns.Add($col3)
$ReportDatatbl.Columns.Add($col4)
$ReportDatatbl.Columns.Add($col5)
$ReportDatatbl.Columns.Add($col6)
$ReportDatatbl.Columns.Add($col7)
$ReportDatatbl.Columns.Add($col8)
$ReportDatatbl.Columns.Add($col9)
$ReportDatatbl.Columns.Add($col10)
$ReportDatatbl.Columns.Add($col11)
$ReportDatatbl.Columns.Add($col12)
$ReportDatatbl.Columns.Add($col13)
$ReportDatatbl.Columns.Add($col14)
$ReportDatatbl.Columns.Add($col15)
$ReportDatatbl.Columns.Add($col16)
$ReportDatatbl.Columns.Add($col17)
$ReportDatatbl.Columns.Add($col18)
$ReportDatatbl.Columns.Add($col19)
$ReportDatatbl.Columns.Add($col20)
$ReportDatatbl.Columns.Add($col21)
$ReportDatatbl.Create()
Write-Host ("Table ReportData created successfully") -ForegroundColor Green
}
else
{
Write-Host ("Table ReportData already exists") -ForegroundColor Yellow
}
#create AzureFeatureParity table
$tableCheck2 = $db.Tables | Where {$_.Name -eq "AzureFeatureParity"}
if(!$tableCheck2)
{
$AzureReportDatatbl = New-Object Microsoft.SqlServer.Management.Smo.Table($db, "AzureFeatureParity")
$col1 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "ImportDate", [Microsoft.SqlServer.Management.Smo.DataType]::DateTime)
$col2 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "ServerName", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(128))
$col3 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "Version", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(15))
$col4 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "Status", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(10))
$col5 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "Category", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col6 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "Severity", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col7 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "FeatureParityCategory", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col8 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "RuleID", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(100))
$col9 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "Title", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(1000))
$col10 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "Impact", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(1000))
$col11 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "Recommendation", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col12 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "MoreInfo", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col13 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "ImpactedDatabasename", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(128))
$col14 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "ImpactedObjectType", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(30))
$col15 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureReportDatatbl, "ImpactDetail", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$AzureReportDatatbl.Columns.Add($col1)
$AzureReportDatatbl.Columns.Add($col2)
$AzureReportDatatbl.Columns.Add($col3)
$AzureReportDatatbl.Columns.Add($col4)
$AzureReportDatatbl.Columns.Add($col5)
$AzureReportDatatbl.Columns.Add($col6)
$AzureReportDatatbl.Columns.Add($col7)
$AzureReportDatatbl.Columns.Add($col8)
$AzureReportDatatbl.Columns.Add($col9)
$AzureReportDatatbl.Columns.Add($col10)
$AzureReportDatatbl.Columns.Add($col11)
$AzureReportDatatbl.Columns.Add($col12)
$AzureReportDatatbl.Columns.Add($col13)
$AzureReportDatatbl.Columns.Add($col14)
$AzureReportDatatbl.Columns.Add($col15)
$AzureReportDatatbl.Create()
Write-Host ("Table AzureFeatureParity created successfully") -ForegroundColor Green
}
else
{
Write-Host ("Table AzureFeatureParity already exists") -ForegroundColor Yellow
}
#create BreakingChangeWeighting table
$tableCheck3 = $db.Tables | Where {$_.Name -eq "BreakingChangeWeighting"}
if(!$tableCheck3)
{
$BreakingChangetbl = New-Object Microsoft.SqlServer.Management.Smo.Table($db, "BreakingChangeWeighting")
$col1 = New-Object Microsoft.SqlServer.Management.Smo.Column($BreakingChangetbl, "RuleId", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(36))
$col1.Nullable = $false
$col2 = New-Object Microsoft.SqlServer.Management.Smo.Column($BreakingChangetbl, "Title", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(150))
$col3 = New-Object Microsoft.SqlServer.Management.Smo.Column($BreakingChangetbl, "Effort", [Microsoft.SqlServer.Management.Smo.DataType]::TinyInt)
$col4 = New-Object Microsoft.SqlServer.Management.Smo.Column($BreakingChangetbl, "FixTime", [Microsoft.SqlServer.Management.Smo.DataType]::TinyInt)
$col5 = New-Object Microsoft.SqlServer.Management.Smo.Column($BreakingChangetbl, "Cost", [Microsoft.SqlServer.Management.Smo.DataType]::TinyInt)
$col6 = New-Object Microsoft.SqlServer.Management.Smo.Column($BreakingChangetbl, "ChangeRank", [Microsoft.SqlServer.Management.Smo.DataType]::TinyInt)
$Col6.Computed = $True
$Col6.ComputedText = "(Effort + FixTime + Cost) / 3"
$BreakingChangetbl.Columns.Add($col1)
$BreakingChangetbl.Columns.Add($col2)
$BreakingChangetbl.Columns.Add($col3)
$BreakingChangetbl.Columns.Add($col4)
$BreakingChangetbl.Columns.Add($col5)
$BreakingChangetbl.Columns.Add($col6)
$BreakingChangetbl.Create()
$PK = New-Object Microsoft.SqlServer.Management.Smo.Index($BreakingChangetbl,"PK_BreakingChangeWeighting_RuleId")
$PK.IndexKeyType = "DriPrimaryKey"
$IdxCol = New-Object Microsoft.SqlServer.Management.Smo.IndexedColumn($PK, $col1.Name)
$PK.IndexedColumns.Add($IdxCol)
$PK.Create()
Write-Host ("Table BreakingChangeWeighting created successfully") -ForegroundColor Green
}
else
{
Write-Host ("Table BreakingChangeWeighting already exists") -ForegroundColor Yellow
}
#Create views
$vwCheck1 = $db.Views | Where {$_.Name -eq "DatabaseCategoryRanking"}
if(!$vwCheck1)
{
$vwDatabaseCategoryRanking = New-Object -TypeName Microsoft.SqlServer.Management.SMO.View -argumentlist $db, "DatabaseCategoryRanking", "dbo"
$vwDatabaseCategoryRanking.TextHeader = "CREATE VIEW [dbo].[DatabaseCategoryRanking] AS"
$vwDatabaseCategoryRanking.TextBody=@"
WITH DatabaseRanking
AS
(
SELECT [Name]
,ChangeCategory
,COUNT(*) AS "NumberOfIssues"
,(CONVERT(NUMERIC(5,2),COUNT(*))/(SELECT CONVERT(NUMERIC(5,2),COUNT(*)) FROM reportdata r2 Where r1.[name] = r2.[name])) * 100 AS "ChangeCategoryPercentage"
FROM reportdata r1
GROUP BY [Name], ChangeCategory
)
SELECT [Name] AS "DatabaseName"
,ChangeCategory
,ChangeCategoryPercentage
FROM DatabaseRanking;
"@
$vwDatabaseCategoryRanking.Create()
Write-Host ("View DatabaseCategoryRanking created successfully") -ForegroundColor Green
}
else
{
Write-Host ("View DatabaseCategoryRanking already exists") -ForegroundColor Yellow
}
$vwCheck2 = $db.Views | Where {$_.Name -eq "UpgradeSuccessRanking"}
if(!$vwCheck2)
{
$vwUpgradeSuccessRanking = New-Object -TypeName Microsoft.SqlServer.Management.SMO.View -argumentlist $db, "UpgradeSuccessRanking", "dbo"
$vwUpgradeSuccessRanking.TextHeader = "CREATE VIEW [dbo].[UpgradeSuccessRanking] AS"
$vwUpgradeSuccessRanking.TextBody=@"
WITH issuecount
AS
(
-- currently doesn't take into account diminishing returns for repeating issues
-- removed NotDefined as these are for feature parity, not migration blockers and should therefore be excluded in calculations
SELECT InstanceName
,NAME
,TargetCompatibilityLevel
,COALESCE(CASE changecategory WHEN 'BehaviorChange' THEN COUNT(*) END,0) AS 'BehaviorChange'
,COALESCE(CASE changecategory WHEN 'Deprecated' THEN COUNT(*) END,0) AS 'DeprecatedCount'
,COALESCE(CASE changecategory WHEN 'BreakingChange' THEN SUM(ChangeRank) END ,0) AS 'BreakingChange'
--,COALESCE(CASE changecategory WHEN 'NotDefined' THEN COUNT(*) END,0) AS 'NotDefined'
,COALESCE(CASE changecategory WHEN 'MigrationBlocker' THEN COUNT(*) END,0) AS 'MigrationBlocker'
FROM reportdata rd
LEFT JOIN BreakingChangeWeighting bcw
ON rd.RuleId = bcw.ruleid
WHERE changecategory != 'NotDefined'
and TargetCompatibilityLevel != 'NA'
GROUP BY InstanceName,name, changecategory, TargetCompatibilityLevel
),
distinctissues
AS
(
SELECT InstanceName
,NAME
,TargetCompatibilityLevel
,MAX(BehaviorChange) AS 'BehaviorChange'
,MAX(DeprecatedCount) AS 'DeprecatedCount'
,MAX(BreakingChange) AS 'BreakingChange'
--,MAX(NotDefined) AS 'NotDefined'
,MAX(MigrationBlocker) AS 'MigrationBlocker'
FROM issuecount
GROUP BY InstanceName,name, TargetCompatibilityLevel
),
IssueTotaled
AS
(
SELECT *, behaviorchange + deprecatedcount + breakingchange + MigrationBlocker AS 'Total'
FROM distinctissues
),
RankedDatabases
AS
(
SELECT InstanceName
,Name
,TargetCompatibilityLevel
,CAST(100-((BehaviorChange + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'BehaviorChange'
,CAST(100-((DeprecatedCount + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'DeprecatedCount'
,CAST(100-((BreakingChange + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'BreakingChange'
--,CAST(100-((NotDefined + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'NotDefined'
,CAST(100-((MigrationBlocker + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'MigrationBlocker'
FROM IssueTotaled
)
-- This section will ensure that if there are 0 issues in a category we return 1. This ensures the reports show data
SELECT InstanceName
,[Name]
,TargetCompatibilityLevel
,CASE WHEN BehaviorChange > 0 THEN BehaviorChange ELSE 1 END AS "BehaviorChange"
,CASE WHEN DeprecatedCount > 0 THEN DeprecatedCount ELSE 1 END AS "DeprecatedCount"
,CASE WHEN BreakingChange > 0 THEN BreakingChange ELSE 1 END AS "BreakingChange"
--,CASE WHEN NotDefined > 0 THEN NotDefined ELSE 1 END AS "NotDefined"
,CASE WHEN MigrationBlocker > 0 THEN MigrationBlocker ELSE 1 END AS "MigrationBlocker"
FROM RankedDatabases
"@
$vwUpgradeSuccessRanking.Create()
Write-Host ("View UpgradeSuccessRanking created successfully") -ForegroundColor Green
}
else
{
Write-Host ("View UpgradeSuccessRanking already exists") -ForegroundColor Yellow
}
$vwCheck3 = $db.Views | Where {$_.Name -eq "UpgradeSuccessRanking_OnPrem"}
if(!$vwCheck3)
{
$vwUpgradeSuccessRankingop = New-Object -TypeName Microsoft.SqlServer.Management.SMO.View -argumentlist $db, "UpgradeSuccessRanking_OnPrem", "dbo"
$vwUpgradeSuccessRankingop.TextHeader = "CREATE VIEW [dbo].[UpgradeSuccessRanking_OnPrem] AS"
$vwUpgradeSuccessRankingop.TextBody=@"
WITH issuecount
AS
(
-- currently doesn't take into account diminishing returns for repeating issues
-- removed NotDefined as these are for feature parity, not migration blockers and should therefore be excluded in calculations
SELECT InstanceName
,NAME
,TargetCompatibilityLevel
,COALESCE(CASE changecategory WHEN 'BehaviorChange' THEN COUNT(*) END,0) AS 'BehaviorChange'
,COALESCE(CASE changecategory WHEN 'Deprecated' THEN COUNT(*) END,0) AS 'DeprecatedCount'
,COALESCE(CASE changecategory WHEN 'BreakingChange' THEN SUM(ChangeRank) END ,0) AS 'BreakingChange'
FROM ReportData rd
LEFT JOIN BreakingChangeWeighting bcw
ON rd.RuleId = bcw.ruleid
WHERE ChangeCategory != 'NotDefined'
AND TargetCompatibilityLevel != 'NA'
AND AssessmentTarget IN ('SqlServer2012', 'SqlServer2014', 'SqlServer2016')
GROUP BY InstanceName,name, changecategory, TargetCompatibilityLevel
),
distinctissues
AS
(
SELECT InstanceName
,NAME
,TargetCompatibilityLevel
,MAX(BehaviorChange) AS 'BehaviorChange'
,MAX(DeprecatedCount) AS 'DeprecatedCount'
,MAX(BreakingChange) AS 'BreakingChange'
FROM issuecount
GROUP BY InstanceName,name, TargetCompatibilityLevel
),
IssueTotaled
AS
(
SELECT *, behaviorchange + deprecatedcount + breakingchange AS 'Total'
FROM distinctissues
),
RankedDatabases
AS
(
SELECT InstanceName
,Name
,TargetCompatibilityLevel
,CAST(100-((BehaviorChange + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'BehaviorChange'
,CAST(100-((DeprecatedCount + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'DeprecatedCount'
,CAST(100-((BreakingChange + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'BreakingChange'
FROM IssueTotaled
)
-- This section will ensure that if there are 0 issues in a category we return 1. This ensures the reports show data
SELECT InstanceName
,[Name]
,TargetCompatibilityLevel
,CASE WHEN BehaviorChange > 0 THEN BehaviorChange ELSE 1 END AS "BehaviorChange"
,CASE WHEN DeprecatedCount > 0 THEN DeprecatedCount ELSE 1 END AS "DeprecatedCount"
,CASE WHEN BreakingChange > 0 THEN BreakingChange ELSE 1 END AS "BreakingChange"
FROM RankedDatabases
"@
$vwUpgradeSuccessRankingop.Create()
Write-Host ("View UpgradeSuccessRanking_OnPrem created successfully") -ForegroundColor Green
}
else
{
Write-Host ("View UpgradeSuccessRanking_OnPrem already exists") -ForegroundColor Yellow
}
$vwCheck4 = $db.Views | Where {$_.Name -eq "UpgradeSuccessRanking_Azure"}
if(!$vwCheck4)
{
$vwUpgradeSuccessRankingaz = New-Object -TypeName Microsoft.SqlServer.Management.SMO.View -argumentlist $db, "UpgradeSuccessRanking_Azure", "dbo"
$vwUpgradeSuccessRankingaz.TextHeader = "CREATE VIEW [dbo].[UpgradeSuccessRanking_Azure] AS"
$vwUpgradeSuccessRankingaz.TextBody=@"
WITH issuecount
AS
(
-- currently doesn't take into account diminishing returns for repeating issues
-- removed NotDefined as these are for feature parity, not migration blockers and should therefore be excluded in calculations
SELECT InstanceName
,NAME
,TargetCompatibilityLevel
,COALESCE(CASE changecategory WHEN 'BehaviorChange' THEN COUNT(*) END,0) AS 'BehaviorChange'
,COALESCE(CASE changecategory WHEN 'Deprecated' THEN COUNT(*) END,0) AS 'DeprecatedCount'
,COALESCE(CASE changecategory WHEN 'BreakingChange' THEN SUM(ChangeRank) END ,0) AS 'BreakingChange'
,COALESCE(CASE changecategory WHEN 'MigrationBlocker' THEN COUNT(*) END,0) AS 'MigrationBlocker'
FROM ReportData rd
LEFT JOIN BreakingChangeWeighting bcw
ON rd.RuleId = bcw.ruleid
WHERE changecategory != 'NotDefined'
AND TargetCompatibilityLevel != 'NA'
AND AssessmentTarget = 'AzureSQLDatabaseV12'
GROUP BY InstanceName, [Name], changecategory, TargetCompatibilityLevel
),
distinctissues
AS
(
SELECT InstanceName
,[Name]
,TargetCompatibilityLevel
,MAX(BehaviorChange) AS 'BehaviorChange'
,MAX(DeprecatedCount) AS 'DeprecatedCount'
,MAX(BreakingChange) AS 'BreakingChange'
,MAX(MigrationBlocker) AS 'MigrationBlocker'
FROM issuecount
GROUP BY InstanceName, [Name], TargetCompatibilityLevel
),
IssueTotaled
AS
(
SELECT *, behaviorchange + deprecatedcount + breakingchange + MigrationBlocker AS 'Total'
FROM distinctissues
),
RankedDatabases
AS
(
SELECT InstanceName
,[Name]
,TargetCompatibilityLevel
,CAST(100-((BehaviorChange + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'BehaviorChange'
,CAST(100-((DeprecatedCount + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'DeprecatedCount'
,CAST(100-((BreakingChange + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'BreakingChange'
,CAST(100-((MigrationBlocker + 0.00) / (total + 0.00)) * 100 AS DECIMAL(5,2)) AS 'MigrationBlocker'
FROM IssueTotaled
)
-- This section will ensure that if there are 0 issues in a category we return 1. This ensures the reports show data
SELECT InstanceName
,[Name]
,TargetCompatibilityLevel
,CASE WHEN BehaviorChange > 0 THEN BehaviorChange ELSE 1 END AS "BehaviorChange"
,CASE WHEN DeprecatedCount > 0 THEN DeprecatedCount ELSE 1 END AS "DeprecatedCount"
,CASE WHEN BreakingChange > 0 THEN BreakingChange ELSE 1 END AS "BreakingChange"
,CASE WHEN MigrationBlocker > 0 THEN MigrationBlocker ELSE 1 END AS "MigrationBlocker"
FROM RankedDatabases
"@
$vwUpgradeSuccessRankingaz.Create()
Write-Host ("View UpgradeSuccessRanking_Azure created successfully") -ForegroundColor Green
}
else
{
Write-Host ("View UpgradeSuccessRanking_Azure already exists") -ForegroundColor Yellow
}
#Create Table Types
$ttCheck = $db.UserDefinedTableTypes | Where {$_.Name -eq "JSONResults"}
if(!$ttCheck)
{
$JSONResultstt = New-Object -TypeName Microsoft.SqlServer.Management.Smo.UserDefinedTableType -ArgumentList $db, "JSONResults"
$col1 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "ImportDate", [Microsoft.SqlServer.Management.Smo.DataType]::DateTime)
$col2 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "InstanceName", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col3 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "Status", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(30))
$col4 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "Name", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(255))
$col5 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "SizeMB", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(30))
$col6 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "SourceCompatibilityLevel", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(15))
$col7 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "TargetCompatibilityLevel", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(15))
$col8 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "Category", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(30))
$col9 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "Severity", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(15))
$col10 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "ChangeCategory", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(20))
$col11 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "RuleId", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(100))
$col12 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "Title", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col13 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "Impact", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col14 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "Recommendation", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col15 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "MoreInfo", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col16 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "ImpactedObjectName", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(255))
$col17 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "ImpactedObjectType", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col18 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "ImpactDetail", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col19 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "DBOwner", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(128))
$col20 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "AssessmentTarget", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col21 = New-Object Microsoft.SqlServer.Management.Smo.Column($JSONResultstt, "AssessmentName", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(128))
$JSONResultstt.Columns.Add($col1)
$JSONResultstt.Columns.Add($col2)
$JSONResultstt.Columns.Add($col3)
$JSONResultstt.Columns.Add($col4)
$JSONResultstt.Columns.Add($col5)
$JSONResultstt.Columns.Add($col6)
$JSONResultstt.Columns.Add($col7)
$JSONResultstt.Columns.Add($col8)
$JSONResultstt.Columns.Add($col9)
$JSONResultstt.Columns.Add($col10)
$JSONResultstt.Columns.Add($col11)
$JSONResultstt.Columns.Add($col12)
$JSONResultstt.Columns.Add($col13)
$JSONResultstt.Columns.Add($col14)
$JSONResultstt.Columns.Add($col15)
$JSONResultstt.Columns.Add($col16)
$JSONResultstt.Columns.Add($col17)
$JSONResultstt.Columns.Add($col18)
$JSONResultstt.Columns.Add($col19)
$JSONResultstt.Columns.Add($col20)
$JSONResultstt.Columns.Add($col21)
$JSONResultstt.Create()
Write-Host ("Table Type JSONResults created successfully") -ForegroundColor Green
}
else
{
Write-Host ("Table Type JSONResults already exists") -ForegroundColor Yellow
}
$ttCheck2 = $db.UserDefinedTableTypes | Where {$_.Name -eq "AzureFeatureParityResults"}
if(!$ttCheck2)
{
$AzureParityResultstt = New-Object -TypeName Microsoft.SqlServer.Management.Smo.UserDefinedTableType -ArgumentList $db, "AzureFeatureParityResults"
$col1 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "ImportDate", [Microsoft.SqlServer.Management.Smo.DataType]::DateTime)
$col2 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "ServerName", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(128))
$col3 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "Version", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(15))
$col4 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "Status", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(10))
$col5 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "Category", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col6 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "Severity", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col7 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "FeatureParityCategory", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(50))
$col8 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "RuleID", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(100))
$col9 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "Title", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(1000))
$col10 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "Impact", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(1000))
$col11 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "Recommendation", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col12 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "MoreInfo", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$col13 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "ImpactedDatabasename", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(128))
$col14 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "ImpactedObjectType", [Microsoft.SqlServer.Management.Smo.DataType]::VarChar(30))
$col15 = New-Object Microsoft.SqlServer.Management.Smo.Column($AzureParityResultstt, "ImpactDetail", [Microsoft.SqlServer.Management.Smo.DataType]::VarCharMax)
$AzureParityResultstt.Columns.Add($col1)
$AzureParityResultstt.Columns.Add($col2)
$AzureParityResultstt.Columns.Add($col3)
$AzureParityResultstt.Columns.Add($col4)
$AzureParityResultstt.Columns.Add($col5)
$AzureParityResultstt.Columns.Add($col6)
$AzureParityResultstt.Columns.Add($col7)
$AzureParityResultstt.Columns.Add($col8)
$AzureParityResultstt.Columns.Add($col9)
$AzureParityResultstt.Columns.Add($col10)
$AzureParityResultstt.Columns.Add($col11)
$AzureParityResultstt.Columns.Add($col12)
$AzureParityResultstt.Columns.Add($col13)
$AzureParityResultstt.Columns.Add($col14)
$AzureParityResultstt.Columns.Add($col15)
$AzureParityResultstt.Create()
Write-Host ("Table Type AzureFeatureParityResults created successfully") -ForegroundColor Green
}
else
{
Write-Host ("Table Type AzureFeatureParityResults already exists") -ForegroundColor Yellow
}
#Create Stored Procedures
$procCheck = $db.StoredProcedures | Where {$_.Name -eq "JSONResults_Insert"}
if(!$procCheck)
{
$JSONResults_Insert = New-Object -TypeName Microsoft.SqlServer.Management.Smo.StoredProcedure -ArgumentList $db, "JSONResults_Insert", "dbo"
$JSONResults_Insert.TextHeader = "CREATE PROCEDURE dbo.JSONResults_Insert @JSONResults JSONResults READONLY AS"
$JSONResults_Insert.TextBody = @"
BEGIN
INSERT INTO dbo.ReportData (ImportDate, InstanceName, [Status], [Name], SizeMB, SourceCompatibilityLevel, TargetCompatibilityLevel, Category, Severity, ChangeCategory, RuleId, Title, Impact, Recommendation, MoreInfo, ImpactedObjectName, ImpactedObjectType, ImpactDetail, DBOwner, AssessmentTarget, AssessmentName)
SELECT ImportDate, InstanceName, [Status], [Name], SizeMB, SourceCompatibilityLevel, TargetCompatibilityLevel, Category, Severity, ChangeCategory, RuleId, Title, Impact, Recommendation, MoreInfo, ImpactedObjectName, ImpactedObjectType, ImpactDetail, DBOwner, AssessmentTarget, AssessmentName
FROM @JSONResults
END
"@
$JSONResults_Insert.Create()
Write-Host ("Stored Procedure JSONNResults_Insert created successfully") -ForegroundColor Green
}
else
{
Write-Host ("Stored Procedure JSONNResults_Insert already exists") -ForegroundColor Yellow
}
$procCheck2 = $db.StoredProcedures | Where {$_.Name -eq "AzureFeatureParityResults_Insert"}
if(!$procCheck2)
{
$AzureFeatureParityResults_Insert = New-Object -TypeName Microsoft.SqlServer.Management.Smo.StoredProcedure -ArgumentList $db, "AzureFeatureParityResults_Insert", "dbo"
$AzureFeatureParityResults_Insert.TextHeader = "CREATE PROCEDURE dbo.AzureFeatureParityResults_Insert @AzureFeatureParityResults AzureFeatureParityResults READONLY AS"
$AzureFeatureParityResults_Insert.TextBody = @"
BEGIN
INSERT INTO dbo.AzureFeatureParity (ImportDate, ServerName, Version, Status, Category, Severity, FeatureParityCategory, RuleID, Title, Impact, Recommendation, MoreInfo, ImpactedDatabasename, ImpactedObjectType, ImpactDetail)
SELECT ImportDate, ServerName, Version, Status, Category, Severity, FeatureParityCategory, RuleID, Title, Impact, Recommendation, MoreInfo, ImpactedDatabasename, ImpactedObjectType, ImpactDetail
FROM @AzureFeatureParityResults
END
"@
$AzureFeatureParityResults_Insert.Create()
Write-Host ("Stored Procedure AzureFeatureParityResults_Insert created successfully") -ForegroundColor Green
}
else
{
Write-Host ("Stored Procedure AzureFeatureParityResults_Insert already exists") -ForegroundColor Yellow
}
# END CREATE DATABASE OBJECTS #
#Make processed directory inside the folder that contains the json files
if(!$jsonDirectory.EndsWith("\"))
{
$jsonDirectory = "$jsonDirectory\"
}
$processedDir = "$jsonDirectory`Processed"
if((Test-Path $processedDir) -eq $false)
{
new-item $processedDir -ItemType directory
Write-Host ("Processed directory created successfully at [$processDir]") -ForegroundColor Green
}
else
{
Write-Host ("Processed directory already exists") -ForegroundColor Yellow
}
 
# if there are no files to process stop importer
$FileCheck = Get-ChildItem $jsonDirectory -Filter *.JSON
if($FileCheck.Count -eq 0)
{
Write-Host ("There are no JSON assessment files to process") -ForegroundColor Yellow
Break
}
$connectionString = "Server=$serverName;Database=$databaseName;Trusted_Connection=True;"
#Populate the breaking change reference data
$RefDataCheck = $db.Tables | Where {$_.Name -eq "BreakingChangeWeighting"} | Select RowCount
if($RefDataCheck.RowCount -eq 0)
{
#populate static data into BreakingChangeWeighting
$CommandText = @'
INSERT INTO BreakingChangeWeighting VALUES ('Microsoft.Rules.Data.Upgrade.UR00001','Syntax issue on the source server',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00006','BACKUP LOG WITH NO_LOG|TRUNCATE_ONLY statements are not supported',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00007','BACKUP/RESTORE TRANSACTION statements are deprecated or discontinued',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00013','COMPUTE clause is not allowed in database compatibility 110',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00020','Read-only databases cannot be upgraded',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00021','Verify all filegroups are writeable during the upgrade process',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00023','SQL Server native SOAP support is discontinued in SQL Server 2014 and above',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00044','Remove user-defined type (UDT)s named after the reserved GEOMETRY and GEOGRAPHY data types',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00050','Table hints in indexed view definitions are ignored in compatibility mode 80 and are not allowed in compatibility mode 90 or above',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00058','After upgrade, new reserved keywords cannot be used as identifiers',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00062','Tables and Columns named NEXT may lead to an error using compatibility Level 110 and above',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00086','XML is a reserved system type name',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00110','New column in output of sp_helptrigger may impact applications',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00113','SQL Mail has been discontinued',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00300','Remove the use of PASSWORD in BACKUP command',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00301','WITH CHECK OPTION is not supported in views that contain TOP in compatibility mode 90 and above',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00302','Discontinued DBCC commands referenced in your T-SQL objects',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00308','Legacy style RAISERROR calls should be replaced with modern equivalents',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00311','Detected statements that reference removed system stored procedures that are not available in database compatibility level 100 and higher',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00318','FOR BROWSE is not allowed in views in 90 or later compatibility modes',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00321','Non ANSI style left outer join usage',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00322','Non ANSI style right outer join usage',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00326','Constant expressions are not allowed in the ORDER BY clause in 90 or later compatibility modes',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00332','FASTFIRSTROW table hint usage',1,1,1),
('Microsoft.Rules.Data.Upgrade.UR00336','Certain XPath functions are not allowed in OPENXML queries',1,1,1)
'@
$conn = New-Object System.Data.SqlClient.SqlConnection $connectionString
$conn.Open() | Out-Null
$cmd = New-Object System.Data.SqlClient.SqlCommand
$cmd.Connection = $conn
$cmd.CommandType = [System.Data.CommandType]"Text"
$cmd.CommandText= $CommandText
$ds=New-Object system.Data.DataSet
$da=New-Object system.Data.SqlClient.SqlDataAdapter($cmd)
$da.fill($ds)
$conn.Close()
}
# importer for SQL2014 and previous versions. Done via PowerShell
Get-ChildItem $jsonDirectory -Filter *.JSON |
Foreach-Object {
$filename = $_.FullName
#ReportData datatable {
$datatable = New-Object -type system.data.datatable
$datatable.columns.add("ImportDate",[DateTime]) | Out-Null
$datatable.columns.add("InstanceName",[String]) | Out-Null
$datatable.columns.add("Status",[String]) | Out-Null
$datatable.columns.add("Name",[String]) | Out-Null
$datatable.columns.add("SizeMB",[String]) | Out-Null
$datatable.columns.add("SourceCompatibilityLevel",[String]) | Out-Null
$datatable.columns.add("TargetCompatibilityLevel",[String]) | Out-Null
$datatable.columns.add("Category",[String]) | Out-Null
$datatable.columns.add("Severity",[String]) | Out-Null
$datatable.columns.add("ChangeCategory",[String]) | Out-Null
$datatable.columns.add("RuleId",[String]) | Out-Null
$datatable.columns.add("Title",[String]) | Out-Null
$datatable.columns.add("Impact",[String]) | Out-Null
$datatable.columns.add("Recommendation",[String]) | Out-Null
$datatable.columns.add("MoreInfo",[String]) | Out-Null
$datatable.columns.add("ImpactedObjectName",[String]) | Out-Null
$datatable.columns.add("ImpactedObjectType",[String]) | Out-Null
$datatable.columns.add("ImpactDetail",[string]) | Out-Null
$datatable.columns.add("DBOwner",[string]) | Out-Null
$datatable.columns.add("AssessmentTarget",[string]) | Out-Null
$datatable.columns.add("AssessmentName",[string]) | Out-Null
#AzureFeatureParity datatable
$azuredatatable = New-Object -type system.data.datatable
$azuredatatable.columns.add("ImportDate",[DateTime]) | Out-Null
$azuredatatable.columns.add("ServerName",[String]) | Out-Null
$azuredatatable.columns.add("Version",[String]) | Out-Null
$azuredatatable.columns.add("Status",[String]) | Out-Null
$azuredatatable.columns.add("Category",[String]) | Out-Null
$azuredatatable.columns.add("Severity",[String]) | Out-Null
$azuredatatable.columns.add("FeatureParityCategory",[String]) | Out-Null
$azuredatatable.columns.add("RuleID",[String]) | Out-Null
$azuredatatable.columns.add("Title",[String]) | Out-Null
$azuredatatable.columns.add("Impact",[String]) | Out-Null
$azuredatatable.columns.add("Recommendation",[String]) | Out-Null
$azuredatatable.columns.add("MoreInfo",[String]) | Out-Null
$azuredatatable.columns.add("ImpactedDatabasename",[String]) | Out-Null
$azuredatatable.columns.add("ImpactedObjectType",[String]) | Out-Null
$azuredatatable.columns.add("ImpactDetail",[String]) | Out-Null
$processStartTime = Get-Date
$datetime = Get-Date
$content = Get-Content $_.FullName -Raw
# when a database assessment fails the assessment recommendations and impacted objects arrays
# will be blank. Setting them to default values allows for the errors to be captured
$blankAssessmentRecommendations = (New-Object PSObject |
Add-Member -PassThru NoteProperty CompatibilityLevel NA |
Add-Member -PassThru NoteProperty Category NA |
Add-Member -PassThru NoteProperty Severity NA |
Add-Member -PassThru NoteProperty ChangeCategory NA |
Add-Member -PassThru NoteProperty RuleId NA |
Add-Member -PassThru NoteProperty Title NA |
Add-Member -PassThru NoteProperty Impact NA |
Add-Member -PassThru NoteProperty Recommendation NA |
Add-Member -PassThru NoteProperty MoreInfo NA |
Add-Member -PassThru NoteProperty ImpactedObjects NA
)
$blankImpactedObjects = (New-Object PSObject |
Add-Member -PassThru NoteProperty Name NA |
Add-Member -PassThru NoteProperty ObjectType NA |
Add-Member -PassThru NoteProperty ImpactDetail NA
)
$blankImpactedDatabases = (New-Object PSObject |
Add-Member -PassThru NoteProperty Name NA |
Add-Member -PassThru NoteProperty ObjectType NA |
Add-Member -PassThru NoteProperty ImpactDetail NA
)
# Start looping through each JSON array
#fill dataset for ReportData table
foreach($obj in (ConvertFrom-Json $content)) #level 1, the actual file
{
foreach($database in $obj.Databases) #level 2, the sources
{
$database.AssessmentRecommendations = if($database.AssessmentRecommendations.Length -eq 0) {$blankAssessmentRecommendations } else {$database.AssessmentRecommendations}
foreach($assessment in $database.AssessmentRecommendations) #level 3, the assessment
{
$assessment.ImpactedObjects = if ($assessment.ImpactedObjects.Length -eq 0) {$blankImpactedObjects} else {$assessment.ImpactedObjects}
foreach($impactedobj in $assessment.ImpactedObjects) #level 4, the impacted objects
{
#TODO Get date here will eventually be replace with timestamp from JSON file
$datatable.rows.add((Get-Date).toString(), $database.ServerName, $database.Status, $database.Name, $database.SizeMB, $database.CompatibilityLevel, $assessment.CompatibilityLevel, $assessment.Category, $assessment.severity, $assessment.ChangeCategory, $assessment.RuleId, $assessment.Title, $assessment.Impact, $assessment.Recommendation, $assessment.MoreInfo, $impactedobj.Name, $impactedobj.ObjectType, $impactedobj.ImpactDetail, $null, $obj.TargetPlatform, $obj.Name) | Out-Null
}
}
}
}
#fill data set for AzureFeatureParity table
foreach($obj in (ConvertFrom-Json $content)) #level 1, the actual file
{
foreach($serverInstances in $obj.ServerInstances) #level 2, the ServerInstances
{
foreach($assessment in $serverInstances.AssessmentRecommendations) #level 3, the assessment
{
$assessment.ImpactedDatabases = if ($assessment.ImpactedDatabases.Length -eq 0) {$blankImpactedDatabases} else {$assessment.ImpactedDatabases}
foreach($impacteddbs in $assessment.ImpactedDatabases) #level 4, the impacted objects
{
#TODO Get date here will eventually be replace with timestamp from JSON file
$azuredatatable.rows.add((Get-Date).toString(), $serverInstances.ServerName, $serverInstances.Version, $serverInstances.Status, $assessment.Category, $assessment.Severity, $assessment.FeatureParityCategory, $assessment.RuleId, $assessment.Title, $assessment.Impact, $assessment.Recommendation, $assessment.MoreInfo, $impacteddbs.Name, $impacteddbs.ObjectType, $impacteddbs.ImpactDetail) | Out-Null
}
}
}
}
$rowcount_rd = $datatable.rows.Count
$rowcount_afp = $azuredatatable.rows.Count
$query1='dbo.JSONResults_Insert'
$query2='dbo.AzureFeatureParityResults_Insert'
#Connect
$conn = New-Object System.Data.SqlClient.SqlConnection $connectionString
$conn.Open() | Out-Null
$cmd1 = New-Object System.Data.SqlClient.SqlCommand
$cmd1.Connection = $conn
$cmd1.CommandType = [System.Data.CommandType]"StoredProcedure"
$cmd1.CommandText= $query1
$cmd1.Parameters.Add("@JSONResults" , [System.Data.SqlDbType]::Structured) | Out-Null
$cmd1.Parameters["@JSONResults"].Value =$datatable
$cmd2 = New-Object System.Data.SqlClient.SqlCommand
$cmd2.Connection = $conn
$cmd2.CommandType = [System.Data.CommandType]"StoredProcedure"
$cmd2.CommandText= $query2
$cmd2.Parameters.Add("@AzureFeatureParityResults" , [System.Data.SqlDbType]::Structured) | Out-Null
$cmd2.Parameters["@AzureFeatureParityResults"].Value = $azuredatatable
$ds1=New-Object system.Data.DataSet
$da1=New-Object system.Data.SqlClient.SqlDataAdapter($cmd1)
$ds2=New-Object system.Data.DataSet
$da2=New-Object system.Data.SqlClient.SqlDataAdapter($cmd2)
# ensure that the dataset can write to the database, if not the dont move the file to processed directory
try
{
$da1.fill($ds1) | Out-Null
$da2.fill($ds2) | out-null
try
{
Move-Item $filename $processedDir -Force
}
catch
{
write-host("Error moving file $filename to directory") -ForegroundColor Red
$error[0]|format-list -force
}
}
catch
{
$rowcount_rd = 0
$rowcount_afp = 0
write-host("Error writing results for file $filename to database") -ForegroundColor Red
$error[0]|format-list -force
}
$conn.Close()
$processEndTime = Get-Date
$processTime = NEW-TIMESPAN -Start $processStartTime -End $processEndTime
Write-Host("Rows Processed for ReportData Table = $rowcount_rd Rows processed for AzureFeatureParityTable = $rowcount_afp for file $filename Total Processing Time = $processTime")
$datatable.Clear()
$azuredatatable.Clear()
}
}
#------------------------------------------------------------------------------------ END FUNCTIONS ------------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------- EXECUTE FUNCTIONS --------------------------------------------------------------------------------------
dmaProcessor -serverName localhost `
-databaseName DMAReporting `
-jsonDirectory "C:\DMAResults\" `
-processTo SQLServer
# To process on a named instance use SERVERNAME\INSTANCENAME as the -serverName
#------------------------------------------------------------------------------------ END EXECUTE FUNCTIONS ------------------------------------------------------------------------------------
@@ -0,0 +1,77 @@
# PowerShell Script for Importing Assessment Results
This contains a PowerShell script for importing assessment results from JSON files into a SQL Server database. Assessments are generated using Data Migration Assistant, to evaluate moving data to SQL Server or to Azure SQL Database.
### Contents
[About this sample](#about-this-sample)<br/>
[Before you begin](#before-you-begin)<br/>
[Run this sample](#run-this-sample)<br/>
[Sample details](#sample-details)<br/>
[Disclaimers](#disclaimers)<br/>
[Related links](#related-links)<br/>
<a name=about-this-sample></a>
## About this sample
- **Applies to:** SQL Server 2016 (or higher), Azure SQL Database
- **Key features:** Migration assessments
- **Programming Language:** PowerShell
- **Authors:** Chris Lound
<a name=before-you-begin></a>
## Before you begin
To run this sample, you need the following prerequisites.
**Software prerequisites:**
1. PowerShell
2. SQL Server 2016 (or higher) or an Azure SQL Database
3. Data Migration Assistant
**Azure prerequisites:**
1. Permission to create an Azure SQL Database
<a name=run-this-sample></a>
## Run this sample
1. Open the script in a text editor and add the following values to the EXECUTE FUNCTIONS section.
- serverName
- databaseName
- jsonDirectory
- processTo
For more information, see [Consolidate Assessment Reports](https://docs.microsoft.com/sql/dma/dma-consolidatereports).
2. Set PowerShell execution policy to bypass for current session, as follows.
`Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass`
1. Run the script in PowerShell.
<a name=sample-details></a>
## Sample details
PowerShell script for imports assessment results from JSON files into a SQL Server database. The results are imported into the table ReportData. Views, stored procedures, and table types are created in the SQL Server instance and database that you specified in the script. For more information, see [Consolidate Assessment Reports](https://docs.microsoft.com/sql/dma/dma-consolidatereports).
<a name=disclaimers></a>
## Disclaimers
This sample code is provided for the purpose of illustration only and is not intended to be used in a production environment. The sample code and any related information are provided "as is" without warranty of any kind, either expressed or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose.
<a name=related-links></a>
## Related Links
For more information, see these articles:
[Consolidate Assessment Reports](https://docs.microsoft.com/sql/dma/dma-consolidatereports)
@@ -0,0 +1,8 @@
# Samples for Data Migration Assistant
[Power BI Reports for Consolidated Migration Assessments](Power BI Reports/README.md)
You can use the Power BI reports to view consolidated migration assessments. You can modify these reports to work with your environment.
[PowerShell Script for Importing Assessment Results](PowerShell Script/README.md)
You can use the PowerShell script to import assessment results from JSON files into a SQL Server database.
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{F14B399A-7131-4C87-9E4B-1186C45EF12D}") = "PolicyReports", "PolicyReports\PolicyReports.rptproj", "{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Default = Debug|Default
DebugLocal|Default = DebugLocal|Default
Release|Default = Release|Default
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Debug|Default.ActiveCfg = Debug
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Debug|Default.Build.0 = DebugLocal
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Debug|Default.Deploy.0 = DebugLocal
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.DebugLocal|Default.ActiveCfg = DebugLocal
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.DebugLocal|Default.Build.0 = DebugLocal
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Release|Default.ActiveCfg = Release
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Release|Default.Build.0 = Release
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Release|Default.Deploy.0 = Release
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{F14B399A-7131-4C87-9E4B-1186C45EF12D}") = "PolicyReports", "PolicyReports.rptproj", "{E0F65769-8BEA-4BFD-B715-44519AF1CF80}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Default = Debug|Default
DebugLocal|Default = DebugLocal|Default
Release|Default = Release|Default
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E0F65769-8BEA-4BFD-B715-44519AF1CF80}.Debug|Default.ActiveCfg = Debug
{E0F65769-8BEA-4BFD-B715-44519AF1CF80}.Debug|Default.Build.0 = DebugLocal
{E0F65769-8BEA-4BFD-B715-44519AF1CF80}.Debug|Default.Deploy.0 = DebugLocal
{E0F65769-8BEA-4BFD-B715-44519AF1CF80}.DebugLocal|Default.ActiveCfg = DebugLocal
{E0F65769-8BEA-4BFD-B715-44519AF1CF80}.DebugLocal|Default.Build.0 = DebugLocal
{E0F65769-8BEA-4BFD-B715-44519AF1CF80}.DebugLocal|Default.Deploy.0 = DebugLocal
{E0F65769-8BEA-4BFD-B715-44519AF1CF80}.Release|Default.ActiveCfg = Release
{E0F65769-8BEA-4BFD-B715-44519AF1CF80}.Release|Default.Build.0 = Release
{E0F65769-8BEA-4BFD-B715-44519AF1CF80}.Release|Default.Deploy.0 = Release
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{F14B399A-7131-4C87-9E4B-1186C45EF12D}") = "PolicyReports", "PolicyReports\PolicyReports.rptproj", "{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Default = Debug|Default
DebugLocal|Default = DebugLocal|Default
Release|Default = Release|Default
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Debug|Default.ActiveCfg = Debug
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Debug|Default.Build.0 = DebugLocal
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Debug|Default.Deploy.0 = DebugLocal
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.DebugLocal|Default.ActiveCfg = DebugLocal
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.DebugLocal|Default.Build.0 = DebugLocal
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Release|Default.ActiveCfg = Release
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Release|Default.Build.0 = Release
{30FA2CD3-F4E3-4EA6-85A7-07AF4D922933}.Release|Default.Deploy.0 = Release
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -2,6 +2,10 @@
Sample order processing workload that can be used for benchmarking transactional processing with in-memory technologies. The scripts in this folder leverage the In-Memory OLTP feature in SQL Server 2016.
Some results from this benchmark:
* [4 Terabyte and 343,000 transactions per second with SQL Server 2016 on Hyper-V](https://blogs.technet.microsoft.com/windowsserver/2016/09/28/windows-server-2016-hyper-v-large-scale-vm-performance-for-in-memory-transaction-processing/)
* [11X perf gain with In-Memory OLTP in Azure SQL Database](https://azure.microsoft.com/blog/in-memory-oltp-in-azure-sql-database/)
<a name=about-this-sample></a>
## About this sample
@@ -0,0 +1,119 @@
# Load packages.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import revoscalepy as revoscale
from scipy.spatial import distance as sci_distance
from sklearn import cluster as sk_cluster
def perform_clustering():
################################################################################################
## Connect to DB and select data
################################################################################################
# Connection string to connect to SQL Server named instance.
conn_str = 'Driver=SQL Server;Server=localhost;Database=tpcxbb_1gb;Trusted_Connection=True;'
input_query = '''SELECT
ss_customer_sk AS customer,
ROUND(COALESCE(returns_count / NULLIF(1.0*orders_count, 0), 0), 7) AS orderRatio,
ROUND(COALESCE(returns_items / NULLIF(1.0*orders_items, 0), 0), 7) AS itemsRatio,
ROUND(COALESCE(returns_money / NULLIF(1.0*orders_money, 0), 0), 7) AS monetaryRatio,
COALESCE(returns_count, 0) AS frequency
FROM
(
SELECT
ss_customer_sk,
-- return order ratio
COUNT(distinct(ss_ticket_number)) AS orders_count,
-- return ss_item_sk ratio
COUNT(ss_item_sk) AS orders_items,
-- return monetary amount ratio
SUM( ss_net_paid ) AS orders_money
FROM store_sales s
GROUP BY ss_customer_sk
) orders
LEFT OUTER JOIN
(
SELECT
sr_customer_sk,
-- return order ratio
count(distinct(sr_ticket_number)) as returns_count,
-- return ss_item_sk ratio
COUNT(sr_item_sk) as returns_items,
-- return monetary amount ratio
SUM( sr_return_amt ) AS returns_money
FROM store_returns
GROUP BY sr_customer_sk ) returned ON ss_customer_sk=sr_customer_sk'''
# Define the columns we wish to import.
column_info = {
"customer": {"type": "integer"},
"orderRatio": {"type": "integer"},
"itemsRatio": {"type": "integer"},
"frequency": {"type": "integer"}
}
data_source = revoscale.RxSqlServerData(sql_query=input_query, column_info=column_info,
connection_string=conn_str)
# import data source and convert to pandas dataframe.
customer_data = pd.DataFrame(revoscalepy.rx_import(data_source))
print("Data frame:", customer_data.head(n=20))
################################################################################################
## Determine number of clusters using the Elbow method
################################################################################################
cdata = customer_data
K = range(1, 20)
KM = (sk_cluster.KMeans(n_clusters=k).fit(cdata) for k in K)
centroids = (k.cluster_centers_ for k in KM)
D_k = (sci_distance.cdist(cdata, cent, 'euclidean') for cent in centroids)
dist = (np.min(D, axis=1) for D in D_k)
avgWithinSS = [sum(d) / cdata.shape[0] for d in dist]
plt.plot(K, avgWithinSS, 'b*-')
plt.grid(True)
plt.xlabel('Number of clusters')
plt.ylabel('Average within-cluster sum of squares')
plt.title('Elbow for KMeans clustering')
plt.show()
################################################################################################
## Perform clustering using Kmeans
################################################################################################
# It looks like k=4 is a good number to use based on the elbow graph.
n_clusters = 4
means_cluster = sk_cluster.KMeans(n_clusters=n_clusters, random_state=111)
columns = ["orderRatio", "itemsRatio", "monetaryRatio", "frequency"]
est = means_cluster.fit(customer_data[columns])
clusters = est.labels_
customer_data['cluster'] = clusters
# Print some data about the clusters:
# For each cluster, count the members.
for c in range(n_clusters):
cluster_members=customer_data[customer_data['cluster'] == c][:]
print('Cluster{}(n={}):'.format(c, len(cluster_members)))
print('-'* 17)
# Print mean values per cluster.
print(customer_data.groupby(['cluster']).mean())
perform_clustering()
@@ -0,0 +1,100 @@
USE [tpcxbb_1gb]
GO
-- Stored procedure that performs customer clustering using Python and SQL Server ML Services
CREATE OR ALTER PROCEDURE [dbo].[py_generate_customer_return_clusters]
AS
BEGIN
DECLARE
-- Input query to generate the purchase history & return metrics
@input_query NVARCHAR(MAX) = N'
SELECT
ss_customer_sk AS customer,
CAST( (ROUND(COALESCE(returns_count / NULLIF(1.0*orders_count, 0), 0), 7) ) AS FLOAT) AS orderRatio,
CAST( (ROUND(COALESCE(returns_items / NULLIF(1.0*orders_items, 0), 0), 7) ) AS FLOAT) AS itemsRatio,
CAST( (ROUND(COALESCE(returns_money / NULLIF(1.0*orders_money, 0), 0), 7) ) AS FLOAT) AS monetaryRatio,
CAST( (COALESCE(returns_count, 0)) AS FLOAT) AS frequency
FROM
(
SELECT
ss_customer_sk,
-- return order ratio
COUNT(distinct(ss_ticket_number)) AS orders_count,
-- return ss_item_sk ratio
COUNT(ss_item_sk) AS orders_items,
-- return monetary amount ratio
SUM( ss_net_paid ) AS orders_money
FROM store_sales s
GROUP BY ss_customer_sk
) orders
LEFT OUTER JOIN
(
SELECT
sr_customer_sk,
-- return order ratio
count(distinct(sr_ticket_number)) as returns_count,
-- return ss_item_sk ratio
COUNT(sr_item_sk) as returns_items,
-- return monetary amount ratio
SUM( sr_return_amt ) AS returns_money
FROM store_returns
GROUP BY sr_customer_sk
) returned ON ss_customer_sk=sr_customer_sk
'
EXEC sp_execute_external_script
@language = N'Python'
, @script = N'
import pandas as pd
from sklearn.cluster import KMeans
#We concluded in step2 in the tutorial that 4 would be a good number of clusters
n_clusters = 4
#Perform clustering
est = KMeans(n_clusters=n_clusters, random_state=111).fit(customer_data[["orderRatio","itemsRatio","monetaryRatio","frequency"]])
clusters = est.labels_
customer_data["cluster"] = clusters
#OutputDataSet = customer_data
'
, @input_data_1 = @input_query
, @input_data_1_name = N'customer_data'
,@output_data_1_name = N'customer_data'
with result sets (("Customer" int, "orderRatio" float,"itemsRatio" float,"monetaryRatio" float,"frequency" float,"cluster" float));
END;
GO
--Creating a table for storing the clustering data
DROP TABLE IF EXISTS [dbo].[py_customer_clusters];
GO
--Create a table to store the predictions in
CREATE TABLE [dbo].[py_customer_clusters](
[Customer] [bigint] NULL,
[OrderRatio] [float] NULL,
[itemsRatio] [float] NULL,
[monetaryRatio] [float] NULL,
[frequency] [float] NULL,
[cluster] [int] NULL,
) ON [PRIMARY]
GO
--Execute the clustering and insert results into table
INSERT INTO py_customer_clusters
EXEC [dbo].[py_generate_customer_return_clusters];
-- Select contents of the table
SELECT * FROM py_customer_clusters;
--Get email addresses of customers in cluster 0
SELECT customer.[c_email_address], customer.c_customer_sk
FROM dbo.customer
JOIN
[dbo].[py_customer_clusters] as c
ON c.Customer = customer.c_customer_sk
WHERE c.cluster = 0;
@@ -2,68 +2,72 @@ import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from revoscalepy.computecontext.RxInSqlServer import RxInSqlServer
from revoscalepy.computecontext.RxInSqlServer import RxSqlServerData
from revoscalepy.etl.RxImport import rx_import_datasource
#If you are running SQL Server 2017 RC1 and above:
from revoscalepy import RxComputeContext, RxInSqlServer, RxSqlServerData
from revoscalepy import rx_import
def get_rental_predictions():
conn_str = 'Driver=SQL Server;Server=MYSQLSERVER;Database=TutorialDB;Trusted_Connection=True;'
column_info = {
"Year" : { "type" : "integer" },
"Month" : { "type" : "integer" },
"Day" : { "type" : "integer" },
"RentalCount" : { "type" : "integer" },
"WeekDay" : {
"type" : "factor",
"levels" : ["1", "2", "3", "4", "5", "6", "7"]
},
"Holiday" : {
"type" : "factor",
"levels" : ["1", "0"]
},
"Snow" : {
"type" : "factor",
"levels" : ["1", "0"]
}
}
#Connection string to connect to SQL Server named instance
conn_str = 'Driver=SQL Server;Server=MYSQLSERVER;Database=TutorialDB;Trusted_Connection=True;'
data_source = RxSqlServerData(table="dbo.rental_data",
connectionString=conn_str, colInfo=column_info)
computeContext = RxInSqlServer(
connectionString = conn_str,
numTasks = 1,
autoCleanup = False
)
RxInSqlServer(connectionString=conn_str, numTasks=1, autoCleanup=False)
# import data source and convert to pandas dataframe
df = pd.DataFrame(rx_import_datasource(data_source))
print("Data frame:", df)
# Get all the columns from the dataframe.
columns = df.columns.tolist()
# Filter the columns to remove ones we don't want.
columns = [c for c in columns if c not in ["Year"]]
# Store the variable we'll be predicting on.
target = "RentalCount"
# Generate the training set. Set random_state to be able to replicate results.
train = df.sample(frac=0.8, random_state=1)
# Select anything not in the training set and put it in the testing set.
test = df.loc[~df.index.isin(train.index)]
# Print the shapes of both sets.
print("Training set shape:", train.shape)
print("Testing set shape:", test.shape)
# Initialize the model class.
lin_model = LinearRegression()
# Fit the model to the training data.
lin_model.fit(train[columns], train[target])
# Generate our predictions for the test set.
lin_predictions = lin_model.predict(test[columns])
print("Predictions:", lin_predictions)
# Compute error between our test predictions and the actual values.
lin_mse = mean_squared_error(lin_predictions, test[target])
print("Computed error:", lin_mse)
#Define the columns we wish to import
column_info = {
"Year" : { "type" : "integer" },
"Month" : { "type" : "integer" },
"Day" : { "type" : "integer" },
"RentalCount" : { "type" : "integer" },
"WeekDay" : {
"type" : "factor",
"levels" : ["1", "2", "3", "4", "5", "6", "7"]
},
"Holiday" : {
"type" : "factor",
"levels" : ["1", "0"]
},
"Snow" : {
"type" : "factor",
"levels" : ["1", "0"]
}
}
#Get the data from SQL Server Table
data_source = RxSqlServerData(table="dbo.rental_data",
connection_string=conn_str, column_info=column_info)
computeContext = RxInSqlServer(
connection_string = conn_str,
num_tasks = 1,
auto_cleanup = False
)
RxInSqlServer(connection_string=conn_str, num_tasks=1, auto_cleanup=False)
# import data source and convert to pandas dataframe
df = pd.DataFrame(rx_import(input_data = data_source))
print("Data frame:", df)
# Get all the columns from the dataframe.
columns = df.columns.tolist()
# Filter the columns to remove ones we don't want to use in the training
columns = [c for c in columns if c not in ["Year"]]
# Store the variable we'll be predicting on.
target = "RentalCount"
# Generate the training set. Set random_state to be able to replicate results.
train = df.sample(frac=0.8, random_state=1)
# Select anything not in the training set and put it in the testing set.
test = df.loc[~df.index.isin(train.index)]
# Print the shapes of both sets.
print("Training set shape:", train.shape)
print("Testing set shape:", test.shape)
# Initialize the model class.
lin_model = LinearRegression()
# Fit the model to the training data.
lin_model.fit(train[columns], train[target])
# Generate our predictions for the test set.
lin_predictions = lin_model.predict(test[columns])
print("Predictions:", lin_predictions)
# Compute error between our test predictions and the actual values.
lin_mse = mean_squared_error(lin_predictions, test[target])
print("Computed error:", lin_mse)
get_rental_predictions()
@@ -27,23 +27,24 @@ BEGIN
@language = N'Python'
, @script = N'
from sklearn import linear_model
import pickle
df = rental_train_data
# Get all the columns from the dataframe.
columns = df.columns.tolist()
# Store the variable well be predicting on.
target = "RentalCount"
from sklearn.linear_model import LinearRegression
# Initialize the model class.
lin_model = LinearRegression()
lin_model = linear_model.LinearRegression()
# Fit the model to the training data.
lin_model.fit(df[columns], df[target])
import pickle
#Before saving the model to the DB table, we need to convert it to a binary object
trained_model = pickle.dumps(lin_model)
'
@@ -75,7 +76,7 @@ AS
BEGIN
DECLARE @py_model varbinary(max) = (select model from rental_py_models where model_name = @model);
EXEC sp_execute_external_script
EXEC sp_execute_external_script
@language = N'Python'
, @script = N'
@@ -83,7 +84,7 @@ BEGIN
import pickle
rental_model = pickle.loads(py_model)
df = rental_score_data
#print(df)
@@ -106,7 +107,7 @@ lin_mse = mean_squared_error(lin_predictions, df[target])
#print(lin_mse)
import pandas as pd
predictions_df = pd.DataFrame(lin_predictions)
predictions_df = pd.DataFrame(lin_predictions)
OutputDataSet = pd.concat([predictions_df, df["RentalCount"], df["Month"], df["Day"], df["WeekDay"], df["Snow"], df["Holiday"], df["Year"]], axis=1)
'
, @input_data_1 = N'Select "RentalCount", "Year" ,"Month", "Day", "WeekDay", "Snow", "Holiday" from rental_data where Year = 2015'
@@ -114,7 +115,7 @@ OutputDataSet = pd.concat([predictions_df, df["RentalCount"], df["Month"], df["D
, @params = N'@py_model varbinary(max)'
, @py_model = @py_model
with result sets (("RentalCount_Predicted" float, "RentalCount" float, "Month" float,"Day" float,"WeekDay" float,"Snow" float,"Holiday" float, "Year" float));
END;
GO
+6 -2
View File
@@ -10,7 +10,11 @@ Master Data Services (MDS) is the SQL Server solution for master data management
[R Services](r-services)
SQL Server R Services brings R processing close to the data, allowing more scalable and more efficient predictive analytics.
SQL Server R Services (in SQL Server 2016 and above) brings R processing close to the data, allowing more scalable and more efficient predictive analytics using R in-database.
[ML Services](ml-services)
SQL Server ML Services (SQL Server 2017) brings Python processing close to the data, allowing more scalable and more efficient predictive analytics using Python in-database.
[JSON Support](json)
@@ -28,4 +32,4 @@ Graph tables enable you to add a non-relational capability to your database.
[Reporting Services (SSRS)](reporting-services)
Reporting Services provides reporting capabilities for your organziation. Reporting Services can be integrated with SharePoint Server or used as a standalone service.
Reporting Services provides reporting capabilities for your organziation. Reporting Services can be integrated with SharePoint Server or used as a standalone service.
@@ -25,6 +25,6 @@ foreach($blob in $blobs)
{
echo ("Deleting blob " + $blob.Name)
# Delete the blob.e
Remove-AzureStorageBlob -Container $storageContainer -Context $context -Blob $blob.Name;
Remove-AzureStorageBlob -Container $storageContainerName -Context $context -Blob $blob.Name;
}
}
}