Veeam_VE_Widget_PerformanceForecast_Install.sql (Resource)

Element properties:

TypeResource
File NameVeeam_VE_Widget_PerformanceForecast_Install.sql
AccessibilityInternal

Source Code:

<Resource ID="Veeam_VE_Widget_PerformanceForecast_Install.sql" Accessibility="Internal" FileName="Veeam_VE_Widget_PerformanceForecast_Install.sql" HasNullStream="false"/>

File Content: Veeam_VE_Widget_PerformanceForecast_Install.sql

 -- ##### Veeam_VE_HyperV_ThresholdsTransformedGet_CreateAlter.sql

IF NOT EXISTS (SELECT * FROM sys.objects WHERE [schema_id]=SCHEMA_ID('dbo') AND type = 'P' AND name = 'Veeam_VE_Widget_ThresholdsTransformedGet')
BEGIN
EXECUTE ('CREATE PROCEDURE dbo.[Veeam_VE_Widget_ThresholdsTransformedGet] AS RETURN 1')
END
GO

ALTER PROCEDURE dbo.[Veeam_VE_Widget_ThresholdsTransformedGet]
@ReportSystemName NVARCHAR(256),
@Thresholds XML,
@SelectedAspects XML = NULL,
@IsXmlMode BIT = 0,
@OutputXml XML = NULL OUT
AS
BEGIN
BEGIN TRY

DECLARE @Config XML
DECLARE @OptionsXml XML

DECLARE @ThresholdsTransforms XML

SELECT @OptionsXml=vgr.Options
FROM [dbo].[Veeam_GRL_Report] vgr
WHERE vgr.ReportSystemName=@ReportSystemName

SET @Config = @OptionsXml.query('/Options[1]/PerfAnalysisConfig[1]')
SET @ThresholdsTransforms = @OptionsXml.query('/Options[1]/ThresholdsTransforms[1]')

IF OBJECT_ID('tempdb..#thresholds') IS NOT NULL DROP TABLE #thresholds

CREATE TABLE #thresholds
(
TargetId NVARCHAR(64),
AspectId NVARCHAR(64),
InputUnit NVARCHAR(64),
[OriginalValue] FLOAT,
[Value] FLOAT
)

INSERT INTO #thresholds
(
TargetId,
AspectId,
InputUnit,
OriginalValue,
[Value]
)

SELECT
TargetId = f.t.value('@TargetId','nvarchar(64)'),
AspectId = f.t.value('@AspectId','nvarchar(64)'),
InputUnit = f.t.value('@InputUnit','nvarchar(64)'),
OriginalValue = t.i.value('@Value','float'),
[Value] = t.i.value('@Value','float')*f.t.value('@Multiplier','float')
FROM
@Thresholds.nodes('/Thresholds/Threshold') AS t(i)
INNER JOIN @ThresholdsTransforms.nodes('/ThresholdsTransforms/ThresholdsTransform') AS f(t)
ON t.i.value('@Id','int') = f.t.value('@ThresholdId','int')
LEFT OUTER JOIN @SelectedAspects.nodes('/SelectedAspects/SelectedAspect') AS s(a)
ON f.t.value('@TargetId','nvarchar(64)')=s.a.value('@TargetId','nvarchar(64)') AND f.t.value('@AspectId','nvarchar(64)')=s.a.value('@AspectId','nvarchar(64)')
WHERE
s.a.value('@AspectId','nvarchar(64)') IS NOT NULL OR @SelectedAspects IS NULL

IF @IsXmlMode=1
BEGIN
SET @OutputXml = (
SELECT
t.TargetId, t.AspectId, t.[Value]
FROM
#thresholds t
FOR XML RAW('Threshold'), ROOT('Thresholds')

)
END
ELSE
BEGIN

;WITH x (TargetId, TargetClassName, AspectId, AspectName)
AS
(
SELECT
TargetId = cfg.aspect.value('../@Id','nvarchar(64)'),
TargetClassName = vmet.ManagedEntityTypeDefaultName,
AspectId = cfg.aspect.value('@Id','nvarchar(64)'),
AspectName = cfg.aspect.value('@Name','nvarchar(max)')
FROM
@Config.nodes('/PerfAnalysisConfig/Target/Aspect') AS cfg(aspect)
INNER JOIN [dbo].[vManagedEntityType] vmet ON vmet.ManagedEntityTypeSystemName=cfg.aspect.value('../@ManagedEntityTypeSystemName','nvarchar(512)')
)
SELECT
x.TargetClassName,
x.AspectName,
t.InputUnit,
t.OriginalValue,
t.[Value]
FROM
#thresholds t
INNER JOIN x x ON x.TargetId = t.TargetId AND x.AspectId = t.AspectId

END

IF OBJECT_ID('tempdb..#thresholds') IS NOT NULL DROP TABLE #thresholds

END TRY
BEGIN CATCH
IF OBJECT_ID('tempdb..#thresholds') IS NOT NULL DROP TABLE #thresholds

DECLARE @errMsg VARCHAR(1024)
SET @errMsg = ERROR_MESSAGE()

RAISERROR(@errMsg, 16, 1)
END CATCH
END
GO

GRANT EXECUTE ON dbo.[Veeam_VE_Widget_ThresholdsTransformedGet] TO OpsMgrReader
GO

-- ##### Veeam_VE_HyperV_PerformanceForecastGet_CreateAlter.sql
IF NOT EXISTS (SELECT * FROM sys.objects WHERE [schema_id]=SCHEMA_ID('dbo') AND type = 'P' AND name = 'Veeam_VE_Widget_PerformanceForecastGet')
BEGIN
EXECUTE ('CREATE PROCEDURE dbo.[Veeam_VE_Widget_PerformanceForecastGet] AS RETURN 1')
END
GO

ALTER PROCEDURE dbo.[Veeam_VE_Widget_PerformanceForecastGet]
@StartDate DATETIME,
@EndDate DATETIME,
@ReportSystemName NVARCHAR(256),
@ObjectList XML,
@RawThresholds XML,
@SelectedAspects XML = NULL,
@ThresholdOverrides XML = NULL,
@IsXmlMode BIT = 0,
@OutputXml XML = NULL OUT
AS
BEGIN
SET NOCOUNT ON

BEGIN TRY
IF GETUTCDATE() BETWEEN @StartDate AND @EndDate
AND GETUTCDATE()<@EndDate
BEGIN

DECLARE @Config XML
DECLARE @OptionsXml XML

SELECT @OptionsXml=vgr.Options
FROM [dbo].[Veeam_GRL_Report] vgr
WHERE vgr.ReportSystemName=@ReportSystemName

SET @Config = @OptionsXml.query('/Options[1]/PerfAnalysisConfig[1]')

IF OBJECT_ID('tempdb..#target') IS NOT NULL DROP TABLE #target
IF OBJECT_ID('tempdb..#aspect') IS NOT NULL DROP TABLE #aspect
IF OBJECT_ID('tempdb..#targetObj') IS NOT NULL DROP TABLE #targetObj
IF OBJECT_ID('tempdb..#objAspect') IS NOT NULL DROP TABLE #objAspect
IF OBJECT_ID('tempdb..#objSummary') IS NOT NULL DROP TABLE #objSummary
IF OBJECT_ID('tempdb..#objAspectPerformance') IS NOT NULL DROP TABLE #objAspectPerformance

CREATE TABLE #target
(
TargetRowId INT IDENTITY PRIMARY KEY,
TargetId NVARCHAR(64) NOT NULL,
ManagedEntityTypeSystemName NVARCHAR(512) NOT NULL,
ManagedEntityTypeRowId INT NOT NULL
)

CREATE TABLE #aspect
(
AspectRowId INT IDENTITY PRIMARY KEY,
TargetRowId INT NOT NULL,

TargetId NVARCHAR(64) NOT NULL,
AspectId NVARCHAR(64) NOT NULL,
AspectName NVARCHAR(MAX) NOT NULL,

Position INT NULL,

IsPropertyBased BIT NOT NULL,
Containment NVARCHAR(16) NOT NULL,
InstanceAggregationFunction NVARCHAR(8) NOT NULL,
RuleSystemName NVARCHAR(512) NOT NULL,
RuleRowId INT NOT NULL,
RuleGUID UNIQUEIDENTIFIER NOT NULL,

PropertyName NVARCHAR(256) NULL,
PropertyMultiplier FLOAT NULL,
PropertyGuid UNIQUEIDENTIFIER NULL,

MeasurementUnitName NVARCHAR(256),
PerformanceDataMultiplier FLOAT DEFAULT 1,

Threshold FLOAT NULL,
IsFloorThreshold BIT NOT NULL,

SuppressResourceOutput BIT DEFAULT 0,

RecommendationTemplate NVARCHAR(MAX) NULL,
RecommendationTemplateOverall NVARCHAR(MAX) NULL,
RecommendationOverall NVARCHAR(MAX) NULL,

SkipOverallRecommendationsIfThresholdIsZero BIT DEFAULT 0,

ThresholdCalcDesc NVARCHAR(MAX) NULL
)

CREATE TABLE #targetObj
(
TargetRowId INT NOT NULL,
ManagedEntityRowId INT NOT NULL
)

CREATE TABLE #objAspect
(
AspectObjectRowId INT IDENTITY PRIMARY KEY,

ManagedEntityRowId INT NOT NULL,
AspectRowId INT NOT NULL,
PerfChartNo INT NOT NULL,

PropertyValue FLOAT,
ThresholdValue FLOAT,

PointsCount BIGINT,

LastValueNo INT,
LastDateTime DATETIME,
a FLOAT,
b FLOAT,
ConfidenceInterval FLOAT,

TargetValueNo INT,
CurrentValueNo INT,

PredictedValueWorst FLOAT,
PredictedValue FLOAT,
PredictedValueBest FLOAT,

AvailableResourcesWorst FLOAT,
AvailableResources FLOAT,
AvailableResourcesBest FLOAT,

Recommendation NVARCHAR(MAX),

DaysTillThresholdMin NUMERIC(38,0),
DaysTillThreshold NUMERIC(38,0),
DaysTillThresholdMax NUMERIC(38,0),
IsAchieved BIT,
WillBeAchievedMin BIT,
WillBeAchieved BIT,
WillBedAchievedMax BIT
)

CREATE TABLE #objSummary
(
GroupId INT,
ElementId INT,
ManagedEntityRowId INT,
GroupName NVARCHAR(MAX),
ElementName NVARCHAR(MAX),
[Value] FLOAT,
IsObjectProblematic BIT DEFAULT 0
)

CREATE TABLE #objAspectPerformance
(
AspectObjectPerformanceRowId INT IDENTITY PRIMARY KEY,
AspectObjectRowId INT NOT NULL,
[DateTime] DATETIME,
[ValueNo] BIGINT,
[Value] FLOAT,
[TrendValueLower] FLOAT,
[TrendValue] FLOAT,
[TrendValueUpper] FLOAT,
[MeasurementUnitName] NVARCHAR(256),
[StandalonePointInd] TINYINT,
[OptionXml] XML
)

-- parse targets
INSERT INTO #target
(
TargetId,
ManagedEntityTypeSystemName,
ManagedEntityTypeRowId
)
SELECT
TargetId = cfg.trgt.value('@Id','nvarchar(64)'),
ManagedEntityTypeSystemName = cfg.trgt.value('@ManagedEntityTypeSystemName','nvarchar(512)'),
vmet.ManagedEntityTypeRowId
FROM
@Config.nodes('/PerfAnalysisConfig/Target') AS cfg(trgt)
INNER JOIN [dbo].[vManagedEntityType] vmet ON vmet.ManagedEntityTypeSystemName = cfg.trgt.value('@ManagedEntityTypeSystemName','nvarchar(512)')

-- parse aspects
INSERT INTO #aspect
(
TargetRowId,
TargetId,
AspectId,
AspectName,

Position,

IsPropertyBased,
Containment,
InstanceAggregationFunction,
RuleSystemName,
RuleRowId,
RuleGUID,
PropertyName,
PropertyMultiplier,
PropertyGuid,
IsFloorThreshold,

SuppressResourceOutput,

RecommendationTemplate,
RecommendationTemplateOverall,

SkipOverallRecommendationsIfThresholdIsZero,

PerformanceDataMultiplier,
MeasurementUnitName,

ThresholdCalcDesc
)
SELECT
t.TargetRowId,
TargetId = cfg.aspect.value('../@Id','nvarchar(64)'),
AspectId = cfg.aspect.value('@Id','nvarchar(64)'),
AspectName = cfg.aspect.value('@Name','nvarchar(max)'),
Position = cfg.aspect.value('@Position','int'),
IsPropertyBased = cfg.aspect.value('@IsPropertyBased','bit'),
Containment = cfg.aspect.value('@Containment','nvarchar(16)'),
InstanceAggregationFunction = cfg.aspect.value('@InstanceAggregationFunction','nvarchar(8)'),
RuleSystemName = cfg.aspect.value('@RuleSystemName','nvarchar(512)'),
RuleRowId = vr.RuleRowId,
RuleGUID = vr.RuleGuid,
PropertyName = cfg.aspect.value('@PropertyName','nvarchar(256)'),
PropertyMultiplier = cfg.aspect.value('@PropertyMultiplier','float'),
PropertyGuid = vmetp.PropertyGuid,
IsFloorThreshold = cfg.aspect.value('@IsFloorThreshold','bit'),
SuppressResourceOutput = cfg.aspect.value('@SuppressResourceOutput','bit'),
RecommendationTemplate = cfg.aspect.value('@RecommendationTemplate','nvarchar(max)'),
RecommendationTemplateOverall = cfg.aspect.value('@RecommendationTemplateOverall','nvarchar(max)'),
SkipOverallRecommendationsIfThresholdIsZero = isnull(cfg.aspect.value('@SkipOverallRecommendationsIfThresholdIsZero','bit'),0),
PerformanceDataMultiplier = isnull(cfg.aspect.value('@PerformanceDataMultiplier','float'),1),
MeasurementUnitName = cfg.aspect.value('@MeasurementUnitName','nvarchar(256)'),
ThresholdCalcDesc= cfg.aspect.value('@ThresholdCalcDesc','nvarchar(max)')
FROM
@Config.nodes('/PerfAnalysisConfig/Target/Aspect') AS cfg(aspect)
INNER JOIN [dbo].[vRule] vr ON vr.RuleSystemName=cfg.aspect.value('@RuleSystemName','nvarchar(512)')
INNER JOIN #target t ON t.TargetId=cfg.aspect.value('../@Id','nvarchar(64)')
LEFT OUTER JOIN [dbo].[vManagedEntityTypeProperty] vmetp ON vmetp.ManagedEntityTypeRowId = t.ManagedEntityTypeRowId AND vmetp.PropertySystemName=cfg.aspect.value('@PropertyName','nvarchar(256)')
ORDER BY t.TargetId, Position, AspectName

-- [bookmark]
-- transform thresholds
DECLARE @Thresholds XML
EXEC [dbo].[Veeam_VE_Widget_ThresholdsTransformedGet]
@ReportSystemName = @ReportSystemName,
@Thresholds = @RawThresholds,
@SelectedAspects = @SelectedAspects,
@IsXmlMode = 1,
@OutputXml = @Thresholds OUT

-- parse thresholds
UPDATE a
SET a.Threshold = thrs.thr.value('@Value','float')
FROM
@Thresholds.nodes('/Thresholds/Threshold') AS thrs(thr)
INNER JOIN #aspect a ON a.TargetId=thrs.thr.value('@TargetId','nvarchar(64)')
AND a.AspectId=thrs.thr.value('@AspectId','nvarchar(64)')
-- remove:
-- * aspects that do not have thresholds
-- * property-based aspects that do not have property assignment
IF (@ThresholdOverrides IS NULL)
BEGIN
DELETE a
FROM #aspect a
WHERE a.Threshold IS NULL OR (a.IsPropertyBased=1 AND a.PropertyGuid IS NULL)
END

-- get objects within the scope for each analysis target
DECLARE @TargetRowId INT, @ManagedEntityTypeRowId INT, @Objects XML
DECLARE trgtCur CURSOR FOR SELECT t.TargetRowId, t.ManagedEntityTypeRowId FROM #target t

OPEN trgtCur
FETCH trgtCur INTO @TargetRowId, @ManagedEntityTypeRowId

WHILE @@FETCH_STATUS=0
BEGIN
EXEC [dbo].[Veeam_GRL_ObjectListGet]
@StartDate = @StartDate,
@EndDate = @EndDate,
@ObjectList = @ObjectList,
@ManagedEntityTypeRowId = @ManagedEntityTypeRowId,
@XmlOutputOnly = 1,
@OutputXml = @Objects OUT

IF @Objects IS NOT NULL
BEGIN
INSERT INTO #targetObj
(
TargetRowId,
ManagedEntityRowId
)
SELECT
@TargetRowId,
O.o.value('.','int')
FROM
@Objects.nodes('/Objects/Object/ManagedEntityRowId') AS O(o)

END

SET @Objects=NULL

FETCH trgtCur INTO @TargetRowId, @ManagedEntityTypeRowId
END

CLOSE trgtCur
DEALLOCATE trgtCur

-- remove objects that do not have active configuration
DELETE FROM #targetObj
WHERE ManagedEntityRowId NOT IN
(
SELECT DISTINCT
o.ManagedEntityRowId
FROM
#targetObj o
INNER JOIN [dbo].[vManagedEntityProperty] vmep ON vmep.ManagedEntityRowId = o.ManagedEntityRowId
WHERE vmep.ToDateTime IS NULL
)

-- get aspect-object pairs with chart numbers - will be used to generate ObjectList for PerfGet SP
INSERT INTO #objAspect
(
ManagedEntityRowId,
AspectRowId,
PerfChartNo
)
SELECT
o.ManagedEntityRowId,
a.AspectRowId,
PerfChartNo = ROW_NUMBER() OVER (ORDER BY a.TargetRowId, a.AspectRowId)
FROM
#targetObj o
INNER JOIN #aspect a ON a.TargetRowId = o.TargetRowId

-- get actual property values
UPDATE oa
SET
PropertyValue = CAST(vmeps.PropertyValue AS FLOAT)*ISNULL(a.PropertyMultiplier,1)
FROM
#objAspect oa
INNER JOIN #aspect a ON a.AspectRowId = oa.AspectRowId
INNER JOIN [dbo].[vManagedEntityPropertySet] vmeps ON vmeps.ManagedEntityRowId = oa.ManagedEntityRowId AND vmeps.PropertyGuid = a.PropertyGuid
WHERE
a.PropertyGuid IS NOT NULL
AND vmeps.ToDateTime IS NULL
AND ISNUMERIC(vmeps.PropertyValue)=1

-- [bookmark]
-- set thresholds for each object-aspect pair
UPDATE oa
SET
ThresholdValue = CASE a.IsPropertyBased WHEN 1 THEN oa.PropertyValue*a.Threshold ELSE a.Threshold END
FROM
#objAspect oa
INNER JOIN #aspect a ON a.AspectRowId = oa.AspectRowId

-- apply threshold overrides
IF @ThresholdOverrides IS NOT NULL
BEGIN
UPDATE oa
SET
ThresholdValue = t.ov.value('@Value','float')
FROM
#objAspect oa
INNER JOIN #aspect a ON a.AspectRowId = oa.AspectRowId
INNER JOIN @ThresholdOverrides.nodes('/ThresholdOverrides/ThresholdOverride') t(ov) ON
a.TargetId = t.ov.value('@TargetId','nvarchar(64)')
AND a.AspectId = t.ov.value('@AspectId','nvarchar(64)')
AND oa.ManagedEntityRowId = t.ov.value('@ManagedEntityRowId','int')
END

-- get performance data & trends
DECLARE @PerfRequestConfig XML,
@PerfResponse XML

SET @PerfRequestConfig =
(
SELECT
[Value/Object/@Use] = a.Containment,
[Value/Object] = ao.ManagedEntityRowId,
[Value/Rule] = a.RuleGUID
FROM
#aspect a
INNER JOIN #objAspect ao ON ao.AspectRowId = a.AspectRowId
ORDER BY ao.PerfChartNo
FOR XML PATH('Values'), ROOT('Data')
)

EXEC [dbo].[Veeam_GRL_PerformanceGet]
@dtStart = @StartDate,
@dtEnd = @EndDate,
@config = @PerfRequestConfig,
@DataAgg = 1,
@DataMode = 'G',
@SectionMode = 'N',
@Histogram = 0,
@enableTrendCalc = 1,
@XmlOutputOnly = 1,
@OutputXml = @PerfResponse OUT

-- get trend data for object aspect
UPDATE ao
SET
LastValueNo = perf.trend.value('@LastValueNo','int'),
LastDateTime = perf.trend.value('@LastDateTime','datetime'),
a = CASE a.InstanceAggregationFunction
WHEN 'Avg' THEN perf.trend.value('@a_avg','float')
WHEN 'SumAvg' THEN perf.trend.value('@a_sumavg','float')
WHEN 'Min' THEN perf.trend.value('@a_min','float')
WHEN 'Max' THEN perf.trend.value('@a_max','float')
WHEN 'Sum' THEN perf.trend.value('@a_sum','float')
ELSE NULL
END * a.PerformanceDataMultiplier,
b = CASE a.InstanceAggregationFunction
WHEN 'Avg' THEN perf.trend.value('@b_avg','float')
WHEN 'SumAvg' THEN perf.trend.value('@b_sumavg','float')
WHEN 'Min' THEN perf.trend.value('@b_min','float')
WHEN 'Max' THEN perf.trend.value('@b_max','float')
WHEN 'Sum' THEN perf.trend.value('@b_sum','float')
ELSE NULL
END * a.PerformanceDataMultiplier,
-- We assume that normal distribution works and the number of measurements is >5,
-- so for Pr=90% t~=1.96
ConfidenceInterval = CASE a.InstanceAggregationFunction
WHEN 'Avg' THEN perf.trend.value('@stdev_avg','float')
WHEN 'SumAvg' THEN perf.trend.value('@stdev_sumavg','float')
WHEN 'Min' THEN perf.trend.value('@stdev_min','float')
WHEN 'Max' THEN perf.trend.value('@stdev_max','float')
WHEN 'Sum' THEN perf.trend.value('@stdev_sum','float')
ELSE NULL
END * 1.96 * a.PerformanceDataMultiplier
FROM
#aspect a
INNER JOIN #objAspect ao ON ao.AspectRowId = a.AspectRowId
INNER JOIN @PerfResponse.nodes('/Performance/Trend/TrendCoef') AS perf(trend)
ON ao.PerfChartNo=perf.trend.value('@ChartNo','int')
AND perf.trend.value('@RowType','char(1)')='G'
WHERE
ao.ThresholdValue IS NOT NULL -- we do not need performance data if we don't have a valid threshold

---- get performance data for object aspect
IF OBJECT_ID('tempdb..#perfpoint') IS NOT NULL DROP TABLE #perfpoint
CREATE TABLE #perfpoint
(
ChartNo INT,
RowType CHAR(1),
[DateTime] DATETIME,
ValueNo BIGINT,
SampleCount FLOAT,
AverageValue FLOAT,
SumAvgValue FLOAT,
MinValue FLOAT,
MaxValue FLOAT,
SumValue FLOAT,
TrendValue_Avg FLOAT,
TrendValue_SumAvg FLOAT,
TrendValue_Min FLOAT,
TrendValue_Max FLOAT,
TrendValue_Sum FLOAT,
MeasurementUnitName NVARCHAR(256),
StandalonePointInd TINYINT,
OptionXml NVARCHAR(MAX)
)

-- parse perf points from xml
INSERT INTO #perfpoint
(
ChartNo,
RowType,
[DateTime],
ValueNo,
SampleCount,
AverageValue,
SumAvgValue,
MinValue,
MaxValue,
SumValue,
TrendValue_Avg,
TrendValue_SumAvg,
TrendValue_Min,
TrendValue_Max,
TrendValue_Sum,
--MeasurementUnitName,
StandalonePointInd,
OptionXml
)
SELECT
perf.pp.value('@ChartNo','int'),
perf.pp.value('@RowType','char(1)'),
perf.pp.value('@DateTime','datetime'),
perf.pp.value('@ValueNo','bigint'),
perf.pp.value('@SampleCount','float'),
perf.pp.value('@AverageValue','float'),
perf.pp.value('@SumAvgValue','float'),
perf.pp.value('@MinValue','float'),
perf.pp.value('@MaxValue','float'),
perf.pp.value('@SumValue','float'),
perf.pp.value('@TrendValue_Avg','float'),
perf.pp.value('@TrendValue_SumAvg','float'),
perf.pp.value('@TrendValue_Min','float'),
perf.pp.value('@TrendValue_Max','float'),
perf.pp.value('@TrendValue_Sum','float'),
--perf.pp.value('@MeasurementUnitName','nvarchar(256)'),
perf.pp.value('@StandalonePointInd','tinyint'),
perf.pp.value('@OptionXml','nvarchar(max)')
FROM @PerfResponse.nodes('/Performance/PerfPoints/PerfPoint') AS perf(pp)

-- select only necessary ones
INSERT INTO #objAspectPerformance
(
AspectObjectRowId,
[DateTime],
ValueNo,
[Value],
TrendValue,
MeasurementUnitName,
StandalonePointInd,
OptionXml
)
SELECT
ao.AspectObjectRowId,
pp.[DateTime],
pp.ValueNo,
a.PerformanceDataMultiplier * (
CASE WHEN pp.SampleCount=0 THEN NULL ELSE
CASE a.InstanceAggregationFunction
WHEN 'Avg' THEN pp.AverageValue
WHEN 'SumAvg' THEN pp.SumAvgValue
WHEN 'Min' THEN pp.MinValue
WHEN 'Max' THEN pp.MaxValue
WHEN 'Sum' THEN pp.SumValue
ELSE NULL
END
END
),
a.PerformanceDataMultiplier * (
CASE a.InstanceAggregationFunction
WHEN 'Avg' THEN pp.TrendValue_Avg
WHEN 'SumAvg' THEN pp.TrendValue_SumAvg
WHEN 'Min' THEN pp.TrendValue_Min
WHEN 'Max' THEN pp.TrendValue_Max
WHEN 'Sum' THEN pp.TrendValue_Sum
ELSE NULL

END
),
pp.MeasurementUnitName,
pp.StandalonePointInd,
CAST(pp.OptionXml AS XML)
FROM
#aspect a
INNER JOIN #objAspect ao ON ao.AspectRowId = a.AspectRowId
INNER JOIN #perfpoint pp
ON ao.PerfChartNo=pp.ChartNo
AND pp.RowType='G'
WHERE
ao.ThresholdValue IS NOT NULL -- we do not need performance data if we don't have a valid threshold

IF OBJECT_ID('tempdb..#perfpoint') IS NOT NULL DROP TABLE #perfpoint
---- / get performance data for object aspect

-- calculate number of performance points per object aspect
UPDATE oa
SET
PointsCount=ISNULL(x.cnt,0)
FROM
#objAspect oa
LEFT OUTER JOIN
(
SELECT oap.AspectObjectRowId, cnt = COUNT(1) FROM #objAspectPerformance oap WHERE oap.[Value] IS NOT NULL GROUP BY oap.AspectObjectRowId
) x ON oa.AspectObjectRowId=x.AspectObjectRowId

-- calculate trend confidence interval boundaries.
UPDATE aop
SET
TrendValueLower = aop.TrendValue-ao.ConfidenceInterval,
TrendValueUpper = aop.TrendValue+ao.ConfidenceInterval
FROM
#objAspectPerformance aop
INNER JOIN #objAspect ao ON ao.AspectObjectRowId = aop.AspectObjectRowId
WHERE ao.PointsCount>0

-- calculate current and target points
UPDATE oa
SET
oa.CurrentValueNo = oa.LastValueNo+DATEDIFF(DAY,oa.LastDateTime,GETUTCDATE())-1,
oa.TargetValueNo = oa.LastValueNo+DATEDIFF(DAY,oa.LastDateTime,@EndDate)-1
FROM
#objAspect oa

-- predict when threshold will be hit
;WITH xdays (AspectObjectRowId, XDayMin, XDay, XDayMax, IsPastOkay, DaysToReportEnd, PredictedValueWorst, PredictedValue, PredictedValueBest)
AS
(
SELECT
oa.AspectObjectRowId,
XDayMin = CAST((CASE WHEN ISNULL(oa.b,0)=0 THEN NULL ELSE (oa.ThresholdValue-oa.a-oa.ConfidenceInterval*SIGN(oa.b))/oa.b END)-oa.CurrentValueNo AS NUMERIC(38,4)),
XDay = CAST((CASE WHEN ISNULL(oa.b,0)=0 THEN NULL ELSE (oa.ThresholdValue-oa.a)/oa.b END)-oa.CurrentValueNo AS NUMERIC(38,4)),
XDayMax = CAST((CASE WHEN ISNULL(oa.b,0)=0 THEN NULL ELSE (oa.ThresholdValue-oa.a+oa.ConfidenceInterval*SIGN(oa.b))/oa.b END)-oa.CurrentValueNo AS NUMERIC(38,4)),
-- also used to check for "reverse hit"
IsPastOkay = CASE WHEN (oa.b<0 AND a.IsFloorThreshold=0) OR (oa.b>0 AND a.IsFloorThreshold=1) THEN 1 ELSE 0 END,
DaysToReportEnd = DATEDIFF(DAY,GETUTCDATE(),@EndDate),
PredictedValueWorst = oa.a + oa.b*CAST(oa.TargetValueNo AS FLOAT)+oa.ConfidenceInterval*SIGN(oa.b),
PredictedValue = oa.a + oa.b*CAST(oa.TargetValueNo AS FLOAT),
PredictedValueBest = oa.a + oa.b*CAST(oa.TargetValueNo AS FLOAT)-oa.ConfidenceInterval*SIGN(oa.b)
FROM
#objAspect oa
INNER JOIN #aspect a ON a.AspectRowId = oa.AspectRowId
)
UPDATE oa
SET
oa.DaysTillThresholdMin = CASE WHEN x.XDayMin>=0 AND x.IsPastOkay=0 THEN x.XDayMin
WHEN x.XDayMin<0 AND x.IsPastOkay=0 THEN 0
ELSE NULL END ,
oa.DaysTillThreshold = CASE WHEN x.XDay>=0 AND x.IsPastOkay=0 THEN x.XDay
WHEN x.XDay<0 AND x.IsPastOkay=0 THEN 0
ELSE NULL END ,
oa.DaysTillThresholdMax = CASE WHEN x.XDayMax>=0 AND x.IsPastOkay=0 THEN x.XDayMax
WHEN x.XDayMax<0 AND x.IsPastOkay=0 THEN 0
ELSE NULL END ,
oa.IsAchieved = CASE WHEN (x.XDay<0 AND x.IsPastOkay=0) OR (x.XDay>=0 AND x.IsPastOkay=1) THEN 1
WHEN isnull(oa.b,0)=0 AND ((oa.a<=oa.ThresholdValue AND a.IsFloorThreshold=1) OR (oa.a>=oa.ThresholdValue AND a.IsFloorThreshold=0)) THEN 1
WHEN x.IsPastOkay=1 AND x.XDayMax>x.DaysToReportEnd THEN 1 -- performance will not be back to normal in the worst cases
ELSE 0 END,
oa.WillBeAchievedMin = CASE WHEN x.XDayMin < x.DaysToReportEnd AND x.IsPastOkay=0 THEN 1 ELSE 0 END,
oa.WillBeAchieved = CASE WHEN x.XDay BETWEEN 1 AND x.DaysToReportEnd AND x.IsPastOkay=0 THEN 1 ELSE 0 END,
oa.WillBedAchievedMax = CASE WHEN x.XDayMax BETWEEN 1 AND x.DaysToReportEnd AND x.IsPastOkay=0 THEN 1 ELSE 0 END,
oa.PredictedValueWorst = x.PredictedValueWorst,
oa.PredictedValue = x.PredictedValue,
oa.PredictedValueBest = x.PredictedValueBest,
oa.AvailableResourcesWorst = (CASE WHEN a.IsFloorThreshold=1 THEN -1 ELSE 1 END)*oa.ThresholdValue + (CASE WHEN a.IsFloorThreshold=1 THEN 1 ELSE -1 END)*x.PredictedValueWorst,
oa.AvailableResources = (CASE WHEN a.IsFloorThreshold=1 THEN -1 ELSE 1 END)*oa.ThresholdValue + (CASE WHEN a.IsFloorThreshold=1 THEN 1 ELSE -1 END)*x.PredictedValue,
oa.AvailableResourcesBest = (CASE WHEN a.IsFloorThreshold=1 THEN -1 ELSE 1 END)*oa.ThresholdValue + (CASE WHEN a.IsFloorThreshold=1 THEN 1 ELSE -1 END)*x.PredictedValueBest
FROM
#objAspect oa
INNER JOIN #aspect a ON a.AspectRowId = oa.AspectRowId
INNER JOIN xdays x ON oa.AspectObjectRowId=x.AspectObjectRowId

-- fix some corner cases for available resources
UPDATE oa
SET
AvailableResourcesWorst = CASE WHEN oa.PropertyValue-oa.AvailableResourcesWorst<0 AND oa.AvailableResourcesWorst>0 THEN oa.PropertyValue ELSE oa.AvailableResourcesWorst END,
AvailableResources = CASE WHEN oa.PropertyValue-oa.AvailableResources<0 AND oa.AvailableResources>0 THEN oa.PropertyValue ELSE oa.AvailableResources END,
AvailableResourcesBest = CASE WHEN oa.PropertyValue-oa.AvailableResourcesBest<0 AND oa.AvailableResourcesBest>0 THEN oa.PropertyValue ELSE oa.AvailableResourcesBest END
FROM
#objAspect oa
INNER JOIN #aspect a ON a.AspectRowId = oa.AspectRowId
WHERE
oa.PropertyValue IS NOT NULL

UPDATE oa
SET
AvailableResourcesWorst = CASE WHEN oa.ThresholdValue-oa.AvailableResourcesWorst<0 AND oa.AvailableResourcesWorst>0 THEN oa.ThresholdValue ELSE oa.AvailableResourcesWorst END,
AvailableResources = CASE WHEN oa.ThresholdValue-oa.AvailableResources<0 AND oa.AvailableResources>0 THEN oa.ThresholdValue ELSE oa.AvailableResources END,
AvailableResourcesBest = CASE WHEN oa.ThresholdValue-oa.AvailableResourcesBest<0 AND oa.AvailableResourcesBest>0 THEN oa.ThresholdValue ELSE oa.AvailableResourcesBest END
FROM
#objAspect oa
INNER JOIN #aspect a ON a.AspectRowId = oa.AspectRowId
WHERE
a.IsFloorThreshold=0 AND oa.PropertyValue IS NULL

UPDATE #objAspect
SET
AvailableResourcesWorst = AvailableResourcesBest,
AvailableResourcesBest = AvailableResourcesWorst,
PredictedValueWorst = PredictedValueBest,
PredictedValueBest = PredictedValueWorst
WHERE AvailableResourcesWorst>AvailableResourcesBest

-- Generate recommendations
UPDATE oa
SET
Recommendation = REPLACE(a.RecommendationTemplate,'%1',CONVERT(NVARCHAR(MAX),ROUND(ABS(oa.AvailableResourcesWorst),2)))
FROM
#objAspect oa
INNER JOIN #aspect a ON a.AspectRowId = oa.AspectRowId
WHERE
oa.AvailableResourcesWorst<0

;WITH rec (AspectRowId, RecommendationOverallValue)
AS
(
SELECT
a.AspectRowId,
RecommendationOverallValue = SUM(ROUND(ABS(ao.AvailableResourcesWorst),2))
FROM
#aspect a
INNER JOIN #objAspect ao ON ao.AspectRowId = a.AspectRowId
WHERE ao.AvailableResourcesWorst<0 AND (ao.ThresholdValue>0 OR a.SkipOverallRecommendationsIfThresholdIsZero=0)
GROUP BY a.AspectRowId
)
UPDATE a
SET
a.RecommendationOverall = REPLACE(a.RecommendationTemplateOverall,'%1',CONVERT(NVARCHAR(MAX),r.RecommendationOverallValue))
FROM
#aspect a
INNER JOIN rec r ON r.AspectRowId = a.AspectRowId

-- get per-object infrastructure summary
DECLARE @summary XML

EXEC [dbo].[Veeam_GRL_CurrentSummaryGetByScope] @ReportSystemName=@ReportSystemName, @ObjectList=@ObjectList, @XmlOutputOnly=1, @OutputXml=@summary OUT

INSERT INTO #objSummary
(
GroupId,
ElementId,
ManagedEntityRowId,
GroupName,
ElementName,
[Value]
)
SELECT
s.n.value('@GroupId','int'),
s.n.value('@ElementId','int'),
s.n.value('@ManagedEntityRowId','int'),
s.n.value('@GroupName','nvarchar(max)'),
s.n.value('@ElementName','nvarchar(max)'),
s.n.value('@Value','float')
FROM @summary.nodes('/Summary/Element') AS s(n)

;WITH po (ManagedEntityRowId)
AS
(
SELECT oa.ManagedEntityRowId
FROM #objAspect oa
WHERE
oa.IsAchieved=1
OR oa.WillBeAchievedMin=1
OR oa.WillBeAchieved=1
OR oa.WillBedAchievedMax=1
)
UPDATE os
SET IsObjectProblematic = 1
FROM
#objSummary os
INNER JOIN po ON po.ManagedEntityRowId = os.ManagedEntityRowId

---- final recordset
IF OBJECT_ID('tempdb..#ForecastRes') IS NOT NULL DROP TABLE #ForecastRes

CREATE TABLE #ForecastRes
(
[RowType] [varchar](1) NOT NULL,
[TargetRowId] [int] NOT NULL,
[AspectRowId] [int] NULL,
[AspectId] NVARCHAR(64) NULL,
[ManagedEntityRowId] [int] NULL,
[Path] [nvarchar](max) NULL,
[ManagedEntityDisplayName] [nvarchar](max) NULL,
[ManagedEntityTypeDefaultName] [nvarchar](256) NULL,
[Image] [varbinary](max) NULL,
[AspectObjectRowId] [int] NULL,
[AspectName] [nvarchar](max) NULL,
[IsPropertyBased] [bit] NULL,
[PropertyValue] [float] NULL,
[ThresholdValue] [float] NULL,
[PredictedValueWorst] [float] NULL,
[PredictedValue] [float] NULL,
[PredictedValueBest] [float] NULL,
[AvailableResourcesWorst] [float] NULL,
[AvailableResources] [float] NULL,
[AvailableResourcesBest] [float] NULL,
[DaysTillThresholdMin] [numeric](38, 0) NULL,
[DaysTillThreshold] [numeric](38, 0) NULL,
[DaysTillThresholdMax] [numeric](38, 0) NULL,
[IsAchieved] [bit] NULL,
[WillBeAchievedMin] [bit] NULL,
[WillBeAchieved] [bit] NULL,
[WillBeAchievedMax] [bit] NULL,
[PointsCount] [bigint] NULL,
[DateTime] [datetime] NULL,
[Value] [float] NULL,
[TrendValueLower] [float] NULL,
[TrendValue] [float] NULL,
[TrendValueUpper] [float] NULL,
[MeasurementUnitName] [nvarchar](256) NULL,
[StandalonePointInd] [tinyint] NULL,
[OptionXml] [xml] NULL,
[Recommendation] [nvarchar](max) NULL,
[IsConstraining] [bit] NULL,
[ThresholdCalcDesc] [nvarchar](max) NULL,
OriginalThreshold FLOAT NULL
)

-- totals
;WITH ca (AspectObjectRowId)
AS
(
SELECT
r.AspectObjectRowId
FROM
(
SELECT
oa.AspectObjectRowId,
RowNo = ROW_NUMBER() OVER ( PARTITION BY a.TargetId, oa.ManagedEntityRowId ORDER BY oa.DaysTillThreshold )
FROM
#objAspect oa
INNER JOIN #aspect a ON a.AspectRowId = oa.AspectRowId
WHERE oa.DaysTillThreshold IS NOT NULL OR oa.IsAchieved=1
) r
WHERE
r.RowNo=1

)
INSERT INTO #ForecastRes
(
RowType,
TargetRowId,
AspectRowId,
[AspectId],
ManagedEntityRowId,
[Path],
ManagedEntityDisplayName,
ManagedEntityTypeDefaultName,
[Image],
AspectObjectRowId,
AspectName,
IsPropertyBased,
PropertyValue,
ThresholdValue,
PredictedValueWorst,
PredictedValue,
PredictedValueBest,
AvailableResourcesWorst,
AvailableResources,
AvailableResourcesBest,
DaysTillThresholdMin,
DaysTillThreshold,
DaysTillThresholdMax,
IsAchieved,
WillBeAchievedMin,
WillBeAchieved,
WillBeAchievedMax,
PointsCount,
[DateTime],
[Value],
TrendValueLower,
TrendValue,
TrendValueUpper,
MeasurementUnitName,
StandalonePointInd,
OptionXml,
Recommendation,
IsConstraining,
ThresholdCalcDesc,
OriginalThreshold
)
SELECT
RowType = 'A',
TargetRowId = a.TargetRowId,
AspectRowId = a.AspectRowId,
a.AspectId,
ManagedEntityRowId = ao.ManagedEntityRowId,
[Path] = vme.[Path],
ManagedEntityDisplayName = vme.DisplayName,
ManagedEntityTypeDefaultName = vmet.ManagedEntityTypeDefaultName,
[Image] = vmeti.[Image],
AspectObjectRowId = ao.AspectObjectRowId,
AspectName = a.AspectName,
IsPropertyBased = a.IsPropertyBased,
PropertyValue = ao.PropertyValue,
ThresholdValue = ao.ThresholdValue,

PredictedValueWorst = ao.PredictedValueWorst,
PredictedValue = ao.PredictedValue,
PredictedValueBest = ao.PredictedValueBest,
AvailableResourcesWorst = CASE WHEN a.SuppressResourceOutput=1 THEN NULL ELSE ao.AvailableResourcesWorst END,
AvailableResources = CASE WHEN a.SuppressResourceOutput=1 THEN NULL ELSE ao.AvailableResources END,
AvailableResourcesBest = CASE WHEN a.SuppressResourceOutput=1 THEN NULL ELSE ao.AvailableResourcesBest END,

