Automatically Create Model Partitions

Creating Tabluar model partitions through visual studio may be a headache task. If you manually typed wrong query in any partition, you may screw up the processing.

In this post, I will share some code I used before to help you automatically create SSAS model partitions.

Step 1: Using SQL management studuo, we need to create a table called PartitionList to provide some information about the partition including PartitionID, the dates which will be used in the partition query and etc.

IF OBJECT_ID(‘dbo.PartitionList’) IS NOT NULL

BEGIN

DROP TABLE dbo.PartitionList

END

CREATE TABLE dbo.[PartitionList]

([PartitionID] [INT] IDENTITY(1, 1)

NOT NULL,

[CreatedDate] [DATETIME] NOT NULL,

[Active] [INT] NOT NULL,

[PartitionNameSuffix] [VARCHAR](255) NOT NULL,

[PartitionStartDate] [DATE] NOT NULL,

[PartitionEndDate] [DATE] NOT NULL,

[PartitionStartDateID] AS (CONVERT( [INT], CONVERT([CHAR](8), [PartitionStartDate], (112)))) PERSISTED,

[PartitionEndDateID] AS (CONVERT( [INT], CONVERT([CHAR](8), [PartitionEndDate], (112)))

)

CONSTRAINT [PK_PartitionList] PRIMARY KEY CLUSTERED

(

[PartitionID] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

) ON [PRIMARY]

GO

ALTER TABLE dbo.[PartitionList]

ADD CONSTRAINT [DF_PartitionList_CreatedDate] DEFAULT(GETDATE()) FOR [CreatedDate]

GO

ALTER TABLE dbo.[PartitionList]

ADD CONSTRAINT [DF_PartitionList_Active] DEFAULT((0)) FOR [Active]

GO

–DELETE dbo.[PartitionList]

–SELECT *

–FROM dbo.[PartitionList]

Step 2: After created the Partition List Table, we need to populate the list with data. Assuming you need to create weekly partitions for year 2016. And we will need a calendar table(most organization will have calendar table, and if you don’t have, you can find plenty of sources online. So here I assume you have one). 

DECLARE @dynamicSQL VARCHAR(MAX)

SET @dynamicSQL = ”

SELECT @dynamicSQL = @dynamicSQL+’INSERT INTO dbo.[PartitionList] (

[PartitionNameSuffix]

,[PartitionStartDate]

,[PartitionEndDate])

VALUES (”’+CAST(CalendarYear AS CHAR(4))+’W’+RIGHT(‘0’+CAST(CalendarWeekNumber AS VARCHAR(2)), 2)+”’

, ”’+CONVERT(VARCHAR(50), [Date])+”’

, ”’+CONVERT(VARCHAR(50), DATEADD(day, 6, [Date]))+”’)’

FROM Ancillary.DBO.V_Calendar x WITH (NOLOCK)

WHERE [Date] >= ‘2016-01-01’

AND [Date] < ‘2017-01-01’

AND ([Day Number Of Week] = 1

OR [Date] = ‘2016-01-01’)

ORDER BY x.[Date]

EXEC (@dynamicSQL)

UPDATE PartitionList

SET

active = 1

WHERE PartitionID = 1

UPDATE PartitionList

SET

PartitionEndDate = ‘2016-01-02’

WHERE PartitionID = 1

UPDATE PartitionList

SET

active = 1

WHERE PartitionID = 1

SELECT *

FROM PartitionList

Step 3: Create a table called Modelinfo which provide the information about the model and the table in the model you are partitioning at. 

IF OBJECT_ID(‘dbo.ModelInfo’) IS NOT NULL

BEGIN

DROP TABLE dbo.ModelInfo

END

CREATE TABLE dbo.ModelInfo

(ModelInfoID INT IDENTITY(1, 1)

NOT NULL,

DatabaseID VARCHAR(200),

CubeID VARCHAR(200),

MeasureID VARCHAR(200),

DatasourceID VARCHAR(200),

TableName VARCHAR(200),

PartitionField VARCHAR(200),

ServerName VARCHAR(200)

)

DELETE dbo.modelinfo

INSERT INTO dbo.ModelInfo

VALUES

(‘(modelName)‘,

(Usually you just need to put – Model)‘,

(ModelTableId which can be found in partition processing script)‘,

(DatasourceID which can be found when you trying to script on creating an new partition through management studio)‘,

(the table name in the database which your model table is trying to query at)‘,

(the field to partition at)‘,

(The server which the model is located at)

)

Step 3: Create a table called TableList which provide the information about partition id and queries on the targeted model table. Assume in our table has a field called [System] and we need to partition the table by system and by week

IF OBJECT_ID(‘dbo.TableList’) IS NOT NULL

BEGIN

DROP TABLE dbo.TableList

END

CREATE TABLE dbo.TableList

([PartitionID] [INT] NOT NULL,

[System] VARCHAR(255) NOT NULL,

[PartitionName] VARCHAR(255) NOT NULL,

[TableName] [VARCHAR](255) NOT NULL,

[PartitionQuery] [VARCHAR](MAX) NULL,

[Active] [INT] NOT NULL

)

ON [PRIMARY]

ALTER TABLE dbo.[TableList]

ADD CONSTRAINT [DF_Table_Active] DEFAULT((0)) FOR [Active]

Step 4: Populate the TableList with data regarding the tables partition queries

IF OBJECT_ID(‘TEMPDB..#TempModelInfo’) IS NOT NULL

BEGIN

DROP TABLE #TempModelInfo

END

SELECT *

INTO #TempModelInfo

FROM dbo.ModelInfo

WHILE(

(

SELECT COUNT(*)

FROM #TempModelInfo

) > 0)

BEGIN

DECLARE @ModelInfoID INT=

(

SELECT MIN(ModelInfoID)

FROM #TempModelInfo

)

DECLARE @TableName VARCHAR(200)=

(

SELECT TableName

FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

)

DECLARE @PartitionField VARCHAR(200)=

(

SELECT PartitionField

FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

)

DECLARE @int INT= 1

WHILE(@int < 54)

BEGIN

IF OBJECT_ID(‘TEMPDB..#TempSystems’) IS NOT NULL

BEGIN

DROP TABLE #TempSystems

END

SELECT ‘SystemA’ AS SystemName

INTO #TempSystems

UNION

SELECT ‘SystemB’

UNION

SELECT ‘SystemC’

UNION

SELECT ‘SystemD’

WHILE(

(

SELECT COUNT(*)

FROM #TempSystems

) > 0)

BEGIN

DECLARE @System VARCHAR(50)=

(

SELECT MIN(SystemName)

FROM #TempSystems

)

DECLARE @FilterStart VARCHAR(50)= CAST(

(

SELECT PartitionStartDate

FROM dbo.PartitionList

WHERE PartitionID = @int

) AS VARCHAR(50))

DECLARE @FilterEnd VARCHAR(50)= CAST(

(

SELECT PartitionEndDate

FROM dbo.PartitionList

WHERE PartitionID = @int

) AS VARCHAR(50))

DECLARE @PartitionName VARCHAR(100)= @System +

(

SELECT PartitionNameSuffix

FROM dbo.PartitionList

WHERE PartitionID = @int

)

INSERT INTO dbo.TableList

(TableName,

PartitionID,

System,

PartitionName,

PartitionQuery

)

VALUES

(@TableName,

@int,

@System,

@PartitionName,

‘SELECT * FROM dbo.’+@TableName+’ WHERE ‘+’LTRIM(RTRIM([System])) =”’+@System+”’ and ‘+@PartitionField+’ between ”’+@FilterStart+”’ AND ”’+@FilterEnd+”’ ‘

)

DELETE FROM #TempSystems

WHERE SystemName = @System

END

SET @int = @int + 1

END

DELETE FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

END

Step 5: Create a store procedure, by excuting the store procedure it will create a job in your SQL server agent. You can double check the properties of the job and make sure everything looks good. By triggering the job, your partitions will created in the model you are targeted at

Create PROC [dbo].[CreatePartitions]

AS

DECLARE @UserName VARCHAR(200)=

(

SELECT CURRENT_USER

)

IF OBJECT_ID(‘TEMPDB..#TempModelInfo’) IS NOT NULL

BEGIN

DROP TABLE #TempModelInfo

END

SELECT *

INTO #TempModelInfo

FROM dbo.ModelInfo

WHILE(

(

SELECT COUNT(*)

FROM #TempModelInfo

) > 0)

BEGIN

DECLARE @ModelInfoID INT=

(

SELECT MIN(ModelInfoID)

FROM #TempModelInfo

)

DECLARE @ServerName VARCHAR(200)=

(

SELECT ServerName

FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

)

DECLARE @DatabaseID VARCHAR(200)=

(

SELECT DatabaseID

FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

)

DECLARE @CubeID VARCHAR(200)=

(

SELECT CubeID

FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

)

DECLARE @MeasureGroupID VARCHAR(200)=

(

SELECT MeasureID

FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

)

DECLARE @DatasourceID VARCHAR(200)=

(

SELECT DatasourceID

FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

)

DECLARE @TableName VARCHAR(200)=

(

SELECT TableName

FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

)

DECLARE @JobName VARCHAR(255)= ‘CreatePartition_’+@DatabaseID+’_’+@TableName

EXEC msdb.dbo.sp_add_job

@job_name = @JobName,

@enabled = 1,

@notify_level_eventlog = 0,

@notify_level_email = 0,

@notify_level_netsend = 0,

@notify_level_page = 0,

@delete_level = 0,

@category_name = N'[Uncategorized (Local)]’,

@owner_login_name = @UserName

IF OBJECT_ID(‘TEMPDB..#TempSystems’) IS NOT NULL

BEGIN

DROP TABLE #TempSystems

END

SELECT ‘System1’ AS SystemName

INTO #TempSystems

UNION

SELECT ‘System2’

UNION

SELECT ‘System3’

UNION

SELECT ‘System4’

WHILE(

(

SELECT COUNT(*)

FROM #TempSystems

) > 0)

BEGIN

DECLARE @int INT= 1

DECLARE @OnSuccess INT= 3

WHILE(@int < 54)

BEGIN

DECLARE @System VARCHAR(50)=

(

SELECT MIN(SystemName)

FROM #TempSystems

)

DECLARE @PartitionQuery VARCHAR(800)=

(

SELECT PartitionQuery

FROM [TableList] WITH (NOLOCK)

WHERE PartitionID = @int

AND [System] = @System

AND [TableName] = @TableName

)

DECLARE @PartitionName VARCHAR(200)=

(

SELECT PartitionName

FROM [TableList] WITH (NOLOCK)

WHERE PartitionID = @int

AND [System] = @System

AND [TableName] = @TableName

)

DECLARE @PartitionCmd VARCHAR(MAX)= ‘

<Alter AllowCreate=”true” ObjectExpansion=”ExpandFull” xmlns=”http://schemas.microsoft.com/analysisservices/2003/engine”&gt;

‘+@DatabaseID+’

‘+@CubeID+’

‘+@MeasureGroupID+’

‘+@PartitionName+’

<ObjectDefinition>

<Partition xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221; xmlns:ddl2=”http://schemas.microsoft.com/analysisservices/2003/engine/2&#8243; xmlns:ddl2_2=”http://schemas.microsoft.com/analysisservices/2003/engine/2/2&#8243; xmlns:ddl100_100=”http://schemas.microsoft.com/analysisservices/2008/engine/100/100&#8243; xmlns:ddl200=”http://schemas.microsoft.com/analysisservices/2010/engine/200&#8243; xmlns:ddl200_200=”http://schemas.microsoft.com/analysisservices/2010/engine/200/200&#8243; xmlns:ddl300=”http://schemas.microsoft.com/analysisservices/2011/engine/300&#8243; xmlns:ddl300_300=”http://schemas.microsoft.com/analysisservices/2011/engine/300/300&#8243; xmlns:ddl400=”http://schemas.microsoft.com/analysisservices/2012/engine/400&#8243; xmlns:ddl400_400=”http://schemas.microsoft.com/analysisservices/2012/engine/400/400″&gt;

<ID>’+@PartitionName+'</ID>

<Name>’+@PartitionName+'</Name>

<Source xsi:type=”QueryBinding”>

<DataSourceID>’+@DataSourceID+'</DataSourceID>

<QueryDefinition>’+@PartitionQuery+'</QueryDefinition>

</Source>

<StorageMode valuens=”ddl200_200″>InMemory</StorageMode>

<ProcessingMode>Regular</ProcessingMode>

<ddl300_300:DirectQueryUsage>InMemoryOnly</ddl300_300:DirectQueryUsage>

</Partition>

</ObjectDefinition>

</Alter>’

IF @int = 53

AND @System = ‘System4’

BEGIN

SET @OnSuccess = 1

END

EXEC msdb.dbo.sp_add_jobstep

@job_name = @JobName,

@step_name = @PartitionName,

@step_id = @int,

@cmdexec_success_code = 0,

@on_success_action = @OnSuccess,

@on_fail_action = 2,

@retry_attempts = 0,

@retry_interval = 0,

@os_run_priority = 0,

@subsystem = N’ANALYSISCOMMAND’,

@command = @PartitionCmd,

@server = @ServerName,

@database_name = N’master’,

@flags = 0,

@proxy_name = N’BAO_SSIS’

SET @int = @int + 1

END

–EXEC msdb.dbo.sp_start_job

— @job_name = @JobName

DELETE FROM #TempSystems

WHERE SystemName = @System

END

EXEC msdb.dbo.sp_update_job

@job_name = @JobName,

@start_step_id = 1

EXEC msdb.dbo.sp_add_jobserver

@job_name = @JobName,

@server_name = N’(put here the server name where your agent job at)

DELETE FROM #TempModelInfo

WHERE ModelInfoID = @ModelInfoID

END

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: