TransformProvanceBFATitleLicensingPositionDailyFactProcResource (Resource)

Element properties:

TypeResource
File NameTransformProvanceBFATitleLicensingPositionDailyFactProc.sql
AccessibilityPublic

Source Code:

<Resource ID="TransformProvanceBFATitleLicensingPositionDailyFactProcResource" Accessibility="Public" FileName="TransformProvanceBFATitleLicensingPositionDailyFactProc.sql" HasNullStream="false"/>

File Content: TransformProvanceBFATitleLicensingPositionDailyFactProc.sql

IF NOT EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = N'TransformProvanceBFATitleLicensingPositionDailyFactProc')

BEGIN
EXECUTE ('CREATE PROCEDURE dbo.[TransformProvanceBFATitleLicensingPositionDailyFactProc] @WaterMark xml AS RETURN 1')
END
GO

ALTER PROCEDURE [dbo].[TransformProvanceBFATitleLicensingPositionDailyFactProc] (@WaterMark xml)
AS
BEGIN
SET NOCOUNT ON
SET XACT_ABORT ON

DECLARE @errorNumber INT,
@errorSeverity INT,
@errorState INT,
@errorLine INT,
@errorProcedure NVARCHAR(256),
@errorMessage NVARCHAR(MAX),
@startTranCount INT = @@TRANCOUNT,
@task NVARCHAR(512)

SELECT @task = 'Starting.'


/*

We are trying to keep a daily history of the BFATitleLicensingPosition postion in the following fact ProvanceBFATitleLicensingPositionDailyFact

<DegenerateDimensions>
<DegenerateDimension ID="SoftwareTitleGuid" Type="guid" CaseSensitive="false" Nullable="false" />
<DegenerateDimension ID="StartDay" Type="int" CaseSensitive="false" Nullable="false" />
<DegenerateDimension ID="EndDay" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="AssignmentCount" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="BatchId" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="EntitlementsAvailable" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="EntitlementsRemaining" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="InstallsCovered" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="InstallsExcluded" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="InstallsNormalized" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="InstallsNotCovered" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="LicensingPositionIndicatorId" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="LicensingPositionPercentage" Type="int" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="TimeStamp" Type="datetime" CaseSensitive="false" Nullable="true" />
<DegenerateDimension ID="TitleLicensingPositionId" Type="int" CaseSensitive="false" Nullable="true" />

In ServiceManager the logical key for BFATitleLicensingPosition is SoftwareTitleGuid, our prefered logical key in the DW would be SoftwareTitleGuid and StartDay
The "system" will add ProvanceBFATitleLicensingPositionDimKey and DateKey to the Fact and to the Primary Key, these should never be updated.

The BFA process can be run many times during a day, we want the last run of each day to be saved.
The BFA process may not run every day, or a title may not change every day, the DailyFact will have a StartDay and EndDay field, these represent the days this record was in effect.
The extract process may run many times before the transform process, this could give us many records for a given logical key, we keep the last record for each day, the EndDay of each will be the StartDay -1
of the next record.

The Timestamp field on the inbound.MTV_Provance$Class$BFATitleLicensingPosition must always move forward. If it is set to a date previous to its current value this procedure could fail
or produce inconsitant results.


insert into t_log (t_xml,t_date) values (@WaterMark,getdate())
begin transaction
insert into t_log (t_xml,t_date) values (null,getdate())
rollback

create table T_log (t_id int not null identity,t_xml xml,t_date datetime)

delete ProvanceBFATitleLicensingPositionDailyFactvw


select * from ProvanceBFATitleLicensingPositionDailyFactvw
select * from t_log order by t_id
select * from save_inbound

-- select * from save_inbound

-- select @WaterMark
commit
rollback
begin transaction
declare @WaterMark XML
select @WaterMark = t_xml
from t_log where t_id = 14
exec [TransformProvanceBFATitleLicensingPositionDailyFactProc] @WaterMark


delete ProvanceBFATitleLicensingPositionDailyFactvw

delete dwdatamart.dbo.ProvanceBFATitleLicensingPositionDailyFactvw


*/


DECLARE @BatchId int, @Inserted int, @Updated int, @CurrentUtcDate datetime, @WaterMarkDate datetime, @MinDateKey int

SET @Inserted = 0
SET @Updated = 0

BEGIN TRY

SELECT @task = 'Shreding WaterMark.'
SELECT * INTO #wm FROM etl.ShredWaterMark(@WaterMark)

SELECT @task = 'Getting Water Mark Date and BatchId.'
SELECT TOP 1 @WaterMarkDate = WaterMark, @BatchId = BatchId
FROM #wm
WHERE WarehouseEntityName = N'MTV_Provance$Class$BFA$TitleLicensingPosition'

SET @CurrentUtcDate = GETUTCDATE()

-- Get the inbound data
-- Join to ProvanceBFATitleLicensingPositionDimvw to get the ProvanceBFATitleLicensingPositionDimKey
SELECT @task = 'Moving inbound data to #Temp1'

select CAST(CONVERT(nvarchar(8), a.TimeStamp, 112) AS INT) AS StartDay,
CAST(NULL AS int) AS EndDay,
ROW_NUMBER() OVER (PARTITION BY a.SoftwareTitleGuid
ORDER BY a.TimeStamp ) AS KeySeqNum,
CAST(CONVERT(nvarchar(8), a.TimeAdded, 112) AS INT) AS DateKey,
A.*
into #Temp1
from ( SELECT INB.[Provance.Class.BFA.TitleLicensingPosition!AssignmentCount] AS AssignmentCount,
INB.BaseManagedEntityId AS BaseManagedEntityId,
INB.[Provance.Class.BFA.TitleLicensingPosition!BatchId] AS BatchId,
INB.[System.Entity!DisplayName] AS DisplayName,
INB.[Provance.Class.BFA.TitleLicensingPosition!EntitlementsAvailable] AS EntitlementsAvailable,
INB.[Provance.Class.BFA.TitleLicensingPosition!EntitlementsRemaining] AS EntitlementsRemaining,
INB.[Provance.Class.BFA.TitleLicensingPosition!InstallsCovered] AS InstallsCovered,
INB.[Provance.Class.BFA.TitleLicensingPosition!InstallsExcluded] AS InstallsExcluded,
INB.[Provance.Class.BFA.TitleLicensingPosition!InstallsNormalized] AS InstallsNormalized,
INB.[Provance.Class.BFA.TitleLicensingPosition!InstallsNotCovered] AS InstallsNotCovered,
INB.[Provance.Class.BFA.TitleLicensingPosition!LicensingPositionIndicatorId] AS LicensingPositionIndicatorId,
INB.[Provance.Class.BFA.TitleLicensingPosition!LicensingPositionPercentage] AS LicensingPositionPercentage,
Dim.ProvanceBFATitleLicensingPositionDimKey AS ProvanceBFATitleLicensingPositionDimKey,
INB.[Provance.Class.BFA.TitleLicensingPosition!SoftwareTitleGuid] AS SoftwareTitleGuid,
INB.[Provance.Class.BFA.TitleLicensingPosition!TimeStamp] AS TimeStamp,
INB.[Provance.Class.BFA.TitleLicensingPosition!TitleLicensingPositionId] AS TitleLicensingPositionId,
ROW_NUMBER() OVER (PARTITION BY [Provance.Class.BFA.TitleLicensingPosition!SoftwareTitleGuid], CAST(CONVERT(nvarchar(8), INB.[Provance.Class.BFA.TitleLicensingPosition!TimeStamp], 112) AS INT)
ORDER BY INB.[Provance.Class.BFA.TitleLicensingPosition!TimeStamp] DESC,
INB.[Provance.Class.BFA.TitleLicensingPosition!BatchId] DESC)
AS DaySeqNum,
INB.TimeAdded AS TimeAdded
FROM inbound.MTV_Provance$Class$BFA$TitleLicensingPosition INB
LEFT JOIN dbo.ProvanceBFATitleLicensingPositionDimvw Dim ON Dim.BaseManagedEntityId = INB.BaseManagedEntityId
WHERE INB.DWTimestamp >= @WaterMarkDate
AND INB.DWTimestamp < @CurrentUtcDate) A
where a.DaySeqNum = 1 -- Keep the most recent record by day