DaysTillThresholdMin = ao.DaysTillThresholdMin,
DaysTillThreshold = ao.DaysTillThreshold,
DaysTillThresholdMax = ao.DaysTillThresholdMax,
IsAchieved = ao.IsAchieved,
WillBeAchievedMin = ao.WillBeAchievedMin,
WillBeAchieved = ao.WillBeAchieved,
WillBeAchievedMax = ao.WillBedAchievedMax,
PointsCount = ao.PointsCount,
[DateTime] = NULL,
Value = NULL,
TrendValueLower = NULL,
TrendValue = NULL,
TrendValueUpper = NULL,
MeasurementUnitName = a.MeasurementUnitName,
StandalonePointInd = NULL,
OptionXml = NULL,
Recommendation = ao.Recommendation,
IsConstraining = CAST((CASE WHEN ca.AspectObjectRowId IS NOT NULL THEN 1 ELSE 0 END) AS BIT),
ThresholdCalcDesc = a.ThresholdCalcDesc,
OriginalThreshold = a.Threshold
FROM
#objAspect ao
INNER JOIN #aspect a ON a.AspectRowId = ao.AspectRowId
INNER JOIN [dbo].[vManagedEntity] vme ON vme.ManagedEntityRowId = ao.ManagedEntityRowId
INNER JOIN [dbo].[vManagedEntityType] vmet ON vmet.ManagedEntityTypeRowId = vme.ManagedEntityTypeRowId
LEFT OUTER JOIN [dbo].[vManagedEntityTypeImage] vmeti ON vmeti.ManagedEntityTypeRowId = vmet.ManagedEntityTypeRowId AND vmeti.ImageCategory = N'u16x16Icon'
LEFT OUTER JOIN ca ca ON ca.AspectObjectRowId = ao.AspectObjectRowId
UNION ALL
-- Overall Recommendations
SELECT
RowType = 'R',
TargetRowId = a.TargetRowId,
AspectRowId = a.AspectRowId,
a.AspectId,
ManagedEntityRowId = NULL,
[Path] = NULL,
ManagedEntityDisplayName = NULL,
ManagedEntityTypeDefaultName = vmet.ManagedEntityTypeDefaultName,
[Image] = NULL,
AspectObjectRowId = NULL,
AspectName = a.AspectName,
IsPropertyBased = a.IsPropertyBased,
PropertyValue = NULL,
ThresholdValue = NULL,

PredictedValueWorst = NULL,
PredictedValue = NULL,
PredictedValueBest = NULL,
AvailableResourcesWorst = NULL,
AvailableResources = NULL,
AvailableResourcesBest = NULL,

DaysTillThresholdMin = NULL,
DaysTillThreshold = NULL,
DaysTillThresholdMax = NULL,
IsAchieved = NULL,
WillBeAchievedMin = NULL,
WillBeAchieved = NULL,
WillBeAchievedMax = NULL,
PointsCount = NULL,
[DateTime] = NULL,
Value = NULL,
TrendValueLower = NULL,
TrendValue = NULL,
TrendValueUpper = NULL,
MeasurementUnitName = NULL,
StandalonePointInd = NULL,
OptionXml = NULL,
Recommendation = a.RecommendationOverall,
IsConstraining = NULL,
ThresholdCalcDesc = NULL,
OriginalThreshold = NULL
FROM
#aspect a
INNER JOIN #target t ON t.TargetRowId = a.TargetRowId
INNER JOIN [dbo].[vManagedEntityType] vmet ON vmet.ManagedEntityTypeRowId = t.ManagedEntityTypeRowId
WHERE
a.RecommendationOverall IS NOT NULL
UNION ALL
-- per-object summary
SELECT
RowType = 'S',
TargetRowId = ot.TargetRowId,
AspectRowId = os.ElementId,
AspectId = NULL,
ManagedEntityRowId = os.ManagedEntityRowId,
[Path] = vme.[Path],
ManagedEntityDisplayName = vme.DisplayName,
ManagedEntityTypeDefaultName = vmet.ManagedEntityTypeDefaultName,
[Image] = NULL,
AspectObjectRowId = NULL,
AspectName = os.ElementName,
IsPropertyBased = NULL,
PropertyValue = os.[Value],
ThresholdValue = NULL,

PredictedValueWorst = NULL,
PredictedValue = NULL,
PredictedValueBest = NULL,
AvailableResourcesWorst = NULL,
AvailableResources = NULL,
AvailableResourcesBest = NULL,

DaysTillThresholdMin = NULL,
DaysTillThreshold = NULL,
DaysTillThresholdMax = NULL,
IsAchieved = os.IsObjectProblematic,
WillBeAchievedMin = NULL,
WillBeAchieved = NULL,
WillBeAchievedMax = NULL,
PointsCount = NULL,
[DateTime] = NULL,
Value = NULL,
TrendValueLower = NULL,
TrendValue = NULL,
TrendValueUpper = NULL,
MeasurementUnitName = NULL,
StandalonePointInd = NULL,
OptionXml = NULL,
Recommendation = NULL,
IsConstraining = NULL,
ThresholdCalcDesc = NULL,
OriginalThreshold = NULL
FROM
#objSummary os
INNER JOIN #targetObj ot ON ot.ManagedEntityRowId = os.ManagedEntityRowId
INNER JOIN [dbo].[vManagedEntity] vme ON vme.ManagedEntityRowId = os.ManagedEntityRowId
INNER JOIN [dbo].[vManagedEntityType] vmet ON vmet.ManagedEntityTypeRowId = vme.ManagedEntityTypeRowId
WHERE
os.ManagedEntityRowId IS NOT NULL AND os.[Value] IS NOT NULL
UNION ALL
-- performance data
SELECT
RowType = 'P',
TargetRowId = a.TargetRowId,
AspectRowId = a.AspectRowId,
a.AspectId,
ManagedEntityRowId = ao.ManagedEntityRowId,
[Path] = vme.[Path],
ManagedEntityDisplayName = vme.DisplayName,
ManagedEntityTypeDefaultName = NULL,
[Image] = NULL,
AspectObjectRowId = ao.AspectObjectRowId,
AspectName = a.AspectName,
IsPropertyBased = a.IsPropertyBased,
PropertyValue = ao.PropertyValue,
ThresholdValue = ao.ThresholdValue,

PredictedValueWorst = ao.PredictedValueWorst,
PredictedValue = ao.PredictedValue,
PredictedValueBest = ao.PredictedValueBest,
AvailableResourcesWorst = ao.AvailableResourcesWorst,
AvailableResources = ao.AvailableResources,
AvailableResourcesBest = ao.AvailableResourcesBest,

DaysTillThresholdMin = ao.DaysTillThresholdMin,
DaysTillThreshold = ao.DaysTillThreshold,
DaysTillThresholdMax = ao.DaysTillThresholdMax,
IsAchieved = ao.IsAchieved,
WillBeAchievedMin = ao.WillBeAchievedMin,
WillBeAchieved = ao.WillBeAchieved,
WillBeAchievedMax = ao.WillBedAchievedMax,
PointsCount = ao.PointsCount,
[DateTime] = aop.[DateTime],
Value = aop.[Value],
TrendValueLower = aop.TrendValueLower,
TrendValue = aop.TrendValue,
TrendValueUpper = aop.TrendValueUpper,
MeasurementUnitName = a.MeasurementUnitName,
StandalonePointInd = aop.StandalonePointInd,
OptionXml = aop.OptionXml,
Recommendation = NULL,
IsConstraining = NULL,
ThresholdCalcDesc = NULL,
OriginalThreshold = NULL
FROM
#objAspect ao
INNER JOIN #aspect a ON a.AspectRowId = ao.AspectRowId
INNER JOIN #objAspectPerformance aop ON aop.AspectObjectRowId = ao.AspectObjectRowId
INNER JOIN [dbo].[vManagedEntity] vme ON vme.ManagedEntityRowId = ao.ManagedEntityRowId

IF @IsXmlMode=0
BEGIN
SELECT * FROM #ForecastRes
ORDER BY RowType, ManagedEntityRowId, [DateTime]
END
ELSE
BEGIN
SET @OutputXml = (
SELECT
fr.RowType, fr.TargetRowId, fr.AspectRowId, fr.AspectId,
fr.ManagedEntityRowId, fr.AspectObjectRowId,
fr.AspectName, fr.IsPropertyBased, fr.PropertyValue,
fr.ThresholdValue, fr.PredictedValueWorst,
fr.PredictedValue, fr.PredictedValueBest,
fr.AvailableResourcesWorst, fr.AvailableResources,
fr.AvailableResourcesBest, fr.DaysTillThresholdMin,
fr.DaysTillThreshold, fr.DaysTillThresholdMax,
fr.IsAchieved, fr.WillBeAchievedMin, fr.WillBeAchieved,
fr.WillBeAchievedMax, fr.PointsCount, fr.[DateTime],
fr.[Value], fr.TrendValueLower, fr.TrendValue,
fr.TrendValueUpper, fr.MeasurementUnitName,
fr.StandalonePointInd, fr.OptionXml, fr.Recommendation,
fr.IsConstraining, fr.ThresholdCalcDesc, fr.OriginalThreshold
FROM #ForecastRes fr
FOR XML RAW('ForecastRow'),ROOT('Forecast')
)
END

IF OBJECT_ID('tempdb..#target') IS NOT NULL DROP TABLE #target
IF OBJECT_ID('tempdb..#aspect') IS NOT NULL DROP TABLE #aspect
IF OBJECT_ID('tempdb..#targetObj') IS NOT NULL DROP TABLE #targetObj
IF OBJECT_ID('tempdb..#objAspect') IS NOT NULL DROP TABLE #objAspect
IF OBJECT_ID('tempdb..#objSummary') IS NOT NULL DROP TABLE #objSummary
IF OBJECT_ID('tempdb..#objAspectPerformance') IS NOT NULL DROP TABLE #objAspectPerformance

END

END TRY
BEGIN CATCH
IF OBJECT_ID('tempdb..#target') IS NOT NULL DROP TABLE #target
IF OBJECT_ID('tempdb..#aspect') IS NOT NULL DROP TABLE #aspect
IF OBJECT_ID('tempdb..#targetObj') IS NOT NULL DROP TABLE #targetObj
IF OBJECT_ID('tempdb..#objAspect') IS NOT NULL DROP TABLE #objAspect
IF OBJECT_ID('tempdb..#objSummary') IS NOT NULL DROP TABLE #objSummary
IF OBJECT_ID('tempdb..#objAspectPerformance') IS NOT NULL DROP TABLE #objAspectPerformance

DECLARE @errMsg VARCHAR(1024)
SET @errMsg = ERROR_MESSAGE()

RAISERROR(@errMsg, 16, 1)
END CATCH

END
GO

GRANT EXECUTE ON dbo.[Veeam_VE_Widget_PerformanceForecastGet] TO OpsMgrReader
GO


IF NOT EXISTS (SELECT * FROM sys.objects WHERE [schema_id]=SCHEMA_ID('sdk') AND type = 'P' AND name = 'Veeam_VE_Widget_PerformanceForecastGet')
BEGIN
EXECUTE ('CREATE PROCEDURE sdk.[Veeam_VE_Widget_PerformanceForecastGet] AS RETURN 1')
END
GO
ALTER PROCEDURE sdk.[Veeam_VE_Widget_PerformanceForecastGet]
@Objects XML,
@SelectedAspect XML,
@DateFrom DATETIME,
@Horisont DATETIME,
@mg UNIQUEIDENTIFIER
AS
BEGIN

BEGIN TRAN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRY

IF OBJECT_ID('tempdb..#lic') IS NOT NULL DROP TABLE #lic
IF OBJECT_ID('tempdb..#objV') IS NOT NULL DROP TABLE #objV
IF OBJECT_ID('tempdb..#rul') IS NOT NULL DROP TABLE #rul
IF OBJECT_ID('tempdb..#Forecast') IS NOT NULL DROP TABLE #Forecast