-- If there are any early arrivals - e.g. no row in ProvanceBFATitleLicensingPositionDimvw yet, update their DWTimestamp so we get them
-- on the next run
SELECT @task = 'Rejecting early arriving records'
UPDATE INB
SET DWTimestamp = @CurrentUtcDate
FROM inbound.MTV_Provance$Class$BFA$TitleLicensingPosition INB
JOIN #Temp1 T ON INB.BaseManagedEntityId = T.BaseManagedEntityId
WHERE T.ProvanceBFATitleLicensingPositionDimKey IS NULL
AND INB.DWTimestamp >= @WaterMarkDate
AND INB.DWTimestamp < @CurrentUtcDate

DELETE FROM #Temp1 WHERE ProvanceBFATitleLicensingPositionDimKey IS NULL

-- KeySeqNo will put records in order of SoftwareTitleGuid,Timestamp each record will be assigned an EndDay that is one day before the StartDay
-- of the next record in order.
SELECT @task = 'Setting EndDay for new facts in t#Temp1'
UPDATE T1
SET T1.EndDay = CAST(CONVERT(nvarchar(8), DATEADD(D,-1,T2.TimeStamp), 112) AS INT)
FROM #Temp1 T1
JOIN #Temp1 T2 ON T1.SoftwareTitleGuid = T2.SoftwareTitleGuid
AND T1.KeySeqNum + 1 = T2.KeySeqNum

-- Update existing facts
SELECT @task = 'Update existing facts'
UPDATE F
SET F.AssignmentCount = T.AssignmentCount,
F.BatchId = T.BatchId,
F.DisplayName = T.DisplayName,
F.EndDay = T.EndDay,
F.EntitlementsAvailable = T.EntitlementsAvailable,
F.EntitlementsRemaining = T.EntitlementsRemaining,
F.InstallsCovered = T.InstallsCovered,
F.InstallsExcluded = T.InstallsExcluded,
F.InstallsNormalized = T.InstallsNormalized,
F.InstallsNotCovered = T.InstallsNotCovered,
F.LicensingPositionIndicatorId = T.LicensingPositionIndicatorId,
F.LicensingPositionPercentage = T.LicensingPositionPercentage,
F.TimeStamp = T.TimeStamp,
F.TitleLicensingPositionId = T.TitleLicensingPositionId,
UpdatedBatchId = @BatchId
FROM dbo.ProvanceBFATitleLicensingPositionDailyFactvw F
JOIN #Temp1 T ON F.SoftwareTitleGuid = T.SoftwareTitleGuid
AND F.StartDay = T.StartDay

SELECT @Updated = @@rowcount

-- The should only be one row per SoftwareTitleGuid that has a null EndDay in BFATitleLicensingPositionDailyFactvw
-- The oldest per SoftwareTitleGuid in #Temp table (T.KeySeqNo = 1) will be used to set the EndDay of that record
-- if it is older than the oldest in the temp table.
SELECT @task = 'Setting EndDay for exising facts'
UPDATE F
SET F.EndDay = CAST(CONVERT(nvarchar(8), DATEADD(D,-1,T.TimeStamp), 112) AS INT),
UpdatedBatchId = @BatchId
FROM dbo.ProvanceBFATitleLicensingPositionDailyFactvw F
JOIN #Temp1 T ON F.SoftwareTitleGuid = T.SoftwareTitleGuid
AND F.StartDay < T.StartDay
AND T.KeySeqNum = 1
WHERE F.EndDay is Null
SELECT @Updated = @Updated + @@rowcount