CREATE TABLE #lic
(
[Message] NVARCHAR(MAX),
[LinkLabel] NVARCHAR(MAX),
[LinkURL] NVARCHAR(MAX)
)
INSERT INTO #lic
(
[Message], LinkLabel, LinkURL
)
EXEC dbo.[Veeam_CheckServiceAvailability]
@mg,
'WD'
DECLARE @xmlout XML
IF EXISTS(SELECT * FROM #lic)
BEGIN

SELECT
'False' AS '@Succeed',
lic.[Message] +'<a href="'+ lic.[LinkURL]+'">'+lic.[LinkLabel] +'</a>'AS '@Message'
FROM #lic AS lic
FOR XML PATH('LicenseCheck'),ROOT('Forecast')
END
ELSE
BEGIN

CREATE TABLE #objV
(
[GUID] UNIQUEIDENTIFIER,
[Object] INT,
entityTypeId NVARCHAR(MAX)
)

CREATE TABLE #rul
(
Id INT IDENTITY(1,1) NOT NULL,
[GUID] UNIQUEIDENTIFIER,
RuleId INT,
RuleSystemName NVARCHAR(MAX),
RuleDefaultName NVARCHAR(MAX),
ObjectName NVARCHAR(MAX),
Threshold NVARCHAR(MAX),
IsFloorThreshold NVARCHAR(MAX),
entityTypeName NVARCHAR(MAX)
)

DECLARE @ObjectList XML,
@Aspects XML,
@Threshold XML

INSERT INTO #objV
(
[Guid],
[Object],
entityTypeId
)
SELECT
EntityId.id.value('.', 'UNIQUEIDENTIFIER'),
vme.ManagedEntityRowId,
vme.ManagedEntityTypeRowId
FROM @Objects.nodes('Objects/Object') AS EntityId(id)
INNER JOIN dbo.vManagedEntity AS vme ON vme.ManagedEntityGuid = EntityId.id.value('.', 'UNIQUEIDENTIFIER')

INSERT INTO #rul
(
[Guid],
RuleId,
RuleSystemName,
RuleDefaultName,
ObjectName,
Threshold,
IsFloorThreshold,
entityTypeName
)
SELECT
DISTINCT(aspect.id.value('@AspectId[1]', 'UNIQUEIDENTIFIER')),
vr.RuleRowId,
vr.RuleSystemName,
vr.RuleDefaultName,
aspect.id.value('@ObjectName[1]', 'NVARCHAR(MAX)'),
aspect.id.value('@Threshold[1]', 'NVARCHAR(MAX)'),
aspect.id.value('@IsFloorThreshold[1]', 'NVARCHAR(MAX)'),
vmet.ManagedEntityTypeSystemName
FROM @SelectedAspect.nodes('SelectedAspects/SelectedAspect') AS aspect(id)
INNER JOIN dbo.vRule AS vr ON vr.RuleGuid = aspect.id.value('@AspectId[1]', 'UNIQUEIDENTIFIER')
INNER JOIN dbo.vPerformanceRuleInstance AS vpri ON vpri.RuleRowId=vr.RuleRowId
INNER JOIN perf.vPerfDaily AS vph ON vph.PerformanceRuleInstanceRowId = vpri.PerformanceRuleInstanceRowId
INNER JOIN dbo.vManagedEntity AS vme ON vph.ManagedEntityRowId=vme.ManagedEntityRowId
INNER JOIN dbo.vManagedEntityType AS vmet ON vmet.ManagedEntityTypeRowId=vme.ManagedEntityTypeRowId
INNER JOIN #objV AS o ON o.entityTypeId=vmet.ManagedEntityTypeRowId
WHERE vph.[DateTime] BETWEEN @DateFrom AND @Horisont

SET @ObjectList =
(
SELECT
'Containment' AS 'Object/@Use',
[Object]
FROM #objV
FOR XML PATH('Objects') , ROOT('Data'),ELEMENTS
)

SET @Aspects =
(
SELECT
r.ObjectName AS '@TargetId',
r.RuleSystemName AS '@AspectId'
FROM #rul AS r
FOR XML PATH('SelectedAspect') , ROOT('SelectedAspects'),ELEMENTS
)

SET @Threshold =
(
SELECT
r.Id AS '@Id',
r.Threshold AS '@Value'
FROM #rul AS r
FOR XML PATH('Threshold') , ROOT('Thresholds'),ELEMENTS
)

DECLARE @Options XML
SET @Options =
(
SELECT (
SELECT
r.ObjectName AS '@Id',
r.entityTypeName AS '@ManagedEntityTypeSystemName',
(
SELECT
r1.RuleSystemName AS '@Id',
r1.RuleSystemName AS '@RuleSystemName',
'Containment' AS '@Containment',
'false' AS '@IsPropertyBased',
'NAME' AS '@Name',
'SumAvg' AS '@InstanceAggregationFunction',
r1.IsFloorThreshold AS '@IsFloorThreshold',
r1.RuleSystemName AS '@PropertyName',
'1' AS '@PropertyMultiplier',
'1' AS '@PerformanceDataMultiplier',
'%1' AS '@RecommendationTemplate',
'%1' AS '@RecommendationTemplateOverall'--,
FROM #rul AS r1
FOR XML PATH('Aspect') , TYPE
)

FROM #rul AS r
group by r.ObjectName, r.entityTypeName
FOR XML PATH('Target') , ROOT('PerfAnalysisConfig'), TYPE
),
(
SELECT
r.ObjectName AS 'ThresholdsTransform/@TargetId',
r.RuleSystemName AS 'ThresholdsTransform/@AspectId',
r.Id AS 'ThresholdsTransform/@ThresholdId',
'1' AS 'ThresholdsTransform/@Multiplier'
FROM #rul AS r

FOR XML PATH('') , ROOT('ThresholdsTransforms'), TYPE
)
FOR XML PATH('') , ROOT('Options'), ELEMENTS

)

DELETE FROM dbo.Veeam_GRL_Report WHERE ReportSystemName='Veeam.Virt.Extensions.HyperV.CapacityPlanning.Widget.Forecast'
INSERT INTO [dbo].[Veeam_GRL_Report]
(
ReportSystemName,
ReportDisplayName,
ReportDescription,
LinkedInd,
BaseReportId,
MPSystemName,
Options
)
VALUES
(
'Veeam.Virt.Extensions.HyperV.CapacityPlanning.Widget.Forecast',
'',
'',
0,
NULL,
'',
@Options
)

CREATE TABLE #Forecast
(
[RowType] [varchar](1) ,
[TargetRowId] [int] ,
[AspectRowId] [int] NULL,
[AspectId] NVARCHAR(max) NULL,
[AspectGuid] UNIQUEIDENTIFIER NULL,
[ManagedEntityName] [nvarchar](max),
[ManagedEntityRowId] [int] NULL,
[ManagedEntityRowGuid] UNIQUEIDENTIFIER NULL,
[Path] [nvarchar](max) NULL,
[ManagedEntityDisplayName] [nvarchar](max) NULL,
[ManagedEntityTypeDefaultName] [nvarchar](256) NULL,
[Image] [varbinary](max) NULL,
[AspectObjectRowId] [int] NULL,
[AspectName] [nvarchar](max) NULL,
[IsPropertyBased] [bit] NULL,
[PropertyValue] [float] NULL,
[ThresholdValue] [float] NULL,
[PredictedValueWorst] [float] NULL,
[PredictedValue] [float] NULL,
[PredictedValueBest] [float] NULL,
[AvailableResourcesWorst] [float] NULL,
[AvailableResources] [float] NULL,
[AvailableResourcesBest] [float] NULL,
[DaysTillThresholdMin] [numeric](38, 0) NULL,
[DaysTillThreshold] [numeric](38, 0) NULL,
[DaysTillThresholdMax] [numeric](38, 0) NULL,
[IsAchieved] [bit] NULL,
[WillBeAchievedMin] [bit] NULL,
[WillBeAchieved] [bit] NULL,
[WillBeAchievedMax] [bit] NULL,
[PointsCount] [bigint] NULL,
[DateTime] [datetime] NULL,
[Value] [float] NULL,
[TrendValueLower] [float] NULL,
[TrendValue] [float] NULL,
[TrendValueUpper] [float] NULL,
[MeasurementUnitName] [nvarchar](256) NULL,
[StandalonePointInd] [tinyint] NULL,
[OptionXml] [xml] NULL,
[Recommendation] [nvarchar](max) NULL,
[IsConstraining] [bit] NULL,
[ThresholdCalcDesc] [nvarchar](max) NULL,
OriginalThreshold FLOAT NULL
)

INSERT INTO #Forecast
(
RowType,
TargetRowId,
AspectRowId,
[AspectId],
ManagedEntityRowId,
[Path],
ManagedEntityDisplayName,
ManagedEntityTypeDefaultName,
[Image],
AspectObjectRowId,
AspectName,
IsPropertyBased,
PropertyValue,
ThresholdValue,
PredictedValueWorst,
PredictedValue,
PredictedValueBest,
AvailableResourcesWorst,
AvailableResources,
AvailableResourcesBest,
DaysTillThresholdMin,
DaysTillThreshold,
DaysTillThresholdMax,
IsAchieved,
WillBeAchievedMin,
WillBeAchieved,
WillBeAchievedMax,
PointsCount,
[DateTime],
[Value],
TrendValueLower,
TrendValue,
TrendValueUpper,
MeasurementUnitName,
StandalonePointInd,
OptionXml,
Recommendation,
IsConstraining,
ThresholdCalcDesc,
OriginalThreshold
)
exec dbo.Veeam_VE_Widget_PerformanceForecastGet
@StartDate=@DateFrom,
@EndDate=@Horisont,
@ReportSystemName=N'Veeam.Virt.Extensions.HyperV.CapacityPlanning.Widget.Forecast',
@ObjectList= @ObjectList,
@RawThresholds=@Threshold,
@SelectedAspects= @Aspects

UPDATE fres
SET ManagedEntityRowGuid=me.ManagedEntityGuid,
ManagedEntityName=me.ManagedEntityName
FROM
(
SELECT
ManagedEntityGuid = vme.ManagedEntityGuid,
ManagedEntityRowId = vme.ManagedEntityRowId,
ManagedEntityName = vme.DisplayName
FROM #Forecast AS fr
INNER JOIN dbo.vManagedEntity AS vme ON vme.ManagedEntityRowId=fr.ManagedEntityRowId
) AS me
INNER JOIN #Forecast AS fres ON fres.ManagedEntityRowId=me.ManagedEntityRowId

UPDATE fres
SET [AspectGuid]=me.[AspectGuid],
AspectId = me.AspectDefoultname
FROM
(
SELECT
[AspectGuid] = r.[GUID],
RuleSystemName = r.RuleSystemName,
AspectDefoultname = r.RuleDefaultName
FROM #Forecast AS fr
INNER JOIN #rul AS r ON r.RuleSystemName=fr.AspectId
) AS me
INNER JOIN #Forecast AS fres ON fres.AspectId=me.RuleSystemName
SET @xmlout =
(
SELECT
(
SELECT
'True' AS '@Succeed'
FOR XML PATH('LicenseCheck') , TYPE
),
(
SELECT
fr.RowType, fr.TargetRowId, fr.AspectRowId, fr.AspectId, fr.AspectGuid, fr.ManagedEntityName,
fr.ManagedEntityRowId, fr.ManagedEntityRowGuid, fr.AspectObjectRowId,
fr.AspectName, fr.IsPropertyBased, fr.PropertyValue,
fr.ThresholdValue, fr.PredictedValueWorst,
fr.PredictedValue, fr.PredictedValueBest,
fr.AvailableResourcesWorst, fr.AvailableResources,
fr.AvailableResourcesBest, fr.DaysTillThresholdMin,
fr.DaysTillThreshold, fr.DaysTillThresholdMax,
fr.IsAchieved, fr.WillBeAchievedMin, fr.WillBeAchieved,
fr.WillBeAchievedMax, fr.PointsCount, fr.[DateTime],
fr.[Value], fr.TrendValueLower, fr.TrendValue,
fr.TrendValueUpper, fr.MeasurementUnitName,
fr.StandalonePointInd, fr.OptionXml, fr.Recommendation,
fr.IsConstraining, fr.ThresholdCalcDesc, fr.OriginalThreshold
FROM #Forecast fr
WHERE fr.RowType='A'
FOR XML RAW('ForecastRow') , TYPE
)
FOR XML PATH('') , ROOT('Forecast'), ELEMENTS

)
DELETE FROM dbo.Veeam_GRL_Report WHERE ReportSystemName='Veeam.Virt.Extensions.HyperV.CapacityPlanning.Widget.Forecast'

SELECT @xmlout

END


IF OBJECT_ID('tempdb..#lic') IS NOT NULL DROP TABLE #lic
IF OBJECT_ID('tempdb..#obj') IS NOT NULL DROP TABLE #objV
IF OBJECT_ID('tempdb..#rul') IS NOT NULL DROP TABLE #rul
IF OBJECT_ID('tempdb..#Forecast') IS NOT NULL DROP TABLE #Forecast

END TRY
BEGIN CATCH
IF OBJECT_ID('tempdb..#lic') IS NOT NULL DROP TABLE #lic
IF OBJECT_ID('tempdb..#obj') IS NOT NULL DROP TABLE #objV
IF OBJECT_ID('tempdb..#rul') IS NOT NULL DROP TABLE #rul
IF OBJECT_ID('tempdb..#Forecast') IS NOT NULL DROP TABLE #Forecast
DECLARE @errMsg VARCHAR(1024)
SET @errMsg = ERROR_MESSAGE()

RAISERROR(@errMsg, 16, 1)
END CATCH

COMMIT TRAN

END
GO

GRANT EXECUTE ON sdk.Veeam_VE_Widget_PerformanceForecastGet TO OpsMgrReader
GO

GRANT DELETE ON dbo.Veeam_GRL_Report TO OpsMgrReader
GO

GRANT INSERT ON dbo.Veeam_GRL_Report TO OpsMgrReader
GO