-- Remove the rows that already exist
DELETE T
FROM #Temp1 T
JOIN dbo.ProvanceBFATitleLicensingPositionDailyFactvw F ON T.SoftwareTitleGuid = F.SoftwareTitleGuid
AND T.StartDay = F.StartDay
-- Insert new facts
SELECT @task = 'Insert new facts.'
INSERT INTO dbo.ProvanceBFATitleLicensingPositionDailyFactvw (
AssignmentCount,
BatchId,
DateKey,
DisplayName,
EndDay,
EntitlementsAvailable,
EntitlementsRemaining,
InsertedBatchId,
InstallsCovered,
InstallsExcluded,
InstallsNormalized,
InstallsNotCovered,
LicensingPositionIndicatorId,
LicensingPositionPercentage,
ProvanceBFATitleLicensingPositionDimKey,
SoftwareTitleGuid,
StartDay,
TimeStamp,
TitleLicensingPositionId,
UpdatedBatchId)
SELECT
T.AssignmentCount,
T.BatchId,
T.DateKey,
t.DisplayName,
T.EndDay,
T.EntitlementsAvailable,
T.EntitlementsRemaining,
@BatchId,
T.InstallsCovered,
T.InstallsExcluded,
T.InstallsNormalized,
T.InstallsNotCovered,
T.LicensingPositionIndicatorId,
T.LicensingPositionPercentage,
T.ProvanceBFATitleLicensingPositionDimKey,
T.SoftwareTitleGuid,
T.StartDay,
T.TimeStamp,
T.TitleLicensingPositionId,
@BatchId
FROM #Temp1 T
SELECT @Inserted = @@rowcount

-- Test code...
--select 1 stepc, getdate() datec,* into temp_wm from #wm a
--insert into temp_wm select 1 stepc, getdate() datec,* from #wm a
-- select * from temp_wm order by datec,stepc
-- sp_help temp_wm

SELECT @task = 'Updating Watermark.'
UPDATE #wm SET WaterMark = CONVERT(nvarchar(64), isnull(@CurrentUtcDate, '1/1/1900'), 109)
WHERE WarehouseEntityName = N'MTV_Provance$Class$BFA$TitleLicensingPosition' and WaterMarkType= N'DateTime'


SELECT @WaterMark = (SELECT ModuleName AS "@ModuleName",
ProcessName AS "@ProcessName",
@BatchId AS "@BatchId",
(SELECT DISTINCT
WarehouseEntityName AS "@WarehouseEntityName",
WarehouseEntityTypeName AS "@WarehouseEntityTypeName",
EntityGuid AS "@EntityGuid",
CASE WarehouseEntityTypeName
WHEN 'Inbound' THEN 'DateTime'
ELSE 'BatchId' END AS "@WaterMarkType",
WaterMark AS "@WaterMark"
FROM #wm
FOR XML path('Entity'), type)
FROM (SELECT DISTINCT ModuleName, ProcessName from #wm) a
FOR XML path('Module'), type)


SELECT @WaterMark as WaterMark, @BatchId as BatchId, @Updated as UpdatedRowCount, @Inserted as InsertedRowCount

END TRY
BEGIN CATCH
DECLARE @errorFmt VARCHAR(256)

SELECT @errorFmt = N'ErrorNumber="%d" Message="%s" Severity="%d" State="%d" ProcedureName="%s" LineNumber="%d" Task="%s"',
@errorNumber = ERROR_NUMBER(),
@errorMessage = ERROR_MESSAGE(),
@errorSeverity = ERROR_SEVERITY(),
@errorState = ERROR_STATE(),
@errorLine = ERROR_LINE(),
@errorProcedure = ERROR_PROCEDURE()

IF(@@TRANCOUNT > @startTranCount) ROLLBACK TRANSACTION

IF OBJECT_ID('tempdb..#Temp1') IS NOT NULL
BEGIN
DROP TABLE #Temp1
END

RAISERROR (
@errorFmt,
@errorSeverity,
@errorState,
@errorNumber,
@errorMessage,
@errorSeverity,
@errorState,
@errorProcedure,
@errorLine,
@task
)

RETURN -1
END CATCH

SET XACT_ABORT OFF
SET NOCOUNT OFF
END

GO