tag:blogger.com,1999:blog-63344812334077435032024-03-12T23:25:31.480+00:00BI LogBusiness Intelligence related blog posts.Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.comBlogger24125tag:blogger.com,1999:blog-6334481233407743503.post-40059480300028399582012-01-25T08:29:00.002+00:002012-01-25T08:30:33.979+00:00SQL Server - Primary KeysI will say that it's amazing what you find out when you try things a different way. Presumably we all know that columns taking part in a primary key cannot be NULL but have you ever tried the different ways of creating them and seeing what happens? Take the following for instance:<br />
<br />
<pre wrap="">CREATE TABLE [#tab1]
(
[my_key_col1] INT PRIMARY KEY CLUSTERED,
[multiplier] FLOAT
);
</pre>
<br />
Note how the default for a column is to be nullable when not specified yet the statement succeeds. Looking at the table definition (i.e. change into [tempdb], highlight the name of the table and press ALT-F1) you can see that the column taking part in the primary key has actually been set to NOT NULL. So how about this way:<br />
<br />
<pre wrap="">CREATE TABLE [#tab2]
(
[my_key_col1] INT,
[multiplier] FLOAT,
PRIMARY KEY CLUSTERED([my_key_col1])
);
</pre>
<br />
This works as well, also setting the column taking part in the primary key to NOT NULL. Clearly SQL Server will set any columns taking part in a primary key to be not nullable when "nullability" is not specified in the column definition. i.e. Leaving it to use the defaults. If you do specifically set the column to be NOT NULL then the create statement will fail. Indeed, books online for SQL Server 2008 for the CREATE TABLE construct states:<br />
<br />
<pre wrap="">All columns defined within a PRIMARY KEY constraint must be defined as NOT NULL.
If nullability is not specified, all columns participating in a PRIMARY KEY constraint have their nullability set to NOT NULL.
</pre>
<br />
Now what about the following?<br />
<br />
<br />
<pre wrap="">CREATE TABLE [#tab3]
(
[my_key_col1] INT,
[multiplier] FLOAT
);
ALTER TABLE [#tab3] ADD PRIMARY KEY CLUSTERED([my_key_col1]);
</pre>
<br />
As expected this <i>fails</i> to add the primary key because the "nullability" of the column has been defined at the time the primary key is to be added. Once the table has been materialised all aspects of its definition have been put in place. Thus trying to add a primary key to columns defined as nullable must fail.<br />
<br />
I always explicitly specify the "nullability" of columns in the definition of all tables I create, including temporary tables, which is why the first two examples surprised me. I was not expecting SQL Server to override the defaults. Hmmmm, just goes to show that we are never too old to learn eh?<br />
<br />
Now before we finish, let's clean up after ourselves...<br />
<br />
<br />
<pre wrap="">DROP TABLE [#tab1], [#tab2], [#tab3];
</pre><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-66815105089022830742012-01-20T08:55:00.002+00:002012-01-25T08:32:18.655+00:00SQL Server - Join the UNIONWow, no posts for months then two in a week. What's going on?<br />
<br />
Well, the prompt for this post occurred whilst going through another developer's code in order to performance tune it (got it down from over half-an-hour to 1 second btw) and found a derived table using code similar to the following:<br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
SELECT *</div>
<div style="font-family: "Courier New",Courier,monospace;">
FROM [dbo].[taba]</div>
<div style="font-family: "Courier New",Courier,monospace;">
UNION ALL</div>
<div style="font-family: "Courier New",Courier,monospace;">
SELECT *</div>
<div style="font-family: "Courier New",Courier,monospace;">
FROM [dbo].[tabb]</div>
<br />
Well, first off I would like to say that you should never use "<span style="font-family: "Courier New",Courier,monospace;">SELECT *</span>" other than for truely adhoc queries, ever. Never ever. Did I say ever? Just to be clear then, never ever. Okay, got it? One more time then, never ever use "<span style="font-family: "Courier New",Courier,monospace;">SELECT *</span>" other than for adhoc queries, ever.<br />
<br />
The problem with SELECT * is that what happens when the underlying table is modified? A new column is added, or removed. What about if an update re-orders the columns? This last one I'll come back to but note that depending on the context of the full query, the "<span style="font-family: "Courier New",Courier,monospace;">SELECT *</span>" part can fail in different ways. Inserting into a given table will fail if a column is added or removed. You may get incorrect information if the columns are re-ordered or it may fail if the data types are incompatible making this especially dangerous. You might argue that a "<span style="font-family: "Courier New",Courier,monospace;">SELECT * INTO</span>" statement is okay but you once again are either copying data that you don't need, in the case where a column is added, or may just remove a required column without knowing it if a column is dropped from the underlying table.<br />
<br />
Trust me on this, production systems should not contain "<span style="font-family: "Courier New",Courier,monospace;">SELECT *</span>" queries. And don't use them in views either.<br />
<br />
Anyhoo, back to the reason for the post. So coming back to the re-ordered columns part. What do you think happens in the UNION ALL statement above if the columns in <span style="font-family: "Courier New",Courier,monospace;">[taba]</span> are in a different order to <span style="font-family: "Courier New",Courier,monospace;">[tabb]</span>? Let's assume compatible data types. <br />
<br />
Well, try it...<br />
<br />
<pre wrap="">-- DROP TABLE [#t1], [#t2];
CREATE TABLE [#t1] ([col1] int, [col2] int);
CREATE TABLE [#t2] ([col2] int, [col1] int);
INSERT INTO [#t1] ([col1], [col2]) VALUES (1, 10);
INSERT INTO [#t2] ([col1], [col2]) VALUES (2, 20);
SELECT *</pre>
<pre wrap=""> FROM [#t1]</pre>
<pre wrap="">UNION ALL</pre>
<pre wrap=""> SELECT *</pre>
<pre wrap=""> FROM [#t2];
</pre>
<br />
Expected behaviour? Would you like to see this in your production systems? I'll leave you with that thought.<br />
<br /><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-40945538157802974202012-01-18T20:53:00.000+00:002012-01-18T20:53:42.417+00:00SQL Server - Validation During Function CreationNow here's a little thing I didn't know until recently. Seems like this is happening a lot lately and I really should get around to documenting these at some point. Anyhoo, my latest finding is as follows...<br />
<br />
We have a process that, every time a script is checked into our version control system, rebuilds all of the databases from scratch, starting from Release 1 and then applying all updates in order. This normally ensures a problem free release into production, however, this most recent time was different. This time the release into production failed when trying to create a function in one of the databases. So what was different between production and the build process? If I mention that we have a stored procedure that creates a temporary table that is used by the function, does that prompt any ideas of what went wrong?<br />
<br />
Well, here's the thing...<br />
For inline table functions, attempting to create one when the underlying object does not exist will fail. However, for scalar and multi-statement table functions things are a little different. If the underlying objects do not exist the functions will be created with no issue. However, if the underlying objects <i>do</i> exist, a check is performed to ensure that their definition matches that expected by the function.<br />
<br />
So in our case, because the system is live in production the SP has been called many times and thus the table has been created and dropped many times. However, in the new update the structure of this table has been changed. Now because the SP is never actually called during the build process no table has been created and the function can be deployed. In production however, the SP has been called and the old version of the table does exist, causing the installation to fail.<br />
<br />
Stored procedures exhibit this same behaviour but don't have the differences related to inline and multi-statement/scalar functions.<br />
<br />
<u>Try it yourself</u>:<br />
<br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;"><span style="color: green; font-size: x-small;"><span style="color: green; font-size: x-small;">/**<br />
<span style="font-family: Courier New; font-size: x-small;">* Create functions.<br />
</span><span style="font-family: Courier New; font-size: x-small;">*/</span> </span></span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;"><span style="color: green; font-size: x-small;"><span style="color: green; font-size: x-small;">-- Successful.</span></span><br />
CREATE</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"> <span style="color: blue;"><span style="color: blue;">FUNCTION</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[udf_scalar_works]<span style="color: grey;"><span style="color: grey;">()</span></span></span></span><span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;"> </span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">RETURNS</span></span></span><span style="font-family: Courier New; font-size: x-small;"> </span><span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">INT</span><span style="font-family: Courier New; font-size: x-small;"> </span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">AS</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">BEGIN</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"> </span></span></span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"> RETURN </span></span><span style="color: grey;"><span style="color: grey;">(</span></span> <span style="color: blue;"><span style="color: blue;">SELECT</span></span> <span style="color: blue;"><span style="color: blue;">TOP</span></span> 1 [col2] <span style="color: blue;"><span style="color: blue;">FROM</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[bar] <span style="color: grey;"><span style="color: grey;">);</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">END</span></span></span><span style="color: grey;"><span style="color: grey;"><span style="font-family: Courier New; font-size: x-small;">;</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">GO<br />
<br />
</span><span style="font-family: Courier New; font-size: x-small;"><span style="color: green;">-- Successful.</span><br />
CREATE</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"> <span style="color: blue;"><span style="color: blue;">FUNCTION</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[udf_multi_works]<span style="color: grey;"><span style="color: grey;">()</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">RETURNS</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"> @x <span style="color: blue;"><span style="color: blue;">TABLE </span></span><span style="color: grey;"><span style="color: grey;">(</span></span>aaa <span style="color: blue;"><span style="color: blue;">INT</span></span><span style="color: grey;"><span style="color: grey;">)</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">AS</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">BEGIN</span></span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"> INSERT</span></span> <span style="color: blue;"><span style="color: blue;">INTO</span></span> @x<span style="color: blue;"><span style="color: blue;"> </span></span><span style="color: grey;"><span style="color: grey;">(</span></span>aaa<span style="color: grey;"><span style="color: grey;">)</span></span></span></span><br />
<span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue; font-family: Courier New;"> SELECT</span></span><span style="font-family: Courier New;"> [col2]</span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"> FROM</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[bar]<span style="color: grey;"><span style="color: grey;">;</span></span></span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: grey;"><span style="color: grey;"> </span></span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"><span style="color: grey;"><br />
</span> RETURN</span></span><span style="color: grey;"><span style="color: grey;">;</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">END</span></span></span><span style="color: grey;"><span style="color: grey;"><span style="font-family: Courier New; font-size: x-small;">;</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">GO<br />
<br />
</span></span></span><span style="color: green;"><span style="color: green; font-family: Courier New; font-size: x-small;">-- Error: Invalid object name 'dbo.bar'.</span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">CREATE</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"> <span style="color: blue;"><span style="color: blue;">FUNCTION</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[udf_inline_doesnt_work]<span style="color: grey;"><span style="color: grey;">()</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">RETURNS</span></span></span><span style="font-family: Courier New; font-size: x-small;"> </span><span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">TABLE</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">AS</span></span></span><br />
<span style="font-size: x-small;"><span style="font-family: Courier New;"><span style="color: blue;"><span style="color: blue;"> RETURN </span></span><span style="color: grey;"><span style="color: grey;">(</span></span> <span style="color: blue;"><span style="color: blue;">SELECT</span></span></span><span style="font-family: Courier New;"> [col2]</span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"> FROM</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[bar] <span style="color: grey;"><span style="color: grey;">);</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">GO<br />
<br />
<br />
</span></span></span><span style="color: green;"><span style="color: green;"><span style="font-family: Courier New; font-size: x-small;">/**<br />
</span><span style="font-family: Courier New; font-size: x-small;">* Create table without the required column.<br />
</span><span style="font-family: Courier New; font-size: x-small;">*/</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">CREATE</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"> <span style="color: blue;"><span style="color: blue;">TABLE</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[bar]<span style="color: blue;"><span style="color: blue;"> </span></span><span style="color: grey;"><span style="color: grey;">(</span></span> [col1] <span style="color: blue;"><span style="color: blue;">INT</span></span> <span style="color: grey;"><span style="color: grey;">);</span></span></span></span><span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">GO<br />
<br />
<br />
</span></span></span><span style="color: green;"><span style="color: green;"><span style="font-family: Courier New; font-size: x-small;">/**<br />
</span><span style="font-family: Courier New; font-size: x-small;">* Try create functions again.<br />
</span><span style="font-family: Courier New; font-size: x-small;">*/</span></span></span><br />
<span style="color: green;"><span style="color: green;"><span style="font-family: Courier New; font-size: x-small;">-- Invalid column name 'col2'.</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">CREATE</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"> <span style="color: blue;"><span style="color: blue;">FUNCTION</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[udf_scalar_doesnt_work]<span style="color: grey;"><span style="color: grey;">()</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">RETURNS</span></span></span><span style="font-family: Courier New; font-size: x-small;"> </span><span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">INT</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">AS</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">BEGIN</span></span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"> RETURN </span></span><span style="color: grey;"><span style="color: grey;">(</span></span> <span style="color: blue;"><span style="color: blue;">SELECT</span></span> <span style="color: blue;"><span style="color: blue;">TOP</span></span> 1 [col2] <span style="color: blue;"><span style="color: blue;">FROM</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[bar] <span style="color: grey;"><span style="color: grey;">);</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">END</span></span></span><span style="color: grey;"><span style="color: grey;"><span style="font-family: Courier New; font-size: x-small;">;</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">GO<br />
<br />
</span></span></span><span style="color: green;"><span style="color: green; font-family: Courier New; font-size: x-small;">-- Error: Invalid column name 'col2'.</span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">CREATE</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"> <span style="color: blue;"><span style="color: blue;">FUNCTION</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[udf_multi_doesnt_work]<span style="color: grey;"><span style="color: grey;">()</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">RETURNS</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"> @x <span style="color: blue;"><span style="color: blue;">TABLE </span></span><span style="color: grey;"><span style="color: grey;">(</span></span>aaa <span style="color: blue;"><span style="color: blue;">INT</span></span><span style="color: grey;"><span style="color: grey;">)</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">AS</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">BEGIN</span></span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"> INSERT</span></span> <span style="color: blue;"><span style="color: blue;">INTO</span></span> @x<span style="color: blue;"><span style="color: blue;"> </span></span><span style="color: grey;"><span style="color: grey;">(</span></span>aaa<span style="color: grey;"><span style="color: grey;">)</span></span></span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"> SELECT</span></span> [col2]</span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"> <span style="color: blue;"><span style="color: blue;">FROM</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[bar]<span style="color: grey;"><span style="color: grey;">;</span></span></span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: grey;"><span style="color: grey;"> </span></span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"><span style="color: grey;"><br />
</span> RETURN</span></span><span style="color: grey;"><span style="color: grey;">;</span></span></span></span><span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;"> </span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">END</span></span></span><span style="color: grey;"><span style="color: grey;"><span style="font-family: Courier New; font-size: x-small;">;</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">GO</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;"><br />
</span></span></span><span style="color: green;"><span style="color: green; font-family: Courier New; font-size: x-small;">-- Error: Invalid column name 'col2'.</span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">CREATE</span></span></span><span style="font-family: Courier New;"><span style="font-size: x-small;"> <span style="color: blue;"><span style="color: blue;">FUNCTION</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[udf_inline_doesnt_work]<span style="color: grey;"><span style="color: grey;">()</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">RETURNS</span></span></span><span style="font-family: Courier New; font-size: x-small;"> </span><span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">TABLE</span></span></span><br />
<span style="color: blue;"><span style="color: blue;"><span style="font-family: Courier New; font-size: x-small;">AS</span></span></span><br />
<span style="font-size: x-small;"><span style="font-family: Courier New;"><span style="color: blue;"><span style="color: blue;"> RETURN </span></span><span style="color: grey;"><span style="color: grey;">(</span></span> <span style="color: blue;"><span style="color: blue;">SELECT</span></span></span><span style="font-family: Courier New;"> [col2]</span></span><br />
<span style="font-family: Courier New;"><span style="font-size: x-small;"><span style="color: blue;"><span style="color: blue;"> FROM</span></span> [dbo]<span style="color: grey;"><span style="color: grey;">.</span></span>[bar] <span style="color: grey;"><span style="color: grey;">);</span></span></span></span><br />
<span style="color: blue;"><span style="color: blue; font-family: Courier New; font-size: x-small;">GO</span></span><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-1582730941457206662011-07-22T22:54:00.002+01:002011-07-22T23:18:04.032+01:00SQL Server - Identifying Control Characters<style>
<!--
/* Font Definitions */
@font-face
{font-family:"Courier New";
panose-1:2 7 3 9 2 2 5 2 4 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 0 0 0 1 0;}
@font-face
{font-family:Cambria;
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 0 0 0 1 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
a:link, span.MsoHyperlink
{color:blue;
text-decoration:underline;
text-underline:single;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-noshow:yes;
color:purple;
text-decoration:underline;
text-underline:single;}
pre
{mso-style-link:"HTML Preformatted Char";
margin:0cm;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:Courier;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-bidi-font-family:Courier;}
p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
{margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
margin-left:36.0pt;
margin-bottom:.0001pt;
mso-add-space:auto;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
p.MsoListParagraphCxSpFirst, li.MsoListParagraphCxSpFirst, div.MsoListParagraphCxSpFirst
{mso-style-type:export-only;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
margin-left:36.0pt;
margin-bottom:.0001pt;
mso-add-space:auto;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
p.MsoListParagraphCxSpMiddle, li.MsoListParagraphCxSpMiddle, div.MsoListParagraphCxSpMiddle
{mso-style-type:export-only;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
margin-left:36.0pt;
margin-bottom:.0001pt;
mso-add-space:auto;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
p.MsoListParagraphCxSpLast, li.MsoListParagraphCxSpLast, div.MsoListParagraphCxSpLast
{mso-style-type:export-only;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
margin-left:36.0pt;
margin-bottom:.0001pt;
mso-add-space:auto;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
span.HTMLPreformattedChar
{mso-style-name:"HTML Preformatted Char";
mso-style-locked:yes;
mso-style-link:"HTML Preformatted";
mso-ansi-font-size:10.0pt;
mso-bidi-font-size:10.0pt;
font-family:Courier;
mso-ascii-font-family:Courier;
mso-hansi-font-family:Courier;
mso-bidi-font-family:Courier;}
span.moz-txt-citetags
{mso-style-name:moz-txt-citetags;}
@page Section1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:36.0pt;
mso-footer-margin:36.0pt;
mso-paper-source:0;}
div.Section1
{page:Section1;}
/* List Definitions */
@list l0
{mso-list-id:777870908;
mso-list-template-ids:857012422;}
@list l0:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level2
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level3
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l0:level4
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level5
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level6
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l0:level7
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level8
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level9
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l1
{mso-list-id:1333097237;
mso-list-template-ids:-480072042;}
@list l1:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level2
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level3
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l1:level4
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level5
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level6
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l1:level7
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level8
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level9
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l2
{mso-list-id:1376854260;
mso-list-type:hybrid;
mso-list-template-ids:-480072042 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l2:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l3
{mso-list-id:1456826996;
mso-list-type:hybrid;
mso-list-template-ids:1636854432 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l3:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l4
{mso-list-id:1481536340;
mso-list-type:hybrid;
mso-list-template-ids:-480072042 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l4:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l5
{mso-list-id:1933468725;
mso-list-type:hybrid;
mso-list-template-ids:857012422 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l5:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
ol
{margin-bottom:0cm;}
ul
{margin-bottom:0cm;}
-->
</style> <br />
<div class="MsoNormal" style="tab-stops: 279.2pt;">Recently a query against our Analysis Services database failed with an error about invalid XML characters and thus prompted me to start the investigation as to which members contained these. I know that in Analysis Services you can set how you want to handle invalid XML characters but as we shouldn’t receive these I'm using the defaults and I don’t want to use “replace” etc.</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">Interestingly though, during my investigation I came across some unexpected behaviour with regards the 0x00 control code. At that point I just needed to identify the culprit members and prevent it from entering the database in the future, so I left that peculiarity and wrote the following function:</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">ANSI_NULLS</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;">GO</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">QUOTED_IDENTIFIER</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;">GO</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span><span style="color: blue;">SELECT</span> <span style="color: grey;">*</span> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span> <span style="color: blue;">WHERE</span> [object_id] <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[udf_string_contains_control_character]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> [type] <span style="color: grey;">IN</span> <span style="color: grey;">(</span>N<span style="color: red;">'FN'</span><span style="color: grey;">,</span> N<span style="color: red;">'IF'</span><span style="color: grey;">,</span> N<span style="color: red;">'TF'</span><span style="color: grey;">,</span> N<span style="color: red;">'FS'</span><span style="color: grey;">,</span> N<span style="color: red;">'FT'</span><span style="color: grey;">))</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">BEGIN</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">DROP</span> <span style="color: blue;">FUNCTION</span> [dbo]<span style="color: grey;">.</span>[udf_string_contains_control_character]<span style="color: grey;">;</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: 8pt;">;</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;">GO</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">FUNCTION</span> [dbo]<span style="color: grey;">.</span>[udf_find_name_with_control_character] <span style="color: grey;">(</span>@i_InputText <span style="color: blue;">NVARCHAR</span><span style="color: grey;">(</span><span style="color: magenta;">MAX</span><span style="color: grey;">))</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">RETURNS</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">INT</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">AS</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">BEGIN</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">RETURN</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: blue;">CASE</span> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span><span style="color: green;">-- First control code set (i.e. 1 to 31)</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: magenta;">PATINDEX</span><span style="color: grey;">(</span><span style="color: red;">'%['</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x01<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'-'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x1F<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">']%'</span><span style="color: grey;">,</span> @i_InputText <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT<span style="color: grey;">)</span> <span style="color: grey;">+</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: green;">-- Control character 127 (i.e. DEL)</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: magenta;">PATINDEX</span><span style="color: grey;">(</span><span style="color: red;">'%['</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x7F<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'-'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x7F<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">']%'</span><span style="color: grey;">,</span> @i_InputText <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT<span style="color: grey;">)</span> <span style="color: grey;">)</span> <span style="color: grey;">></span> 0 <span style="color: blue;">THEN</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> 1</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">ELSE</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> 0</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">END</span> <span style="color: grey;">);</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: 8pt;">;</span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;">GO</span><span style="font-size: 8pt;"></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">Clearly the function doesn’t handle every “dodgy” character but it handles some of the more common control characters and can be easily extended.</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">I then never found the time to get back to the issue with regards the 0x00 control character until now, thanks largely to a question posted on the Analysis Services forum which you can see here: <a href="http://social.msdn.microsoft.com/Forums/en/sqlanalysisservices/thread/619a0d73-455c-404f-99ad-bbebfab2cf18"><span lang="EN-US" style="font-size: 10pt;">http://social.msdn.microsoft.com/Forums/en/sqlanalysisservices/thread/619a0d73-455c-404f-99ad-bbebfab2cf18</span></a>)</div><div class="MsoNormal" style="tab-stops: 279.2pt;">In this particular case, the error message was:</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><span style="color: red; font-family: "Courier New"; font-size: 10pt;">The server sent an unrecognizable response. _'.', hexadecimal value 0x00, is an invalid character. Line <x>, position <y>.</y></x></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">This prompted me to revisit why, when I used the 0x00 control character in the filter in the above function, the function didn’t behave as I initially expected. Clearly it appears that the control character 0x00 in SQL Server is a little problematic but I didn’t realise just how problematic until I started digging a little deeper.</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">So how hard can it be to find control characters in SQL? Answer, harder than you might think. So, in SSMS run this in grid view (i.e. CTRL-D) and then in test view (i.e. CTRL-T).</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [test]<span style="color: grey;">,</span> <span style="color: magenta;">LEN</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "len"<span style="color: grey;">,</span> <span style="color: magenta;">DATALENGTH</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "data_length"</span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: red;">'foo'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test" <span style="color: grey;">)</span> a<span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">You should hopefully see the differences there. The grid view hides the underlying artefact, though the lengths clearly show something isn't right, but switching to text view shines a bit more light on the issue. So let’s try finding the row using LIKE…</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [test]<span style="color: grey;">,</span> <span style="color: magenta;">LEN</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "len"<span style="color: grey;">,</span> <span style="color: magenta;">DATALENGTH</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "data_length"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: red;">'foo'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test" <span style="color: grey;">)</span> a</span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">WHERE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [test] <span style="color: grey;">LIKE</span> <span style="color: red;">'%'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'%'</span><span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">Er, nope, that doesn’t work. Aha, maybe we need to escape it...</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [test]<span style="color: grey;">,</span> <span style="color: magenta;">LEN</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "len"<span style="color: grey;">,</span> <span style="color: magenta;">DATALENGTH</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "data_length"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: red;">'foo'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">UNION ALL</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">SELECT</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test" <span style="color: grey;">)</span> a</span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">WHERE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [test] <span style="color: grey;">LIKE</span> <span style="color: red;">'%\'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'%'</span> <span style="color: blue;">ESCAPE</span> <span style="color: red;">'\'</span><span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">Groan, grumble, no that’s still not the right answer. Note how we get both rows. I suspect all of this is due to the fact that C Strings are “Nul” terminated (i.e. \0) so all rows match. I could go on for ages about trying to use REPLACE, PATINDEX, CHARINDEX etc. as I did, but I’ll save you the time, they don’t work.</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">For example, trying to use REPLACE:</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: magenta;">REPLACE</span><span style="color: grey;">(</span>[test]<span style="color: grey;">,</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">),</span> <span style="color: red;">''</span><span style="color: grey;">)</span> <span style="color: blue;">AS</span> "test"<span style="color: grey;">,</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: magenta;">LEN</span><span style="color: grey;">(</span><span style="color: magenta;">REPLACE</span><span style="color: grey;">(</span>[test]<span style="color: grey;">,</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">),</span> <span style="color: red;">''</span><span style="color: grey;">))</span> <span style="color: blue;">AS</span> "len"<span style="color: grey;">,</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: magenta;">DATALENGTH</span><span style="color: grey;">(</span><span style="color: magenta;">REPLACE</span><span style="color: grey;">(</span>[test]<span style="color: grey;">,</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">),</span> <span style="color: red;">''</span><span style="color: grey;">))</span> <span style="color: blue;">AS</span> "data_length"</span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: red;">'foo'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test" <span style="color: grey;">)</span> a<span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">I then had one of those eureka moments whilst looking through the list of string functions in Books Online. What happens if I use the QUOTENAME function? I figured that that might do something interesting based on the fact that it is meant to delimit object names, and indeed it does do something interesting. If a column contains the 0x00 control character, wrapping that value with QUOTENAME returns NULL. So, to find rows that contain the 0x00 character in the data as is, I found the following works reliably:</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [test]<span style="color: grey;">,</span> <span style="color: magenta;">LEN</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "len"<span style="color: grey;">,</span> <span style="color: magenta;">DATALENGTH</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "data_length"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: red;">'foo'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">UNION ALL</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">SELECT</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test" <span style="color: grey;">)</span> a</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">WHERE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [test] <span style="color: grey;">IS</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span> <span style="color: grey;">AND</span></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: magenta;">QUOTENAME</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: grey;">IS</span> <span style="color: grey;">NULL;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">However, this only identifies the culprits. We still haven’t discovered a way to fix the data by removing the control code. We know that we can’t use the standard string functions such as REPLACE etc but what happens if we use XML?</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">So, using XML we can identify the control character by looking for "&#x00;" within the xml fragment. See what’s returned by the following code:</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [test]<span style="color: grey;">,</span> <span style="color: magenta;">LEN</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "len"<span style="color: grey;">,</span> <span style="color: magenta;">DATALENGTH</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "data_length"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: red;">'foo'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">UNION ALL</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">SELECT</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test" <span style="color: grey;">)</span> a</span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FOR</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">XML</span> <span style="color: blue;">AUTO</span><span style="color: grey;">;</span></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="tab-stops: 279.2pt;">Okay, so now that we can identify the control character we should be able to remove it with the standard text functions. Something like the following should do it:</div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> dta<span style="color: grey;">.</span>[xmltest]<span style="color: grey;">.</span>value<span style="color: grey;">(</span><span style="color: red;">'(/a/@test)[1]'</span><span style="color: grey;">,</span> <span style="color: red;">'VARCHAR(20)'</span><span style="color: grey;">)</span> <span style="color: blue;">AS</span> "test"<span style="color: grey;">,</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: magenta;">LEN</span><span style="color: grey;">(</span>dta<span style="color: grey;">.</span>[xmltest]<span style="color: grey;">.</span>value<span style="color: grey;">(</span><span style="color: red;">'(/a/@test)[1]'</span><span style="color: grey;">,</span> <span style="color: red;">'VARCHAR(20)'</span><span style="color: grey;">))</span> <span style="color: blue;">AS</span> "len"<span style="color: grey;">,</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: magenta;">DATALENGTH</span><span style="color: grey;">(</span>dta<span style="color: grey;">.</span>[xmltest]<span style="color: grey;">.</span>value<span style="color: grey;">(</span><span style="color: red;">'(/a/@test)[1]'</span><span style="color: grey;">,</span> <span style="color: red;">'VARCHAR(20)'</span><span style="color: grey;">))</span> <span style="color: blue;">AS</span> "data_length"<span style="color: grey;">,</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> dta<span style="color: grey;">.</span>[xmltest]<span style="color: grey;">.</span>value<span style="color: grey;">(</span><span style="color: red;">'(/a/@len)[1]'</span><span style="color: grey;">,</span> <span style="color: red;">'INT'</span><span style="color: grey;">)</span> <span style="color: blue;">AS</span> "original_len"<span style="color: grey;">,</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> dta<span style="color: grey;">.</span>[xmltest]<span style="color: grey;">.</span>value<span style="color: grey;">(</span><span style="color: red;">'(/a/@data_length)[1]'</span><span style="color: grey;">,</span> <span style="color: red;">'INT'</span><span style="color: grey;">)</span> <span style="color: blue;">AS</span> "original_data_length"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">(</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: magenta;">CAST</span><span style="color: grey;">(</span><span style="color: magenta;">REPLACE</span><span style="color: grey;">(</span>[xmltest]<span style="color: grey;">,</span> <span style="color: red;">'&#x00;'</span><span style="color: grey;">,</span> <span style="color: red;">''</span><span style="color: grey;">)</span> <span style="color: blue;">AS</span> <span style="color: blue;">XML</span><span style="color: grey;">)</span> <span style="color: blue;">AS</span> "xmltest"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">(</span> <span style="color: green;">-- Retrieve sample data with lengths etc.</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">SELECT</span> [test]<span style="color: grey;">,</span> <span style="color: magenta;">LEN</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "len"<span style="color: grey;">,</span> <span style="color: magenta;">DATALENGTH</span><span style="color: grey;">(</span>[test]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "data_length"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">FROM</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: red;">'foo'</span> <span style="color: grey;">+</span> <span style="color: blue;">CHAR</span><span style="color: grey;">(</span>0x00<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test"</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">UNION ALL</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">SELECT</span> <span style="color: red;">'bar'</span> <span style="color: blue;">AS</span> "test" <span style="color: grey;">)</span> a</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: green;">-- Don't specify TYPE as it will fail due to the 0x00 character</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: green;">-- not allowed in XML. We'll convert it later after removing it.</span></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">FOR</span> <span style="color: blue;">XML</span> <span style="color: blue;">AUTO</span> <span style="color: grey;">)</span> xmled<span style="color: grey;">(</span>xmltest<span style="color: grey;">)</span> <span style="color: grey;">)</span> dta<span style="color: grey;">;</span></span></div><div class="MsoNormal" style="tab-stops: 279.2pt;"><br />
</div><span style="font-family: Cambria; font-size: 12pt;">Clearly you could also write a function to iterate through each character within the string and remove the control character, but where’s the fun in that?</span><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com2tag:blogger.com,1999:blog-6334481233407743503.post-30805971883138246472011-07-12T08:44:00.000+01:002011-07-12T08:44:29.650+01:00Implementing Analysis Services Process Add Functionality – Part 3<style>
<!--
/* Font Definitions */
@font-face
{font-family:"Courier New";
panose-1:2 7 3 9 2 2 5 2 4 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 0 0 0 1 0;}
@font-face
{font-family:Cambria;
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:0;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 0 0 0 1 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-parent:"";
margin:0cm;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
a:link, span.MsoHyperlink
{color:blue;
text-decoration:underline;
text-underline:single;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-noshow:yes;
color:purple;
text-decoration:underline;
text-underline:single;}
pre
{mso-style-link:"HTML Preformatted Char";
margin:0cm;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:Courier;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-bidi-font-family:Courier;}
p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
{margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
margin-left:36.0pt;
margin-bottom:.0001pt;
mso-add-space:auto;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
p.MsoListParagraphCxSpFirst, li.MsoListParagraphCxSpFirst, div.MsoListParagraphCxSpFirst
{mso-style-type:export-only;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
margin-left:36.0pt;
margin-bottom:.0001pt;
mso-add-space:auto;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
p.MsoListParagraphCxSpMiddle, li.MsoListParagraphCxSpMiddle, div.MsoListParagraphCxSpMiddle
{mso-style-type:export-only;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
margin-left:36.0pt;
margin-bottom:.0001pt;
mso-add-space:auto;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
p.MsoListParagraphCxSpLast, li.MsoListParagraphCxSpLast, div.MsoListParagraphCxSpLast
{mso-style-type:export-only;
margin-top:0cm;
margin-right:0cm;
margin-bottom:0cm;
margin-left:36.0pt;
margin-bottom:.0001pt;
mso-add-space:auto;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:"Times New Roman";
mso-ascii-font-family:Cambria;
mso-ascii-theme-font:minor-latin;
mso-fareast-font-family:Cambria;
mso-fareast-theme-font:minor-latin;
mso-hansi-font-family:Cambria;
mso-hansi-theme-font:minor-latin;
mso-bidi-font-family:"Times New Roman";
mso-bidi-theme-font:minor-bidi;}
span.HTMLPreformattedChar
{mso-style-name:"HTML Preformatted Char";
mso-style-locked:yes;
mso-style-link:"HTML Preformatted";
mso-ansi-font-size:10.0pt;
mso-bidi-font-size:10.0pt;
font-family:Courier;
mso-ascii-font-family:Courier;
mso-hansi-font-family:Courier;
mso-bidi-font-family:Courier;}
span.moz-txt-citetags
{mso-style-name:moz-txt-citetags;}
@page Section1
{size:612.0pt 792.0pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:36.0pt;
mso-footer-margin:36.0pt;
mso-paper-source:0;}
div.Section1
{page:Section1;}
/* List Definitions */
@list l0
{mso-list-id:777870908;
mso-list-template-ids:857012422;}
@list l0:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level2
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level3
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l0:level4
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level5
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level6
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l0:level7
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level8
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l0:level9
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l1
{mso-list-id:1333097237;
mso-list-template-ids:-480072042;}
@list l1:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level2
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level3
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l1:level4
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level5
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level6
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l1:level7
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level8
{mso-level-number-format:alpha-lower;
mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l1:level9
{mso-level-number-format:roman-lower;
mso-level-tab-stop:none;
mso-level-number-position:right;
text-indent:-9.0pt;}
@list l2
{mso-list-id:1376854260;
mso-list-type:hybrid;
mso-list-template-ids:-480072042 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l2:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l3
{mso-list-id:1456826996;
mso-list-type:hybrid;
mso-list-template-ids:1636854432 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l3:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l4
{mso-list-id:1481536340;
mso-list-type:hybrid;
mso-list-template-ids:-480072042 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l4:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
@list l5
{mso-list-id:1933468725;
mso-list-type:hybrid;
mso-list-template-ids:857012422 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l5:level1
{mso-level-tab-stop:none;
mso-level-number-position:left;
text-indent:-18.0pt;}
ol
{margin-bottom:0cm;}
ul
{margin-bottom:0cm;}
-->
</style> <br />
<div class="MsoNormal">Following on from my previous post, which can be found <a href="http://bi-logger.blogspot.com/2011/05/implementing-analysis-services-process.html"><span style="color: black;">here</span></a>, where I presented one solution for implementing process add functionality, I’ll try to cover off some functional code in order to implement this. Clearly this code can be enhanced and/or converted to your specific needs but hopefully this is a start.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">First let’s setup a dummy set of tables to represent a customer dimension. <i>(Apologies for the formatting, will fix once I can edit my templates again.)</i></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 14pt;">Dummy Tables</span></b> </div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ANSI_NULLS</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">QUOTED_IDENTIFIER</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">NOCOUNT</span> <span style="color: blue;">ON</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/**</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Delete objects.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> [object_id] <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[customer]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [type] <span style="color: grey;">in</span> <span style="color: grey;">(</span>N<span style="color: red;">'U'</span><span style="color: grey;">)</span> <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[customer]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> [object_id] <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[address]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [type] <span style="color: grey;">in</span> <span style="color: grey;">(</span>N<span style="color: red;">'U'</span><span style="color: grey;">)</span> <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[address]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> [object_id] <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[customer_group]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [type] <span style="color: grey;">in</span> <span style="color: grey;">(</span>N<span style="color: red;">'U'</span><span style="color: grey;">)</span> <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[customer_group]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> [object_id] <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[customer_class]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [type] <span style="color: grey;">in</span> <span style="color: grey;">(</span>N<span style="color: red;">'U'</span><span style="color: grey;">)</span> <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[customer_class]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/**</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * CUSTOMER CLASS table.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[customer_class]</span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_class_id] <span style="color: blue;">INT</span> <span style="color: blue;">IDENTITY</span><span style="color: grey;">(</span>1<span style="color: grey;">,</span> 1<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span> <span style="color: blue;">PRIMARY</span> <span style="color: blue;">KEY</span> <span style="color: blue;">CLUSTERED</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_class_name] <span style="color: blue;">VARCHAR</span><span style="color: grey;">(</span>50<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">)</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> [PRIMARY]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[customer_class] <span style="color: blue;">ON</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[customer_class] <span style="color: grey;">(</span>[customer_class_id]<span style="color: grey;">,</span> [customer_class_name]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">1<span style="color: grey;">,</span> <span style="color: red;">'Class1'</span><span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[customer_class] <span style="color: blue;">OFF</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/**</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * CUSTOMER GROUP table.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[customer_group]</span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_group_id] <span style="color: blue;">INT</span> <span style="color: blue;">IDENTITY</span><span style="color: grey;">(</span>1<span style="color: grey;">,</span> 1<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span> <span style="color: blue;">PRIMARY</span> <span style="color: blue;">KEY</span> <span style="color: blue;">CLUSTERED</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_group_name] <span style="color: blue;">VARCHAR</span><span style="color: grey;">(</span>50<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_class_id] <span style="color: blue;">INT</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CONSTRAINT</span> [fk_customer_group_customer_class]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">REFERENCES</span> [dbo]<span style="color: grey;">.</span>[customer_class] <span style="color: grey;">(</span>[customer_class_id]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">)</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> [PRIMARY]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[customer_group] <span style="color: blue;">ON</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[customer_group] <span style="color: grey;">( </span>[customer_group_id]<span style="color: grey;">,</span> [customer_group_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_class_id] <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">1<span style="color: grey;">,</span> <span style="color: red;">'Group1'</span><span style="color: grey;">,</span> 1<span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[customer_group] <span style="color: grey;">( </span>[customer_group_id]<span style="color: grey;">,</span> [customer_group_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_class_id] <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">2<span style="color: grey;">,</span> <span style="color: red;">'Group2'</span><span style="color: grey;">,</span> 1<span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[customer_group] <span style="color: blue;">OFF</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/**</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * ADDRESS table.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[address]</span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [address_id] <span style="color: blue;">INT</span> <span style="color: blue;">IDENTITY</span><span style="color: grey;">(</span>1<span style="color: grey;">,</span> 1<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span> <span style="color: blue;">PRIMARY</span> <span style="color: blue;">KEY</span> <span style="color: blue;">CLUSTERED</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [address_line_1] <span style="color: blue;">VARCHAR</span><span style="color: grey;">(</span>50<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [address_line_2] <span style="color: blue;">VARCHAR</span><span style="color: grey;">(</span>50<span style="color: grey;">)</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">)</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> [PRIMARY]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[address] <span style="color: blue;">ON</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[address] <span style="color: grey;">(</span>[address_id]<span style="color: grey;">,</span> [address_line_1]<span style="color: grey;">,</span> [address_line_2]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(-</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">1<span style="color: grey;">,</span> <span style="color: red;">'Unknown'</span><span style="color: grey;">,</span> <span style="color: grey;">NULL);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[address] <span style="color: grey;">(</span>[address_id]<span style="color: grey;">,</span> [address_line_1]<span style="color: grey;">,</span> [address_line_2]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">1<span style="color: grey;">,</span> <span style="color: red;">'House 1'</span><span style="color: grey;">,</span> <span style="color: red;">'Street 1'</span><span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[address] <span style="color: grey;">(</span>[address_id]<span style="color: grey;">,</span> [address_line_1]<span style="color: grey;">,</span> [address_line_2]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">2<span style="color: grey;">,</span> <span style="color: red;">'House 2'</span><span style="color: grey;">,</span> <span style="color: grey;">NULL);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[address] <span style="color: blue;">OFF</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/**</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * CUSTOMER table.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[customer]</span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_id] <span style="color: blue;">INT</span> <span style="color: blue;">IDENTITY</span><span style="color: grey;">(</span>1<span style="color: grey;">,</span> 1<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span> <span style="color: blue;">PRIMARY</span> <span style="color: blue;">KEY</span> <span style="color: blue;">CLUSTERED</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_name] <span style="color: blue;">VARCHAR</span><span style="color: grey;">(</span>50<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [address_id] <span style="color: blue;">INT</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CONSTRAINT</span> [fk_customer_address]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">REFERENCES</span> [dbo]<span style="color: grey;">.</span>[address]<span style="color: grey;">(</span>[address_id]<span style="color: grey;">),</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_group_id] <span style="color: blue;">INT</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CONSTRAINT</span> [fk_customer_customer_group]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">REFERENCES</span> [dbo]<span style="color: grey;">.</span>[customer_group]<span style="color: grey;">(</span>[customer_group_id]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">)</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> [PRIMARY]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[customer] <span style="color: blue;">ON</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[customer] <span style="color: grey;">(</span>[customer_id]<span style="color: grey;">,</span> [customer_name]<span style="color: grey;">,</span> [address_id]<span style="color: grey;">,</span> [customer_group_id]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">1<span style="color: grey;">,</span> <span style="color: red;">'Customer 1'</span><span style="color: grey;">,</span> 1<span style="color: grey;">,</span> 1<span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[customer] <span style="color: grey;">(</span>[customer_id]<span style="color: grey;">,</span> [customer_name]<span style="color: grey;">,</span> [address_id]<span style="color: grey;">,</span> [customer_group_id]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">2<span style="color: grey;">,</span> <span style="color: red;">'Customer 2'</span><span style="color: grey;">,</span> <span style="color: grey;">-</span>1<span style="color: grey;">,</span> 1<span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[customer] <span style="color: grey;">(</span>[customer_id]<span style="color: grey;">,</span> [customer_name]<span style="color: grey;">,</span> [address_id]<span style="color: grey;">,</span> [customer_group_id]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">3<span style="color: grey;">,</span> <span style="color: red;">'Customer 3'</span><span style="color: grey;">,</span> 2<span style="color: grey;">,</span> 2<span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[customer] <span style="color: blue;">OFF</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">Now, taking each of the steps in turn…</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 14pt;">The Seven-And-A-Half Steps to Process Add</span></b></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;">Step 1</b></div><div class="MsoNormal">First we need to capture the list of dimensions we are interested in and the associated key table for that dimension. Note that by “key table”, I’m referring to the table that contains the attribute to be used as the key in the dimension. The following code will create a table that captures this information.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/**</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * LIST OF DIMENSIONS</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> [object_id] <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[dimension]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [type] <span style="color: grey;">in</span> <span style="color: grey;">(</span>N<span style="color: red;">'U'</span><span style="color: grey;">)</span> <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[dimension]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[dimension]<span style="color: grey;">(</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_id] <span style="color: blue;">INT</span> <span style="color: blue;">IDENTITY</span><span style="color: grey;">(</span>1<span style="color: grey;">,</span>1<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CONSTRAINT</span> [pk_dimension] <span style="color: blue;">PRIMARY</span> <span style="color: blue;">KEY</span> <span style="color: blue;">CLUSTERED</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [olap_dimension_id] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CONSTRAINT</span> [uk_dimension] <span style="color: blue;">UNIQUE</span> <span style="color: blue;">NONCLUSTERED</span> <span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_name] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">)</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> [PRIMARY]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;">Step 1a</b></div><div class="MsoNormal">For performance reasons we will create a table in which we will capture the names of all the tables used by a given. (i.e. The key table and recursively all related tables.)</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/**</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * DIMENSION TABLE RELATIONSHIP</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> [object_id] <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[dimension_table_relationship]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [type] <span style="color: grey;">in</span> <span style="color: grey;">(</span>N<span style="color: red;">'U'</span><span style="color: grey;">)</span> <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[dimension_table_relationship]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[dimension_table_relationship]<span style="color: grey;">(</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_table_relationship_id] <span style="color: blue;">INT</span> <span style="color: blue;">IDENTITY</span><span style="color: grey;">(</span>1<span style="color: grey;">,</span>1<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CONSTRAINT</span> [pk_dimension_table_relationship] <span style="color: blue;">PRIMARY</span> <span style="color: blue;">KEY</span> <span style="color: blue;">CLUSTERED</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_id] <span style="color: blue;">INT</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CONSTRAINT</span> [fk_dimension_table_relationship_dimension_dimension]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">REFERENCES</span> [dbo]<span style="color: grey;">.</span>[dimension]<span style="color: grey;">(</span>[dimension_id]<span style="color: grey;">),</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [olap_dimension_id] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CONSTRAINT</span> [fk_dimension_table_relationship_dimension_olap]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">REFERENCES</span> [dbo]<span style="color: grey;">.</span>[dimension]<span style="color: grey;">(</span>[olap_dimension_id]<span style="color: grey;">),</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_key_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_key_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [attribute_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [attribute_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [first_referencing_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [first_referencing_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">)</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> [PRIMARY]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;">Step 2</b></div><div class="MsoNormal">Next we need to create a table in which we will capture the names of all the tables used by a given dimension on rows. (i.e. The key table and all related tables.) as well as the previous and current identity values for each table.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span><span style="color: blue;">SELECT</span> <span style="color: grey;">*</span> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span> <span style="color: blue;">WHERE</span> <span style="color: magenta;">object_id</span> <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[dimension_process_attribute_key_range]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: blue;">type</span> <span style="color: grey;">in</span> <span style="color: grey;">(</span>N<span style="color: red;">'U'</span><span style="color: grey;">))</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TABLE</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range]<span style="color: grey;">(</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_process_attribute_key_range_key] <span style="color: blue;">INT</span> <span style="color: blue;">IDENTITY</span><span style="color: grey;">(</span>1<span style="color: grey;">,</span>1<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CONSTRAINT</span> [pk_dimension_process_attribute_key_range] <span style="color: blue;">PRIMARY</span> <span style="color: blue;">KEY</span> <span style="color: blue;">CLUSTERED</span> <span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [olap_dimension_id] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_key_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_key_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [attribute_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [attribute_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [min_key_value] <span style="color: blue;">BIGINT</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [max_key_value] <span style="color: blue;">BIGINT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [new_data_flag] <span style="color: blue;">BIT</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [process_flag] <span style="color: blue;">BIT</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [created_date] <span style="color: blue;">DATETIME</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [created_by] <span style="color: blue;">NVARCHAR</span><span style="color: grey;">(</span>255<span style="color: grey;">)</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [updated_date] <span style="color: blue;">DATETIME</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [updated_by] <span style="color: blue;">NVARCHAR</span><span style="color: grey;">(</span>255<span style="color: grey;">)</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">)</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> [PRIMARY]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span><span style="font-family: "Courier New"; font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;">Step 3</b></div><div class="MsoNormal">Populate the tables created in point 1 and 1a above with the dimensions for which you wish to use process add and where the underlying relational schema has been configured as described in the previous posts.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[dimension] <span style="color: blue;">ON</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[dimension] <span style="color: grey;">(</span>[dimension_id]<span style="color: grey;">,</span> [olap_dimension_id]<span style="color: grey;">,</span> [dimension_name] <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">1<span style="color: grey;">,</span> <span style="color: red;">'Customer'</span><span style="color: grey;">,</span> <span style="color: red;">'Customer'</span><span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IDENTITY_INSERT</span> [dbo]<span style="color: grey;">.</span>[dimension] <span style="color: blue;">OFF</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span><span style="font-size: xx-small;"></span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[dimension_table_relationship] </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">( </span>[dimension_id]<span style="color: grey;">,</span> [olap_dimension_id]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_key_table_schema]<span style="color: grey;">,</span> [dimension_key_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [attribute_table_schema]<span style="color: grey;">,</span> [attribute_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [first_referencing_table_schema]<span style="color: grey;">,</span> [first_referencing_table_name] <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">(</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">1<span style="color: grey;">,</span> <span style="color: red;">'Customer'</span><span style="color: grey;">,</span> <span style="color: red;">'dbo'</span><span style="color: grey;">,</span> <span style="color: red;">'customer'</span><span style="color: grey;">,</span> <span style="color: red;">'dbo'</span><span style="color: grey;">,</span> <span style="color: red;">'customer'</span><span style="color: grey;">,</span> <span style="color: red;">'dbo'</span><span style="color: grey;">,</span> <span style="color: red;">'customer'</span><span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span><span style="font-size: xx-small;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;">Step 4</b></div><div class="MsoNormal">Create a stored procedure that accepts a given dimension name and key table name and, using the information schema views etc, identify all related tables by means of foreign key relationships.<table_name> If you did not create foreign keys between all tables, you will need statically capture all tables used by a given dimension and maintain this over time as tables are added or dropped.</table_name></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ANSI_NULLS</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">QUOTED_IDENTIFIER</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span><span style="color: blue;">SELECT</span> <span style="color: grey;">*</span> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span> <span style="color: blue;">WHERE</span> <span style="color: magenta;">object_id</span> <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[usp_reseed_dimension_table_relationship_by_dimension]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: blue;">type</span> <span style="color: grey;">in</span> <span style="color: grey;">(</span>N<span style="color: red;">'P'</span><span style="color: grey;">,</span> N<span style="color: red;">'PC'</span><span style="color: grey;">))</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">PROCEDURE</span> [dbo]<span style="color: grey;">.</span>[usp_reseed_dimension_table_relationship_by_dimension]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">PROCEDURE</span> [dbo]<span style="color: grey;">.</span>[usp_reseed_dimension_table_relationship_by_dimension]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @i_DimensionID <span style="color: blue;">INT</span> <span style="color: grey;">=</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @i_DimensionKeyTableSchema <span style="color: blue;">SYSNAME</span> <span style="color: grey;">=</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @i_DimensionKeyTableName <span style="color: blue;">SYSNAME</span> <span style="color: grey;">=</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">AS</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/**</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Recursively captures all tables related to the table passed into the</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * stored procedure. Essentially it recursively captures the attribute</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * relationships from a given "dimension key" table.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> *</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Input Parameters:</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * ----------------</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * @i_DimensionID The relational identifier for the dimension for</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * which attribute relationships are required.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * @i_DimensionKeyTableSchema The schema in which the dimension key table</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * resides.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * @i_DimensionKeyTableName The name of the table from which all related</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * tables should be derived.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> *</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Ver Author Date Comments</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * --- ------------------- ----------- ------------------------------</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * 1 Philip Stephenson 11-Mar-2011 Original version.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">NOCOUNT</span> <span style="color: blue;">ON</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">DECLARE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Define Error Codes.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @ERR_MISSING_PARAM <span style="color: blue;">INT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @ERR_GENERAL <span style="color: blue;">INT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Define user variables.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @ErrCode <span style="color: blue;">INT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @ErrMsg <span style="color: blue;">NVARCHAR</span><span style="color: grey;">(</span><span style="color: magenta;">MAX</span><span style="color: grey;">),</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @StepNbr <span style="color: blue;">SMALLINT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @FQProcedureName <span style="color: blue;">NVARCHAR</span><span style="color: grey;">(</span>392<span style="color: grey;">),</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @RetVal <span style="color: blue;">INT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @NewLine <span style="color: blue;">NVARCHAR</span><span style="color: grey;">(</span><span style="color: magenta;">MAX</span><span style="color: grey;">),</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @OlapDimensionID <span style="color: blue;">SYSNAME</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @RowsAffected <span style="color: blue;">BIGINT</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 1</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Set variables.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ERR_MISSING_PARAM <span style="color: grey;">=</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ERR_GENERAL <span style="color: grey;">=</span> 128<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrCode <span style="color: grey;">=</span> 0<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @FQProcedureName <span style="color: grey;">=</span> <span style="color: magenta;">QUOTENAME</span><span style="color: grey;">(</span><span style="color: magenta;">DB_NAME</span><span style="color: grey;">())</span> <span style="color: grey;">+</span> <span style="color: red;">'.'</span> <span style="color: grey;">+</span> <span style="color: magenta;">QUOTENAME</span><span style="color: grey;">(</span>OBJECT_SCHEMA_NAME<span style="color: grey;">(</span><span style="color: magenta;">@@PROCID</span><span style="color: grey;">))</span> <span style="color: grey;">+</span> <span style="color: red;">'.'</span> <span style="color: grey;">+</span> <span style="color: magenta;">QUOTENAME</span><span style="color: grey;">(</span><span style="color: magenta;">OBJECT_NAME</span><span style="color: grey;">(</span><span style="color: magenta;">@@PROCID</span><span style="color: grey;">));</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrMsg <span style="color: grey;">=</span> N<span style="color: red;">'ERROR - Stored procedure '</span> <span style="color: grey;">+</span> @FQProcedureName <span style="color: grey;">+</span> N<span style="color: red;">' '</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @NewLine <span style="color: grey;">=</span> <span style="color: blue;">NCHAR</span><span style="color: grey;">(</span>13<span style="color: grey;">)</span> <span style="color: grey;">+</span> <span style="color: blue;">NCHAR</span><span style="color: grey;">(</span>10<span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Capture the OLAP dimension ID for the dimension ID provided.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SELECT</span> @OlapDimensionID <span style="color: grey;">=</span> [olap_dimension_id]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> [dbo]<span style="color: grey;">.</span>[dimension]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> [dimension_id] <span style="color: grey;">=</span> @i_DimensionID<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Set the default rows affected count.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @RowsAffected <span style="color: grey;">=</span> <span style="color: grey;">-</span>1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 2</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Ensure that the dimension ID parameter is not NULL and that a non-null olap</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * dimension ID was found.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IF</span> <span style="color: grey;">(</span>@i_DimensionID <span style="color: grey;">IS</span> <span style="color: grey;">NULL)</span> <span style="color: grey;">OR</span> <span style="color: grey;">(</span>@OlapDimensionID <span style="color: grey;">IS</span> <span style="color: grey;">NULL)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrMsg <span style="color: grey;">=</span> @ErrMsg <span style="color: grey;">+</span> N<span style="color: red;">'identified that either the given @i_DimensionID parameter (i.e. '</span> <span style="color: grey;">+</span> <span style="color: magenta;">ISNULL</span><span style="color: grey;">(</span>@i_DimensionID<span style="color: grey;">,</span> <span style="color: red;">'{null}'</span><span style="color: grey;">)</span> <span style="color: grey;">+</span> N<span style="color: red;">') was NULL or the associated [olap_dimension_id] was NULL. This is not allowed!'</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrCode <span style="color: grey;">=</span> @ERR_MISSING_PARAM<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">GOTO</span> FAIL<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 3</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Ensure that the dimension key table schema parameter is not NULL.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IF</span> <span style="color: grey;">(</span>@i_DimensionKeyTableSchema <span style="color: grey;">IS</span> <span style="color: grey;">NULL)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrMsg <span style="color: grey;">=</span> @ErrMsg <span style="color: grey;">+</span> N<span style="color: red;">'identified that the @i_DimensionKeyTableSchema parameter was NULL. This is not allowed!'</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrCode <span style="color: grey;">=</span> @ERR_MISSING_PARAM<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">GOTO</span> FAIL<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 4</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Ensure that the dimension key table name parameter is not NULL.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IF</span> <span style="color: grey;">(</span>@i_DimensionKeyTableName <span style="color: grey;">IS</span> <span style="color: grey;">NULL)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrMsg <span style="color: grey;">=</span> @ErrMsg <span style="color: grey;">+</span> N<span style="color: red;">'identified that the @i_DimensionKeyTableName parameter was NULL. This is not allowed!'</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrCode <span style="color: grey;">=</span> @ERR_MISSING_PARAM<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">GOTO</span> FAIL<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span> <span style="color: blue;">TRY</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 5</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Create temporary table, else truncate it if it already exists.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IF</span> <span style="color: grey;">(</span><span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span><span style="color: red;">'[tempdb].[dbo].[#foreign_key_tree]'</span><span style="color: grey;">)</span> <span style="color: grey;">IS</span> <span style="color: grey;">NULL)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CREATE</span> <span style="color: blue;">TABLE</span> [#foreign_key_tree]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">(</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [base_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [base_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referencing_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referencing_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ELSE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TRUNCATE</span> <span style="color: blue;">TABLE</span> [#foreign_key_tree]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 6</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Capture the starting point from which to recursively derive all related</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * tables.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INSERT</span> <span style="color: blue;">INTO</span> [#foreign_key_tree] <span style="color: grey;">(</span> [base_table_schema]<span style="color: grey;">,</span> [base_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_schema]<span style="color: grey;">,</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referencing_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referencing_table_name] <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">VALUES</span><span style="color: grey;">(</span>@i_DimensionKeyTableSchema<span style="color: grey;">,</span> @i_DimensionKeyTableName<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @i_DimensionKeyTableSchema<span style="color: grey;">,</span> @i_DimensionKeyTableName<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @i_DimensionKeyTableSchema<span style="color: grey;">,</span> @i_DimensionKeyTableName<span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 7</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Recursively capture all tables related to the set of tables already in</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * the temporary table. The idea here is to obtain the set of all tables</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * that could be used by a dimension in Analysis Services.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHILE</span> <span style="color: grey;">(</span>@RowsAffected <span style="color: grey;"><></span> 0<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INSERT</span> <span style="color: blue;">INTO</span> [#foreign_key_tree] <span style="color: grey;">(</span> [base_table_schema]<span style="color: grey;">,</span> [base_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referencing_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referencing_table_name] <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SELECT</span> inline<span style="color: grey;">.</span>[base_table_schema] <span style="color: blue;">AS</span> "base_table_schema"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> inline<span style="color: grey;">.</span>[base_table_name] <span style="color: blue;">AS</span> "base_table_name"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> inline<span style="color: grey;">.</span>[TABLE_SCHEMA] <span style="color: blue;">AS</span> "referenced_table_schema"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> inline<span style="color: grey;">.</span>[TABLE_NAME] <span style="color: blue;">AS</span> "referenced_table_name"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> inline<span style="color: grey;">.</span>[referenced_table_schema] <span style="color: blue;">AS</span> "referencing_table_schema"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> inline<span style="color: grey;">.</span>[referenced_table_name] <span style="color: blue;">AS</span> "referencing_table_name"</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">(</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SELECT</span> <span style="color: blue;">DISTINCT</span> tmp<span style="color: grey;">.</span>[base_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[base_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> reftab<span style="color: grey;">.</span>[TABLE_SCHEMA]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> reftab<span style="color: grey;">.</span>[TABLE_NAME]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[referenced_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[referenced_table_name]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">INFORMATION_SCHEMA.TABLES</span> tab</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> <span style="color: green;">INFORMATION_SCHEMA.TABLE_CONSTRAINTS</span> con</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> tab<span style="color: grey;">.</span>[TABLE_SCHEMA] <span style="color: grey;">=</span> con<span style="color: grey;">.</span>[TABLE_SCHEMA] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tab<span style="color: grey;">.</span>[TABLE_NAME] <span style="color: grey;">=</span> con<span style="color: grey;">.</span>[TABLE_NAME]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> <span style="color: green;">INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE</span> fctcol</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> tab<span style="color: grey;">.</span>[TABLE_SCHEMA] <span style="color: grey;">=</span> fctcol<span style="color: grey;">.</span>[TABLE_SCHEMA] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tab<span style="color: grey;">.</span>[TABLE_NAME] <span style="color: grey;">=</span> fctcol<span style="color: grey;">.</span>[TABLE_NAME] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> con<span style="color: grey;">.</span>[CONSTRAINT_NAME] <span style="color: grey;">=</span> fctcol<span style="color: grey;">.</span>[CONSTRAINT_NAME]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> <span style="color: green;">INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS</span> rfc</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> con<span style="color: grey;">.</span>[CONSTRAINT_SCHEMA] <span style="color: grey;">=</span> rfc<span style="color: grey;">.</span>[CONSTRAINT_SCHEMA] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> con<span style="color: grey;">.</span>[CONSTRAINT_NAME] <span style="color: grey;">=</span> rfc<span style="color: grey;">.</span>[CONSTRAINT_NAME]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> [CONSTRAINT_SCHEMA]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [CONSTRAINT_NAME]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [TABLE_SCHEMA]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [TABLE_NAME]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [COLUMN_NAME]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">UNION</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Include unique indexes</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SELECT</span> <span style="color: magenta;">SCHEMA_NAME</span><span style="color: grey;">(</span>obj<span style="color: grey;">.</span>[schema_id]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "CONSTRAINT_SCHEMA"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> idx<span style="color: grey;">.</span>[name] <span style="color: blue;">AS</span> "CONSTRAINT_NAME"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: magenta;">SCHEMA_NAME</span><span style="color: grey;">(</span>obj<span style="color: grey;">.</span>[schema_id]<span style="color: grey;">)</span> <span style="color: blue;">AS</span> "TABLE_SCHEMA"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> obj<span style="color: grey;">.</span>[name] <span style="color: blue;">AS</span> "TABLE_NAME"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> col<span style="color: grey;">.</span>[name] <span style="color: blue;">AS</span> "COLUMN_NAME"</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">sys.index_columns</span> icl </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> <span style="color: green;">sys.indexes</span> idx</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> icl<span style="color: grey;">.</span>[index_id] <span style="color: grey;">=</span> idx<span style="color: grey;">.</span>[index_id]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> <span style="color: green;">sys.objects</span> obj</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> idx<span style="color: grey;">.</span>[object_id] <span style="color: grey;">=</span> obj<span style="color: grey;">.</span>[object_id] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> icl<span style="color: grey;">.</span>[object_id] <span style="color: grey;">=</span> obj<span style="color: grey;">.</span>[object_id]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> <span style="color: green;">sys.columns</span> col</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> obj<span style="color: grey;">.</span>[object_id] <span style="color: grey;">=</span> col<span style="color: grey;">.</span>[object_id] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> icl<span style="color: grey;">.</span>[column_id] <span style="color: grey;">=</span> col<span style="color: grey;">.</span>[column_id]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> idx<span style="color: grey;">.</span>[is_unique] <span style="color: grey;">=</span> 1 <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> idx<span style="color: grey;">.</span>[is_primary_key] <span style="color: grey;">=</span> 0 <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> obj<span style="color: grey;">.</span>[is_ms_shipped] <span style="color: grey;">=</span> 0 <span style="color: grey;">)</span> refcol</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> rfc<span style="color: grey;">.</span>[UNIQUE_CONSTRAINT_SCHEMA] <span style="color: grey;">=</span> refcol<span style="color: grey;">.</span>[CONSTRAINT_SCHEMA] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> rfc<span style="color: grey;">.</span>[UNIQUE_CONSTRAINT_NAME] <span style="color: grey;">=</span> refcol<span style="color: grey;">.</span>[CONSTRAINT_NAME]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> <span style="color: green;">INFORMATION_SCHEMA.TABLES</span> reftab</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> refcol<span style="color: grey;">.</span>[TABLE_SCHEMA] <span style="color: grey;">=</span> reftab<span style="color: grey;">.</span>[TABLE_SCHEMA] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> refcol<span style="color: grey;">.</span>[TABLE_NAME] <span style="color: grey;">=</span> reftab<span style="color: grey;">.</span>[TABLE_NAME]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> [#foreign_key_tree] tmp</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> tab<span style="color: grey;">.</span>[TABLE_SCHEMA] <span style="color: grey;">=</span> tmp<span style="color: grey;">.</span>[referenced_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tab<span style="color: grey;">.</span>[TABLE_NAME] <span style="color: grey;">=</span> tmp<span style="color: grey;">.</span>[referenced_table_name]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> tab<span style="color: grey;">.</span>[TABLE_TYPE] <span style="color: grey;">=</span> <span style="color: red;">'BASE TABLE'</span> <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> con<span style="color: grey;">.</span>[CONSTRAINT_TYPE] <span style="color: grey;">=</span> <span style="color: red;">'FOREIGN KEY'</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">)</span> inline <span style="color: grey;">LEFT</span> <span style="color: grey;">OUTER</span> <span style="color: grey;">JOIN</span> [#foreign_key_tree] nxt</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> inline<span style="color: grey;">.</span>[TABLE_SCHEMA] <span style="color: grey;">=</span> nxt<span style="color: grey;">.</span>[referenced_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> inline<span style="color: grey;">.</span>[TABLE_NAME] <span style="color: grey;">=</span> nxt<span style="color: grey;">.</span>[referenced_table_name]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> nxt<span style="color: grey;">.</span>[base_table_name] <span style="color: grey;">IS</span> <span style="color: grey;">NULL;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Capture the number of rows inserted.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @RowsAffected <span style="color: grey;">=</span> <span style="color: magenta;">@@ROWCOUNT</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 9</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Update current information in the static table.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">UPDATE</span> tgt</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> [first_referencing_table_schema] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[referencing_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [first_referencing_table_name] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[referencing_table_name]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> [dbo]<span style="color: grey;">.</span>[dimension_table_relationship] tgt </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> [#foreign_key_tree] src</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> tgt<span style="color: grey;">.</span>[dimension_id] <span style="color: grey;">=</span> @i_DimensionID <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">=</span> @OlapDimensionID <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[dimension_key_table_schema] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[base_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[dimension_key_table_name] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[base_table_name] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[attribute_table_schema] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[referenced_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[attribute_table_name] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[referenced_table_name]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> tgt<span style="color: grey;">.</span>[first_referencing_table_schema] <span style="color: grey;"><></span> src<span style="color: grey;">.</span>[referencing_table_schema] <span style="color: grey;">OR</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[first_referencing_table_name] <span style="color: grey;"><></span> src<span style="color: grey;">.</span>[referencing_table_name]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 9</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Insert new information into the static table.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INSERT</span> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[dimension_table_relationship]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">( </span>[dimension_id]<span style="color: grey;">,</span> [olap_dimension_id]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_key_table_schema]<span style="color: grey;">,</span> [dimension_key_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [attribute_table_schema]<span style="color: grey;">, </span>[attribute_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [first_referencing_table_schema]<span style="color: grey;">,</span> [first_referencing_table_name] <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SELECT</span> @i_DimensionID <span style="color: blue;">AS</span> "dimension_id"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @OlapDimensionID <span style="color: blue;">AS</span> "olap_dimension_id"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [base_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [base_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referencing_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referencing_table_name]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> [#foreign_key_tree] src</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">LEFT</span> <span style="color: grey;">OUTER</span> <span style="color: grey;">JOIN</span> [dbo]<span style="color: grey;">.</span>[dimension_table_relationship] tgt</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> tgt<span style="color: grey;">.</span>[dimension_id] <span style="color: grey;">=</span> @i_DimensionID <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">=</span> @OlapDimensionID <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[dimension_key_table_schema] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[base_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[dimension_key_table_name] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[base_table_name] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[attribute_table_schema] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[referenced_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[attribute_table_name] <span style="color: grey;">=</span> src<span style="color: grey;">.</span>[referenced_table_name]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> tgt<span style="color: grey;">.</span>[dimension_table_relationship_id] <span style="color: grey;">IS</span> <span style="color: grey;">NULL;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 11</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Clean up.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IF</span> <span style="color: grey;">(</span><span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span><span style="color: red;">'[tempdb].[dbo].[#foreign_key_tree]'</span><span style="color: grey;">)</span> <span style="color: grey;">IS</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">TABLE</span> [#foreign_key_tree]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span> <span style="color: blue;">TRY</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span> <span style="color: blue;">CATCH</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrCode <span style="color: grey;">=</span> @ERR_GENERAL<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrMsg <span style="color: grey;">=</span> @ErrMsg <span style="color: grey;">+</span> N<span style="color: red;">'raised error ('</span> <span style="color: grey;">+</span> <span style="color: magenta;">CAST</span><span style="color: grey;">(</span><span style="color: magenta;">ERROR_NUMBER</span><span style="color: grey;">()</span> <span style="color: blue;">AS</span> <span style="color: blue;">NVARCHAR</span><span style="color: grey;">)</span> <span style="color: grey;">+</span> N<span style="color: red;">') in step number ('</span> <span style="color: grey;">+</span> <span style="color: magenta;">CAST</span><span style="color: grey;">(</span>@StepNbr <span style="color: blue;">AS</span> <span style="color: blue;">NVARCHAR</span><span style="color: grey;">)</span> <span style="color: grey;">+</span> N<span style="color: red;">') at line number ('</span> <span style="color: grey;">+</span> <span style="color: magenta;">CAST</span><span style="color: grey;">(</span><span style="color: magenta;">ERROR_LINE</span><span style="color: grey;">()</span> <span style="color: blue;">AS</span> <span style="color: blue;">NVARCHAR</span><span style="color: grey;">)</span> <span style="color: grey;">+</span> N<span style="color: red;">') with message: '</span> <span style="color: grey;">+</span> <span style="color: magenta;">ERROR_MESSAGE</span><span style="color: grey;">();</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">GOTO</span> FAIL<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span> <span style="color: blue;">CATCH</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">GOTO</span> SUCCESS<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">FAIL<span style="color: grey;">:</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Cater for max exception string length.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrMsg <span style="color: grey;">=</span> <span style="color: blue;">CASE</span> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span><span style="color: magenta;">LEN</span><span style="color: grey;">(</span>@ErrMsg<span style="color: grey;">)</span> <span style="color: grey;">></span> 2044<span style="color: grey;">)</span> <span style="color: blue;">THEN</span> N<span style="color: red;">'...'</span> <span style="color: grey;">+</span> <span style="color: grey;">RIGHT(</span>@ErrMsg<span style="color: grey;">,</span> 2041<span style="color: grey;">)</span> <span style="color: blue;">ELSE</span> <span style="color: grey;">RIGHT(</span>@ErrMsg<span style="color: grey;">,</span> 2044<span style="color: grey;">)</span> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">RAISERROR</span><span style="color: grey;">(</span>@ErrMsg<span style="color: grey;">,</span> 16<span style="color: grey;">,</span> 1<span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IF</span> <span style="color: grey;">(</span><span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span><span style="color: red;">'[tempdb].[dbo].[#foreign_key_tree]'</span><span style="color: grey;">)</span> <span style="color: grey;">IS</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">TABLE</span> [#foreign_key_tree]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">RETURN</span> @ErrCode<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">SUCCESS<span style="color: grey;">:</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">RETURN</span> 0<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span><span style="font-family: "Courier New"; font-size: xx-small;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;">Step 5</b></div><div class="MsoNormal">Create a stored procedure that uses the information captured by the SP created in step 4 above, to now populate the table created in point 2 above with an arbitrary minimum value and, using the IDENT_CURRENT(‘’) function, populate the max value with the current identity value for the table<style>
.
</style><span style="font-family: Cambria; font-size: 12.0pt; mso-ansi-language: EN-GB; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: "Times New Roman"; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Cambria; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;">. Note that you must ensure that you retrieve the values for the key table <i style="mso-bidi-font-style: normal;">before</i> any of the related tables. This is what provides protection against the race condition discussed in my previous post</span>.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ANSI_NULLS</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">QUOTED_IDENTIFIER</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span><span style="color: blue;">SELECT</span> <span style="color: grey;">*</span> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span> <span style="color: blue;">WHERE</span> <span style="color: magenta;">object_id</span> <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[usp_derive_new_attribute_keys_for_processing]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: blue;">type</span> <span style="color: grey;">in</span> <span style="color: grey;">(</span>N<span style="color: red;">'P'</span><span style="color: grey;">,</span> N<span style="color: red;">'PC'</span><span style="color: grey;">))</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">PROCEDURE</span> [dbo]<span style="color: grey;">.</span>[usp_derive_new_attribute_keys_for_processing]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">PROCEDURE</span> [dbo]<span style="color: grey;">.</span>[usp_derive_new_attribute_keys_for_processing]</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">AS</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/**</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * For each dimension configured to be processed using "process add", capture the</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * set of new attribute keys for every attribute in the dimension.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> *</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Ver Author Date Comments</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * --- ------------------- ----------- ------------------------------</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * 1 Philip Stephenson 01-Jul-2011 Original version.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">NOCOUNT</span> <span style="color: blue;">ON</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">DECLARE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Define Error Codes.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @ERR_GENERAL <span style="color: blue;">INT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @ERR_LOOKUP_FAIL <span style="color: blue;">INT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Define user variables.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @ErrCode <span style="color: blue;">INT</span> <span style="color: grey;">,</span><span style="color: green;">--= 0,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @ErrMsg <span style="color: blue;">NVARCHAR</span><span style="color: grey;">(</span><span style="color: magenta;">MAX</span><span style="color: grey;">),</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @StepNbr <span style="color: blue;">SMALLINT</span><span style="color: grey;">,</span><span style="color: green;">-- = 0,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @FQProcedureName <span style="color: blue;">NVARCHAR</span><span style="color: grey;">(</span>392<span style="color: grey;">),</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @RetVal <span style="color: blue;">INT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @AbsoluteMinKeyValue <span style="color: blue;">BIGINT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @AbsoluteMaxKeyValue <span style="color: blue;">BIGINT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @MinKeyValue <span style="color: blue;">BIGINT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @RowsAffected <span style="color: blue;">BIGINT</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @ProcessAddFlag <span style="color: blue;">BIT</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 1</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Set variables.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ERR_GENERAL <span style="color: grey;">=</span> 128</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ERR_LOOKUP_FAIL <span style="color: grey;">=</span> 512<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @FQProcedureName <span style="color: grey;">=</span> <span style="color: magenta;">QUOTENAME</span><span style="color: grey;">(</span><span style="color: magenta;">DB_NAME</span><span style="color: grey;">())</span> <span style="color: grey;">+</span> <span style="color: red;">'.'</span> <span style="color: grey;">+</span> <span style="color: magenta;">QUOTENAME</span><span style="color: grey;">(</span>OBJECT_SCHEMA_NAME<span style="color: grey;">(</span><span style="color: magenta;">@@PROCID</span><span style="color: grey;">))</span> <span style="color: grey;">+</span> <span style="color: red;">'.'</span> <span style="color: grey;">+</span> <span style="color: magenta;">QUOTENAME</span><span style="color: grey;">(</span><span style="color: magenta;">OBJECT_NAME</span><span style="color: grey;">(</span><span style="color: magenta;">@@PROCID</span><span style="color: grey;">));</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrMsg <span style="color: grey;">=</span> N<span style="color: red;">'ERROR - Stored procedure '</span> <span style="color: grey;">+</span> @FQProcedureName <span style="color: grey;">+</span> N<span style="color: red;">' '</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @AbsoluteMinKeyValue <span style="color: grey;">=</span> <span style="color: grey;">-</span>32768<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @AbsoluteMaxKeyValue <span style="color: grey;">=</span> <span style="color: grey;">((</span><span style="color: magenta;">POWER</span><span style="color: grey;">(</span><span style="color: magenta;">CAST</span><span style="color: grey;">(</span>2 <span style="color: blue;">AS</span> <span style="color: blue;">BIGINT</span><span style="color: grey;">),</span> 62<span style="color: grey;">)</span> <span style="color: grey;">-</span> 1<span style="color: grey;">)</span> <span style="color: grey;">*</span> 2<span style="color: grey;">)</span> <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @MinKeyValue <span style="color: grey;">=</span> @AbsoluteMinKeyValue<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @RowsAffected <span style="color: grey;">=</span> <span style="color: grey;">-</span>1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span> <span style="color: blue;">TRY</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 2</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Create temporary table, else truncate it if it already exists.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">IF</span> <span style="color: grey;">(</span><span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span><span style="color: red;">'[tempdb].[dbo].[#foreign_key_tree]'</span><span style="color: grey;">)</span> <span style="color: grey;">IS</span> <span style="color: grey;">NULL)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CREATE</span> <span style="color: blue;">TABLE</span> [#foreign_key_tree]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">(</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [olap_dimension_id] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [base_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [base_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NOT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_schema] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_name] <span style="color: blue;">SYSNAME</span> <span style="color: blue;">COLLATE</span> DATABASE_DEFAULT <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [new_min_key_value] <span style="color: blue;">BIGINT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [min_key_value] <span style="color: blue;">BIGINT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [max_key_value] <span style="color: blue;">BIGINT</span> <span style="color: grey;">NULL,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [process_add_flag] <span style="color: blue;">BIT</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ELSE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TRUNCATE</span> <span style="color: blue;">TABLE</span> [#foreign_key_tree]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 3</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Capture all tables (and their current identity column value) for all</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * dimensions set to be processed. The idea here is to obtain the set of</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * all tables that could be used by a dimension in Analysis Services and</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * to capture the available keys.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INSERT</span> <span style="color: blue;">INTO</span> [#foreign_key_tree] <span style="color: grey;">(</span> [olap_dimension_id]<span style="color: grey;">,</span> [base_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [base_table_name]<span style="color: grey;">,</span> [referenced_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [referenced_table_name]<span style="color: grey;">,</span> [new_min_key_value]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [min_key_value]<span style="color: grey;">,</span> [max_key_value]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [process_add_flag] <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SELECT</span> rel<span style="color: grey;">.</span>[olap_dimension_id]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> rel<span style="color: grey;">.</span>[dimension_key_table_schema] <span style="color: blue;">AS</span> "base_table_schema"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> rel<span style="color: grey;">.</span>[dimension_key_table_name] <span style="color: blue;">AS</span> "base_table_name"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> rel<span style="color: grey;">.</span>[attribute_table_schema] <span style="color: blue;">AS</span> "referenced_table_schema"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> rel<span style="color: grey;">.</span>[attribute_table_name] <span style="color: blue;">AS</span> "referenced_table_name"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> atr<span style="color: grey;">.</span>[max_key_value] <span style="color: grey;">+</span> 1 <span style="color: blue;">AS</span> "new_min_key_value"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @AbsoluteMinKeyValue <span style="color: blue;">AS</span> "min_key_value"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: magenta;">IDENT_CURRENT</span><span style="color: grey;">(</span><span style="color: magenta;">QUOTENAME</span><span style="color: grey;">(</span>rel<span style="color: grey;">.</span>[attribute_table_schema]<span style="color: grey;">)</span> <span style="color: grey;">+</span> N<span style="color: red;">'.'</span> <span style="color: grey;">+</span> <span style="color: magenta;">QUOTENAME</span><span style="color: grey;">(</span>rel<span style="color: grey;">.</span>[attribute_table_name]<span style="color: grey;">))</span> <span style="color: blue;">AS</span> "max_key_value"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> 1 <span style="color: blue;">AS</span> "process_add_flag"</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> [dbo]<span style="color: grey;">.</span>[dimension_table_relationship] rel</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">LEFT</span> <span style="color: grey;">OUTER</span> <span style="color: grey;">JOIN</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range] atr</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> rel<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">=</span> atr<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> rel<span style="color: grey;">.</span>[dimension_key_table_schema] <span style="color: grey;">=</span> atr<span style="color: grey;">.</span>[dimension_key_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> rel<span style="color: grey;">.</span>[dimension_key_table_name] <span style="color: grey;">=</span> atr<span style="color: grey;">.</span>[dimension_key_table_name] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> rel<span style="color: grey;">.</span>[attribute_table_schema] <span style="color: grey;">=</span> atr<span style="color: grey;">.</span>[attribute_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> rel<span style="color: grey;">.</span>[attribute_table_name] <span style="color: grey;">=</span> atr<span style="color: grey;">.</span>[attribute_table_name] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> atr<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 4</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Invert current (process flag = 1) and non-current (process flag = 0) rows,</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * updating related attributes appropriately.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">UPDATE</span> tgt</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> [process_flag] <span style="color: grey;">=</span> <span style="color: blue;">CASE</span> <span style="color: blue;">WHEN</span> tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 1 <span style="color: blue;">THEN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> 0</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ELSE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [min_key_value] <span style="color: grey;">=</span> <span style="color: blue;">CASE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Update soon to be non-current record for ProcessAdd.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[process_add_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">)</span> <span style="color: blue;">THEN</span> tmp<span style="color: grey;">.</span>[max_key_value] <span style="color: grey;">+</span> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Update soon to be current record for ProcessAdd when flipped from "non process add".</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[process_add_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 0<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[min_key_value] <span style="color: grey;">=</span> @AbsoluteMinKeyValue<span style="color: grey;">)</span> <span style="color: blue;">THEN</span> non<span style="color: grey;">.</span>[max_key_value] <span style="color: grey;">+</span> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Update soon to be current record for ProcessUpdate/ProcessFull</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[process_add_flag] <span style="color: grey;">=</span> 0<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 0<span style="color: grey;">)</span> <span style="color: blue;">THEN</span> @AbsoluteMinKeyValue</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ELSE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[min_key_value]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [max_key_value] <span style="color: grey;">=</span> tmp<span style="color: grey;">.</span>[max_key_value]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [new_data_flag] <span style="color: grey;">=</span> <span style="color: blue;">CASE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span> <span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[process_add_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">((</span>tmp<span style="color: grey;">.</span>[max_key_value] <span style="color: grey;">+</span> 1<span style="color: grey;">)</span> <span style="color: grey;"><=</span> <span style="color: magenta;">ISNULL</span><span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[max_key_value]<span style="color: grey;">,</span> @AbsoluteMaxKeyValue<span style="color: grey;">))</span> <span style="color: grey;">)</span> <span style="color: blue;">THEN</span> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span> <span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[process_add_flag] <span style="color: grey;">=</span> 0<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 0<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>@AbsoluteMinKeyValue <span style="color: grey;"><=</span> <span style="color: magenta;">ISNULL</span><span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[max_key_value]<span style="color: grey;">,</span> @AbsoluteMaxKeyValue<span style="color: grey;">))</span> <span style="color: grey;">)</span> <span style="color: blue;">THEN</span> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span> <span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[process_add_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 0<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[min_key_value] <span style="color: grey;">=</span> @AbsoluteMinKeyValue<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">((</span>non<span style="color: grey;">.</span>[max_key_value] <span style="color: grey;">+</span> 1<span style="color: grey;">)</span> <span style="color: grey;"><=</span> <span style="color: magenta;">ISNULL</span><span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[max_key_value]<span style="color: grey;">,</span> @AbsoluteMaxKeyValue<span style="color: grey;">))</span> <span style="color: grey;">)</span> <span style="color: blue;">THEN</span> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span> <span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[process_add_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 0<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[min_key_value] <span style="color: grey;"><></span> @AbsoluteMinKeyValue<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[min_key_value] <span style="color: grey;"><=</span> <span style="color: magenta;">ISNULL</span><span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[max_key_value]<span style="color: grey;">,</span> @AbsoluteMaxKeyValue<span style="color: grey;">))</span> <span style="color: grey;">)</span> <span style="color: blue;">THEN</span> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span> <span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[process_add_flag] <span style="color: grey;">=</span> 0<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">)</span> <span style="color: grey;">AND</span> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[min_key_value] <span style="color: grey;"><=</span> <span style="color: magenta;">ISNULL</span><span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[max_key_value]<span style="color: grey;">,</span> @AbsoluteMaxKeyValue<span style="color: grey;">))</span> <span style="color: grey;">)</span> <span style="color: blue;">THEN</span> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ELSE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> 0</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [updated_date] <span style="color: grey;">=</span> <span style="color: magenta;">GETDATE</span><span style="color: grey;">(),</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [updated_by] <span style="color: grey;">=</span> <span style="color: magenta;">ORIGINAL_LOGIN</span><span style="color: grey;">()</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range] tgt</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">LEFT</span> <span style="color: grey;">OUTER</span> <span style="color: grey;">JOIN</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range] non</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> tgt<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">=</span> non<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[dimension_key_table_schema] <span style="color: grey;">=</span> non<span style="color: grey;">.</span>[dimension_key_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[dimension_key_table_name] <span style="color: grey;">=</span> non<span style="color: grey;">.</span>[dimension_key_table_name] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[attribute_table_schema] <span style="color: grey;">=</span> non<span style="color: grey;">.</span>[attribute_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[attribute_table_name] <span style="color: grey;">=</span> non<span style="color: grey;">.</span>[attribute_table_name] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;"><></span> non<span style="color: grey;">.</span>[process_flag]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> [#foreign_key_tree] tmp</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> tgt<span style="color: grey;">.</span>[dimension_key_table_schema] <span style="color: grey;">=</span> tmp<span style="color: grey;">.</span>[base_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[dimension_key_table_name] <span style="color: grey;">=</span> tmp<span style="color: grey;">.</span>[base_table_name] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[attribute_table_schema] <span style="color: grey;">=</span> tmp<span style="color: grey;">.</span>[referenced_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[attribute_table_name] <span style="color: grey;">=</span> tmp<span style="color: grey;">.</span>[referenced_table_name]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> tgt<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">=</span> tmp<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">(</span> <span style="color: grey;">(</span>non<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">IS</span> <span style="color: grey;">NULL)</span> <span style="color: grey;">OR</span> <span style="color: grey;">((</span>non<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">IS</span> <span style="color: grey;">NOT</span> <span style="color: grey;">NULL)</span> <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">(</span>tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;"><></span> non<span style="color: grey;">.</span>[process_flag]<span style="color: grey;">))</span> <span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">/**</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * STEP 5</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Capture information for use by OLAP views during dimension processing.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @StepNbr <span style="color: grey;">=</span> @StepNbr <span style="color: grey;">+</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">INSERT</span> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range] </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">(</span> [olap_dimension_id]<span style="color: grey;">,</span> [dimension_key_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_key_table_name]<span style="color: grey;">,</span> [attribute_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [attribute_table_name]<span style="color: grey;">,</span> [min_key_value]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [max_key_value]<span style="color: grey;">,</span> [new_data_flag]<span style="color: grey;">,</span> [process_flag]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [created_date]<span style="color: grey;">,</span> [created_by] <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SELECT</span> tmp<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: blue;">AS</span> "olap_dimension_id"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[base_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[base_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[referenced_table_schema]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[referenced_table_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- In the case of ProcessAdd, set the Min Key value appropriately else it must be the AbsoluteMinKeyValue.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CASE</span> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[process_add_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">)</span> <span style="color: blue;">THEN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Note that the prev min key value was bumped by the update statement in the prior step so we can just carry this forward.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: magenta;">COALESCE</span><span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[new_min_key_value]<span style="color: grey;">,</span> @AbsoluteMinKeyValue<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ELSE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @AbsoluteMinKeyValue</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span> <span style="color: blue;">AS</span> "min_key_value"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[max_key_value]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">CASE</span> <span style="color: blue;">WHEN</span> <span style="color: magenta;">ISNULL</span><span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[max_key_value]<span style="color: grey;">,</span> @AbsoluteMaxKeyValue<span style="color: grey;">)</span> <span style="color: grey;">>=</span> <span style="color: magenta;">COALESCE</span><span style="color: grey;">(</span>tmp<span style="color: grey;">.</span>[new_min_key_value]<span style="color: grey;">,</span> @AbsoluteMinKeyValue<span style="color: grey;">)</span> <span style="color: blue;">THEN</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ELSE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> 0</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END </span> <span style="color: blue;">AS</span> "new_data_flag" <span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> 1 <span style="color: blue;">AS</span> "process_flag"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: magenta;">GETDATE</span><span style="color: grey;">()</span> <span style="color: blue;">AS</span> "created_date"<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: magenta;">ORIGINAL_LOGIN</span><span style="color: grey;">()</span> <span style="color: blue;">AS</span> "created_by"</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> [#foreign_key_tree] tmp </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">LEFT</span> <span style="color: grey;">OUTER</span> <span style="color: grey;">JOIN</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range] tgt</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> tmp<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">=</span> tgt<span style="color: grey;">.</span>[olap_dimension_id] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[base_table_schema] <span style="color: grey;">=</span> tgt<span style="color: grey;">.</span>[dimension_key_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[base_table_name] <span style="color: grey;">=</span> tgt<span style="color: grey;">.</span>[dimension_key_table_name] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[referenced_table_schema] <span style="color: grey;">=</span> tgt<span style="color: grey;">.</span>[attribute_table_schema] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tmp<span style="color: grey;">.</span>[referenced_table_name] <span style="color: grey;">=</span> tgt<span style="color: grey;">.</span>[attribute_table_name] <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> tgt<span style="color: grey;">.</span>[process_flag] <span style="color: grey;">=</span> 1</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> tgt<span style="color: grey;">.</span>[dimension_process_attribute_key_range_key] <span style="color: grey;">IS</span> <span style="color: grey;">NULL;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span> <span style="color: blue;">TRY</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">BEGIN</span> <span style="color: blue;">CATCH</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrCode <span style="color: grey;">=</span> @ERR_GENERAL<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrMsg <span style="color: grey;">=</span> @ErrMsg <span style="color: grey;">+</span> N<span style="color: red;">'raised error ('</span> <span style="color: grey;">+</span> <span style="color: magenta;">CAST</span><span style="color: grey;">(</span><span style="color: magenta;">ERROR_NUMBER</span><span style="color: grey;">()</span> <span style="color: blue;">AS</span> <span style="color: blue;">NVARCHAR</span><span style="color: grey;">)</span> <span style="color: grey;">+</span> N<span style="color: red;">') in step number ('</span> <span style="color: grey;">+</span> <span style="color: magenta;">CAST</span><span style="color: grey;">(</span>@StepNbr <span style="color: blue;">AS</span> <span style="color: blue;">NVARCHAR</span><span style="color: grey;">)</span> <span style="color: grey;">+</span> N<span style="color: red;">') at line number ('</span> <span style="color: grey;">+</span> <span style="color: magenta;">CAST</span><span style="color: grey;">(</span><span style="color: magenta;">ERROR_LINE</span><span style="color: grey;">()</span> <span style="color: blue;">AS</span> <span style="color: blue;">NVARCHAR</span><span style="color: grey;">)</span> <span style="color: grey;">+</span> N<span style="color: red;">') with message: '</span> <span style="color: grey;">+</span> <span style="color: magenta;">ERROR_MESSAGE</span><span style="color: grey;">();</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">GOTO</span> FAIL<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">END</span> <span style="color: blue;">CATCH</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">GOTO</span> SUCCESS<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">FAIL<span style="color: grey;">:</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Cater for max exception string length.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SET</span> @ErrMsg <span style="color: grey;">=</span> <span style="color: blue;">CASE</span> <span style="color: blue;">WHEN</span> <span style="color: grey;">(</span><span style="color: magenta;">LEN</span><span style="color: grey;">(</span>@ErrMsg<span style="color: grey;">)</span> <span style="color: grey;">></span> 2044<span style="color: grey;">)</span> <span style="color: blue;">THEN</span> N<span style="color: red;">'...'</span> <span style="color: grey;">+</span> <span style="color: grey;">RIGHT(</span>@ErrMsg<span style="color: grey;">,</span> 2041<span style="color: grey;">)</span> <span style="color: blue;">ELSE</span> <span style="color: grey;">RIGHT(</span>@ErrMsg<span style="color: grey;">,</span> 2044<span style="color: grey;">)</span> <span style="color: blue;">END</span><span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">RAISERROR</span><span style="color: grey;">(</span>@ErrMsg<span style="color: grey;">,</span> 16<span style="color: grey;">,</span> 1<span style="color: grey;">);</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">RETURN</span> @ErrCode<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">SUCCESS<span style="color: grey;">:</span> </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">RETURN</span> 0<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;">Step 6</b></div><div class="MsoNormal">Create a user defined table function that accepts a dimension name, schema name and table name and returns the minimum and maximum values from the table created in point 2 above for a given dimension, schema and table.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ANSI_NULLS</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">QUOTED_IDENTIFIER</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span> <span style="color: blue;">SELECT</span> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> <span style="color: green;">sys.objects</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> [object_id] <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[udf_attribute_keys_for_process_add]'</span><span style="color: grey;">)</span> <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [type] <span style="color: grey;">IN</span> <span style="color: grey;">(</span>N<span style="color: red;">'FN'</span><span style="color: grey;">,</span> N<span style="color: red;">'IF'</span><span style="color: grey;">,</span> N<span style="color: red;">'TF'</span><span style="color: grey;">,</span> N<span style="color: red;">'FS'</span><span style="color: grey;">,</span> N<span style="color: red;">'FT'</span><span style="color: grey;">)</span> <span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">FUNCTION</span> [dbo]<span style="color: grey;">.</span>[udf_attribute_keys_for_process_add]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FUNCTION</span> [dbo]<span style="color: grey;">.</span>[udf_attribute_keys_for_process_add] <span style="color: grey;">(</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">@i_OlapDimensionID <span style="color: blue;">SYSNAME</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @i_DimensionTableSchema <span style="color: blue;">SYSNAME</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @i_DimensionTableName <span style="color: blue;">SYSNAME</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @i_AttributeTableSchema <span style="color: blue;">SYSNAME</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> @i_AttributeTableName <span style="color: blue;">SYSNAME </span><span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">RETURNS</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">TABLE</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">AS</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;">/*</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Returns the minimum and maximum keys for a given dimension's attribute</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * table that need to be processed by Analysis Services.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> *</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> *</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Input Parameters:</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * ----------------</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * @i_OlapDimensionID The Analysis Services identifier for the dimension</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * for which attribute key ranges are required.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * @i_DimensionTableSchema The schema for the table that contains the key</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * attribute for the dimension.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * @i_DimensionTableName The name of the table that contains the key</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * attribute for the dimension.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * @i_AttributeTableSchema The schema for the table for the attribute to be</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * processed.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * @i_AttributeTableName The name of the table for the attribute to be</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * processed.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * </span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * Ver Author Date Comments</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * --- ------------------- ----------- ---------------------------------</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> * 1 Philip Stephenson 01-Jul-2011 Original version.</span></div><div class="MsoNormal"><span lang="EN-US" style="color: green; font-family: "Courier New"; font-size: xx-small;"> */</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: green;">-- Return results.</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">RETURN</span> <span style="color: blue;">SELECT</span> [min_key_value]<span style="color: grey;">,</span> [max_key_value]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">WHERE</span> [olap_dimension_id] <span style="color: grey;">=</span> @i_OlapDimensionID <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_key_table_schema] <span style="color: grey;">=</span> @i_DimensionTableSchema <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [dimension_key_table_name] <span style="color: grey;">=</span> @i_DimensionTableName <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [attribute_table_schema] <span style="color: grey;">=</span> @i_AttributeTableSchema <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [attribute_table_name] <span style="color: grey;">=</span> @i_AttributeTableName <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [process_flag] <span style="color: grey;">=</span> 1 <span style="color: grey;">AND</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [new_data_flag] <span style="color: grey;">=</span> 1<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;">Step 7</b></div><div class="MsoNormal">Update the current views used to present data to Analysis Services to join to the function created in point 6 above, limiting the output to be where the surrogate key value is between the minimum and maximum values.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ANSI_NULLS</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">SET</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">QUOTED_IDENTIFIER</span> <span style="color: blue;">ON</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">IF</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">EXISTS</span> <span style="color: grey;">(</span><span style="color: blue;">SELECT</span> <span style="color: grey;">*</span> <span style="color: blue;">FROM</span> <span style="color: green;">sys.views</span> <span style="color: blue;">WHERE</span> [object_id] <span style="color: grey;">=</span> <span style="color: magenta;">OBJECT_ID</span><span style="color: grey;">(</span>N<span style="color: red;">'[dbo].[v_process_add_customer]'</span><span style="color: grey;">))</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">BEGIN</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">DROP</span> <span style="color: blue;">VIEW</span> [dbo]<span style="color: grey;">.</span>[v_process_add_customer]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">END</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;">;</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span></div><div class="MsoNormal"><span style="font-size: xx-small;"><br />
</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">CREATE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">VIEW</span> [dbo]<span style="color: grey;">.</span>[v_process_add_customer]</span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: xx-small;">AS</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">SELECT</span> [customer_id]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_name]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [address_id]<span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> [customer_group_id]</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">FROM</span> [dbo]<span style="color: grey;">.</span>[customer] att </span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;">INNER</span> <span style="color: grey;">JOIN</span> [dbo]<span style="color: grey;">.</span>[udf_attribute_keys_for_process_add]<span style="color: grey;">(</span><span style="color: red;">'Customer'</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: xx-small;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: red;">'dbo'</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;"> </span> <span style="color: red;">'customer'</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;"> </span><span style="color: red;">'dbo'</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: grey;"> </span><span style="color: red;">'customer'</span><span style="color: grey;">)</span> prc</span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;"> <span style="color: blue;">ON</span> att<span style="color: grey;">.</span>[customer_id] <span style="color: grey;">BETWEEN</span> prc<span style="color: grey;">.</span>[min_key_value] <span style="color: grey;">AND</span> prc<span style="color: grey;">.</span>[max_key_value]<span style="color: grey;">;</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: xx-small;">GO</span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 14pt;">Test Drive</span></b></div><div class="MsoNormal">Now that we have everything setup, let’s give it a whirl. First of all we need to identify all of the relationships for a given dimension, customer in this case, starting from the key table.</div><div align="right" class="MsoNormal" style="text-align: right;"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">EXECUTE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [dbo]<span style="color: grey;">.</span>[usp_reseed_dimension_table_relationship_by_dimension]</span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> @i_DimensionID <span style="color: grey;">=</span> 1<span style="color: grey;">,</span></span></div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> @i_DimensionKeyTableSchema <span style="color: grey;">=</span> <span style="color: red;">'dbo'</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> @i_DimensionKeyTableName <span style="color: grey;">=</span> <span style="color: red;">'customer'</span><span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">We can see what this did be executing the following:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">*</span> <span style="color: blue;">FROM</span> [dbo]<span style="color: grey;">.</span>[dimension_table_relationship]<span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">Next we need to identify the minimum and maximum surrogate key values in each of the tables, which we do as follows:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">EXECUTE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [dbo]<span style="color: grey;">.</span>[usp_derive_new_attribute_keys_for_processing]<span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">We can see what this did by executing the following:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">*</span> <span style="color: blue;">FROM</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range]<span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">All we need to do now is select from the view to see all <i style="mso-bidi-font-style: normal;">new</i> entries:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [dbo]<span style="color: grey;">.</span>[v_process_add_customer]<span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">To see how this works, we can select from the function we created earlier as follows:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [dbo]<span style="color: grey;">.</span>[udf_attribute_keys_for_process_add]<span style="color: grey;">(</span><span style="color: red;">'Customer'</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: 8pt;"> </span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: red;">'dbo'</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: red;">'customer'</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: red;">'dbo'</span><span style="color: grey;">,</span></span></div><div class="MsoNormal"><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: red;">'customer'</span><span style="color: grey;">);</span></span><span lang="EN-US" style="font-size: 8pt;"> </span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">To actually test the concept of “process add”, let’s now add a new member:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">INSERT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: blue;">INTO</span> [dbo]<span style="color: grey;">.</span>[customer] <span style="color: grey;">(</span>[customer_name]<span style="color: grey;">,</span> [address_id]<span style="color: grey;">,</span> [customer_group_id]<span style="color: grey;">)</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">VALUES</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: 8pt;">(</span><span lang="EN-US" style="color: red; font-family: "Courier New"; font-size: 8pt;">'Customer 4'</span><span lang="EN-US" style="color: grey; font-family: "Courier New"; font-size: 8pt;">,</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> 2<span style="color: grey;">,</span> 2<span style="color: grey;">);</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">In order to capture the metadata around new key values etc. we need to execute:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">EXECUTE</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [dbo]<span style="color: grey;">.</span>[usp_derive_new_attribute_keys_for_processing]<span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">Which, once again, has captured the metadata as follows:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">*</span> <span style="color: blue;">FROM</span> [dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range]<span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">To see what Analysis Services would see, run the following:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal" style="mso-layout-grid-align: none; mso-pagination: none; text-autospace: none;"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">SELECT</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> <span style="color: grey;">*</span></span></div><div class="MsoNormal"><span lang="EN-US" style="color: blue; font-family: "Courier New"; font-size: 8pt;">FROM</span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;"> [dbo]<span style="color: grey;">.</span>[v_process_add_customer]<span style="color: grey;">;</span></span><span style="font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b style="mso-bidi-font-weight: normal;"><span style="font-size: 14pt;">Conclusion</span></b></div><div class="MsoNormal">Now I will admit that I haven’t fully test driven all of this myself to see if it all works in all situations etc. so please let me know if anything is broken and I’ll aim to fix it. Either way I hope the concept is clear, such that you can make any modifications as required.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">Hopefully you will have noted that in the stored procedure that determines the min and max key values, that it can be easily updated to accommodate ProcessUpdate and ProcessAdd situations by not hard-coding the value for the “process_add_flag” but I’ll leave that as an exercise for the reader.</div><div class="MsoNormal"><br />
</div><span style="font-family: Cambria; font-size: 12pt;">From the above code and sample, the thing to note is that immediately before processing dimensions the </span><span lang="EN-US" style="font-family: "Courier New"; font-size: 8pt;">[dbo]<span style="color: grey;">.</span>[dimension_process_attribute_key_range]</span><span style="font-family: Cambria; font-size: 12pt;"> stored procedure must be called in order to “snapshot” all surrogate key values. Clearly you need to be careful not to get out of sync else things will not work. If that happens you will need to revert back to a “ProcessUpdate” and then continue as per normal.</span><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com2tag:blogger.com,1999:blog-6334481233407743503.post-44010745334607391582011-05-19T08:15:00.002+01:002011-07-25T09:05:33.437+01:00Implementing Analysis Services Process Add Functionality – Part 2<style>
@font-face {
font-family: "Cambria";
}p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; font-size: 12pt; font-family: "Times New Roman"; }div.Section1 { page: Section1; }
</style> <br />
<div class="MsoNormal">In a previous <a href="http://bi-logger.blogspot.com/2011/04/implementing-analysis-services-process.html">here</a> I briefly mentioned some of the benefits and issues surrounding the implementation of incremental processing of Analysis Services dimensions. In this post I’ll go into a bit more detail with regards configuring the SQL Server schema to support incremental processing of Analysis Services dimensions.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">I should point out upfront that I am specifically referring to SQL Server as the relational database here but it could be any database really. The thing is, I’m going to use some SQL Server features as a shortcut both for performance reasons and ease of understanding. I know Oracle has similar functionality but I cannot document each and every RDBMS so I have just chosen SQL Server as the basis for this post.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">So straight off, we have a choice to make. Should we use an out-of-line DSV when incrementally processing or not? Depending on what is chosen here influences how you go about implementing incremental dimension processing, though in the solution presented here only the final steps will need to change. To get around the issue of having to configure Kerberos and submitting a potentially large DSV every time we wish to process, I have chosen not to go the out-of-line DSV route. Although there is nothing that I could see in SQL Profiler, I would presume that there is some form of overhead to Analysis Services evaluating an out-of-line DSV, no matter how trivial.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">It’s also worth mentioning that a nice side-effect of my solution is that we also overcome the race-condition with regards attribute processing when processing dimensions whilst the relational database is loading dimensional data. For example, in the case where you load a new customer linked to a new customer group and Analysis Services has already processed the customer group attribute but not the customer attribute, dimension processing will fail. The reason being that before the new member was added, Analysis Services will already have captured the set of customer group attributes as it was before the new member arrived in the table. This means that processing of the customer attribute will fail when Analysis Services tries to link the customer to the customer group, as the related member will not exist in the processed set of members for the customer group attribute. This can be extremely annoying and there is no out-of-the-box way to force a consistent snapshot of all attributes for a dimension during processing.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><b>One Solution:</b></div><div class="MsoNormal">So, looking at snapshots, it seems that we need to roll our own. Clearly one idea is to effectively snapshot all the rows we wish to load for the dimension across every attribute. We can then present only those rows for loading by Analysis Services at process time. Using this method we can ensure that we prevent the race-condition described earlier during a ProcessUpdate operation too. The trick is how to snapshot the rows quickly and cheaply. (i.e. We don’t want to have to copy an entire table or perform a join across the current dimension table and a previous snapshot if we can avoid it.)</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">So, in my proposed solution, we first of all need to ensure that every attribute that is to be loaded into the dimension is recorded in its own table. That is, the relational schema for the dimension needs to be snow flaked. I know Kimball die-hard fans will be screaming around about now but I haven’t said that you can’t also have a star-schema table. For large Analysis Services dimensions this is usually what I do. I ensure that I generate integer surrogate keys for every attribute using snow-flaked tables with identity columns and configure the Analysis Services DSV using those tables such that only a table scan of a small table is required for every attribute. However, I <i>also</i> ensure that the “key” table (or bottom level) of the dimension is a star-schema table for relational reporting and as such also contains the attributes from related tables.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">For example, given a customer dimension with customer as the bottom level and being related to group and organisation, I would create an organisation table and a customer group table to capture the discrete entities and generate a surrogate key for each. The customer table however, will be a star schema table, generating a surrogate key for each customer but also containing the attributes of the related groups and organisations.)</div><div class="MsoNormal"><br />
</div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-QtMnHcClKq4/TdTCMPGScGI/AAAAAAAAACg/0tbxTQ_z8tY/s1600/CustomerRelationship.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="183" src="http://4.bp.blogspot.com/-QtMnHcClKq4/TdTCMPGScGI/AAAAAAAAACg/0tbxTQ_z8tY/s400/CustomerRelationship.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Customer Relationships</td></tr>
</tbody></table><div class="MsoNormal"><br />
</div><div class="MsoNormal">The main “trick” here, is to ensure that <i>every</i> snow-flaked table for each attribute uses an identity column for its surrogate key. You should also endeavour to choose an integer that best matches the expected maximum number of entries, be it a smallint (2 byte signed integer), int (4 byte signed integer) or bigint (8 byte signed integer). Analysis Services is no longer partial to the tinyint data type so best steer clear of that though.</div><div class="MsoNormal"><style>
@font-face {
font-family: "Cambria";
}p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; font-size: 12pt; font-family: "Times New Roman"; }p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph { margin: 0cm 0cm 0.0001pt 36pt; font-size: 12pt; font-family: "Times New Roman"; }p.MsoListParagraphCxSpFirst, li.MsoListParagraphCxSpFirst, div.MsoListParagraphCxSpFirst { margin: 0cm 0cm 0.0001pt 36pt; font-size: 12pt; font-family: "Times New Roman"; }p.MsoListParagraphCxSpMiddle, li.MsoListParagraphCxSpMiddle, div.MsoListParagraphCxSpMiddle { margin: 0cm 0cm 0.0001pt 36pt; font-size: 12pt; font-family: "Times New Roman"; }p.MsoListParagraphCxSpLast, li.MsoListParagraphCxSpLast, div.MsoListParagraphCxSpLast { margin: 0cm 0cm 0.0001pt 36pt; font-size: 12pt; font-family: "Times New Roman"; }div.Section1 { page: Section1; }ol { margin-bottom: 0cm; }ul { margin-bottom: 0cm; }
</style> </div><div class="MsoNormal"><br />
</div><div class="MsoNormal">This next part isn’t really required, though it will make your life easier in the long run as well as being good practice. Make sure that you have foreign keys setup between all of the snow flaked tables including the star-schema table and the snow-flaked tables. Essentially “document” the relationship between all related attributes by means of foreign keys. The reason for this will become clear later.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">So we now have our dimension configured such that we have integer surrogate keys for every attribute in our dimension and we have both star-schema and snow-flaked tables. We could go ahead and build an Analysis Services dimension from this right now, if we so wished, so we can consider the schema requirements component of the solution to be complete.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">Now that we have our dimension schema I’ll attempt to explain how all of this is used. In part 3 I’ll present some actual code that can be used as a basis for a more substantial implementation but for now I’ll just present a conceptual implementation plan. So, here goes…</div><div class="MsoNormal"><br />
</div><div class="MsoListParagraphCxSpFirst" style="text-indent: -18pt;">1.<span style="font: 7pt "Times New Roman";"> </span>First we need to capture the list of dimensions we are interested in and the associated key table for that dimension. Note that by “key table”, I’m referring to the table that contains the attribute to be used as the key in the dimension. Create a table that captures this information.</div><div class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;">2.<span style="font: 7pt "Times New Roman";"> </span>Next we need to create a table in which we will capture the names of all the tables used by a given dimension on rows (i.e. the key table and all related tables) as well as the previous and current identity values for each table.</div><div class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;">3.<span style="font: 7pt "Times New Roman";"> </span> Populate the table created in point 1 above with the dimensions for which you wish to use process add and where the underlying relational schema has been configured as described in the main text.</div><div class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;">4.<span style="font: 7pt "Times New Roman";"> </span>Create a stored procedure that accepts a given dimension name and key table name and, using the information schema views etc, identify all related tables by means of foreign key relationships. Using this information, populate the table created in point 2 above with an arbitrary minimum value and, using the IDENT_CURRENT(‘<table_name>’) function, populate the max value with the current identity value for the table. Note that you must ensure that you retrieve the values for the key table <i>before</i> any of the related tables. This is what provides protection against the race condition discussed earlier.<br />
If you did not create foreign keys between all tables, you will need statically capture all tables used by a given dimension and maintain this over time as tables are added or dropped.</table_name></div><div class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;">5.<span style="font: 7pt "Times New Roman";"> </span>Create another stored procedure that iterates through each entry in the table created in point 1 above and calls the stored procedure created in point 4 above.</div><div class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;">6.<span style="font: 7pt "Times New Roman";"> </span>Create a user defined table function that accepts a dimension name, schema name and table name and returns the minimum and maximum values from the table created in point 2 above for a given dimension, schema and table.</div><div class="MsoListParagraphCxSpLast" style="text-indent: -18pt;">7.<span style="font: 7pt "Times New Roman";"> </span>Update the current views used to present data to Analysis Services to join to the function created in point 6 above, limiting the output to be where the surrogate key value is between the minimum and maximum values.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">And that’s it really, or the basic nuances of it anyway. Clearly, in point 4 above, there is some work required to only set an arbitrary minimum value the first time the table is populated and thereafter to set the minimum value to the previous maximum value + 1. Where the minimum value is greater than the maximum value you get an indication that now rows have been added to the table since it was processed.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">The final step in the solution of course, is to ensure that the stored procedure created in step 5 is always called before Analysis Services processing commences. In order to perform a full process of the database from SSMS say, you just need to reset the table created in point 2. (eg. Truncate the table and reseed with arbitrary minimum value and current identity value.)</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">And there you go, easy-peasy eh? </div><div class="MsoNormal"><br />
Please find part 3 <a href="http://bi-logger.blogspot.com/2011/07/implementing-analysis-services-process.html">here</a>.</div><div class="MsoNormal"><br />
</div><span style="font-family: Cambria; font-size: 12pt;"></span><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-91052913154677936602011-04-26T23:16:00.002+01:002011-07-25T09:06:23.022+01:00Implementing Analysis Services Process Add Functionality – Part 1<style>
@font-face {
font-family: "Cambria";
}p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; font-size: 12pt; font-family: "Times New Roman"; }a:link, span.MsoHyperlink { color: blue; text-decoration: underline; }a:visited, span.MsoHyperlinkFollowed { color: purple; text-decoration: underline; }pre { margin: 0cm 0cm 0.0001pt; font-size: 10pt; font-family: Courier; }p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph { margin: 0cm 0cm 0.0001pt 36pt; font-size: 12pt; font-family: "Times New Roman"; }p.MsoListParagraphCxSpFirst, li.MsoListParagraphCxSpFirst, div.MsoListParagraphCxSpFirst { margin: 0cm 0cm 0.0001pt 36pt; font-size: 12pt; font-family: "Times New Roman"; }p.MsoListParagraphCxSpMiddle, li.MsoListParagraphCxSpMiddle, div.MsoListParagraphCxSpMiddle { margin: 0cm 0cm 0.0001pt 36pt; font-size: 12pt; font-family: "Times New Roman"; }p.MsoListParagraphCxSpLast, li.MsoListParagraphCxSpLast, div.MsoListParagraphCxSpLast { margin: 0cm 0cm 0.0001pt 36pt; font-size: 12pt; font-family: "Times New Roman"; }span.HTMLPreformattedChar { font-family: Courier; }span.moz-txt-citetags { }div.Section1 { page: Section1; }ol { margin-bottom: 0cm; }ul { margin-bottom: 0cm; }
</style> <br />
<div class="MsoNormal">I think most people who have used Analysis Services know about the ability to incrementally process dimensions using “ProcessAdd” and let’s face it, without the ability to partition dimensions it’s about the only data-reducing optimisation we can perform on dimensions. Sure, we have “by table” processing versus “by attribute” processing, the ability to process attributes in parallel and we can make sure that the relational layer can produce results quickly by either using snow-flaked tables or star-schema tables with indexes etc. However, we are still bound by the amount of time taken to process a given set of rows, where a subset of this information may already have been previously processed.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">To this end we can use incremental dimension processing, i.e. the “ProcessAdd” processing type, which aims to reduce the amount of time taken to process a dimension by only processing new information into the dimension. Clearly changes in hierarchy relationships will still require “ProcessUpdate” or “ProcessFull” as the entire dimension data set will need to be reprocessed in order to identify and reflect any hierarchy changes.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">However there are some fundamental limitations with regards how fast incremental dimension processing can go…</div><div class="MsoListParagraphCxSpFirst" style="text-indent: -18pt;">1.<span style="font: 7pt "Times New Roman";"> </span>Analysis Services performs transactional processing using files on the file system. As such, when starting a transaction its first task is to take a copy of all relevant files. It then starts to perform processing and if processing is successful the newly processed file is used. Based on this we can see that the amount of time taken to process must include at least the amount of time taken to clone all relevant files for the dimension. This can be a non-trivial amount of time on large dimensions.<br />
<i>I guess an enhancement request could be to have Analysis Services clone existing dimension files using a background thread some time after processing. A per dimension configuration would be ideal so that we don’t automatically double disk space and waste resources on small dimensions.</i></div><div class="MsoListParagraphCxSpMiddle" style="text-indent: -18pt;">2.<span style="font: 7pt "Times New Roman";"> </span>In order to use incremental processing on dimensions there appears to be two general forms of implementation. There’s the method that presents only the new rows to Analysis Services during processing (the intended but clearly more arduous method) and the one that presents all rows but changes the error configuration to ignore duplicate errors. I consider the latter option a bit of a hack to be honest and not in the true spirit of incremental processing.</div><div class="MsoListParagraphCxSpLast" style="text-indent: -18pt;">3.<span style="font: 7pt "Times New Roman";"> </span>Even after providing only new rows, Analysis Services needs to ensure that attributes which have ordering defined based on some other attribute are updated to reflect this. Clearly, if ordering has been defined on an attribute with many members, the act of Analysis Services revisiting this set could take a considerable amount of time. </div><div class="MsoNormal"><br />
</div><div class="MsoNormal">From what I’ve seen, the implementation of Analysis Services “ProcessAdd” on dimensions seems somewhat diverse and I’m not aware of anyone documenting a definitive guide to implementing this. Now I certainly don’t intend these posts to be considered a definitive guide but more of a starting point for discussion. To this end, I’ll try to cover off how I see “ProcessAdd” working with regards the relationship between Analysis Services and SQL Server. Don’t get me wrong, others have most definitely blogged about “ProcessAdd” and you can see Greg Galloway’s blog for more information on ProcessAdd performance metrics here: <a href="http://www.artisconsulting.com/blogs/greggalloway/Lists/Posts/Post.aspx?List=83c71d76-a4d8-4197-9257-38d6b857634f&ID=7">http://www.artisconsulting.com/blogs/greggalloway/Lists/Posts/Post.aspx?List=83c71d76-a4d8-4197-9257-38d6b857634f&ID=7</a>. There are others out there like this too. However, these posts tend to focus more on the Analysis Services side, detailing the performance characteristics or the options available such as Out-of-Line DSV’s etc. but not much with regards how to actually go about integrating the relational layer and Analysis Services with incremental processing of dimensions in mind.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">So what are the challenges with integrating Analysis Services with SQL Server?</div><div class="MsoListParagraphCxSpFirst" style="text-indent: -18pt;">1.<span style="font: 7pt "Times New Roman";"> </span>Well, first we need to be able to <i>identify</i> new rows for <i>every</i> attribute. Note that it is insufficient to only identify new “key” rows as each attribute in a dimension is processed separately. So it is well possible, and indeed likely, that any new “key” row will be related to attribute members that have already been processed.</div><div class="MsoListParagraphCxSpLast" style="text-indent: -18pt;">2.<span style="font: 7pt "Times New Roman";"> </span>Once we have the ability to identify new rows for every attribute, how do we only present these new rows to Analysis Services when processing the dimension? </div><div class="MsoNormal"><br />
</div><div class="MsoNormal">Delving into the second point a bit more, we should note that this tends to be a bit of a double-edged sword. We could use an out-of-line DSV to point Analysis Services to some object(s) to present only new rows but the use of an out-of-line DSV requires a connection to be specified too. Now as soon as you specify a connection in an XMLA script you lose the option to allow Analysis Services to process under the service account. So you either have to specify a username/password combination in the XMLA connection configuration, not nice, or use Kerberos and ensure that the account submitting the process request has sufficient privileges both in Analysis Services and in SQL Server. We could also opt to just configure the base objects upon which the dimension is built to only present new rows, allowing the use of the service account during processing. However, if you do this then how do you go about performing a “ProcessUpdate” or “ProcessFull” on an adhoc basis in order to fix a rigid relationship issue or to refresh the hierarchies?</div><div class="MsoNormal"><br />
</div><span style="font: 12pt "Times New Roman";">In my next post (<a href="http://bi-logger.blogspot.com/2011/05/implementing-analysis-services-process.html">here</a>) I’ll try to cover off one solution to this problem. Clearly this is not going to be straightforward or risk-free but hopefully it’s a starting point.</span><br />
<br />
<span style="font: 12pt "Times New Roman";">Please find part 2 <a href="http://bi-logger.blogspot.com/2011/05/implementing-analysis-services-process.html">here</a>. </span><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-72117257850854751972011-04-17T22:34:00.002+01:002011-04-17T22:40:18.849+01:00Configure Reporting Services Database on a SQL Server with non-default port<style>
@font-face {
font-family: "Courier New";
}@font-face {
font-family: "Cambria";
}p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; font-size: 12pt; font-family: "Times New Roman"; }a:link, span.MsoHyperlink { color: blue; text-decoration: underline; }a:visited, span.MsoHyperlinkFollowed { color: purple; text-decoration: underline; }div.Section1 { page: Section1; }
</style> <br />
<div class="MsoNormal">I know this is “so last year” when talking about SQL Server 2008 Reporting Services R1 but I figured I’d talk about it anyway, as it may apply to R2 as well. I haven’t checked so please feel free to leave a comment if you can confirm one way or the other.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">I am also aware that it has been a long time since we discovered this problem and that there is now another more elegant solution to the problem as well. However, I figured I would provide the information on how we solved this same issue for reference.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">So, given a SQL Server instance where the SQL Browser service is disabled (or cannot be reached) and/or SQL Server is using a non-default port number, when attempting to generate the “rights” script whilst configuring Reporting Services you get the following error: </div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span style="font-family: "Courier New"; font-size: 8pt;">System.Net.Sockets.SocketException: No such host is known</span></div><div class="MsoNormal"><span style="font-family: "Courier New"; font-size: 8pt;"> at System.Net.Dns.GetAddrInfo(String name)</span></div><div class="MsoNormal"><span style="font-family: "Courier New"; font-size: 8pt;"> at System.Net.Dns.InternalGetHostByName(String hostName, Boolean includeIPv6)</span></div><div class="MsoNormal"><span style="font-family: "Courier New"; font-size: 8pt;"> at System.Net.Dns.GetHostEntry(String hostNameOrAddress)</span></div><div class="MsoNormal"><span style="font-family: "Courier New"; font-size: 8pt;"> at ReportServicesConfigUI.RSDatabase.IsLocalDbServer(String dbServer)</span></div><div class="MsoNormal"><span style="font-family: "Courier New"; font-size: 8pt;"> at ReportServicesConfigUI.RSDatabase.GrantRSConnectionRights()</span></div><div class="MsoNormal"><span style="font-family: "Courier New"; font-size: 8pt;"> at ReportServicesConfigUI.RSDatabase.CreateNewDatabase()</span><span style="font-family: "Courier New"; font-size: 8pt;"></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">In our case, our UAT environment has the SQL Browser service disabled and we do not use the default port for SQL Server, both for security reasons I suspect. As such we need to specify our SQL Server as “<span style="font-family: "Courier New";">servername.domain,port</span>” which in the general case is fine. Even when creating the actual databases whilst configuring Reporting Services this is fine. However, it would appear that when generating the rights script, this form of connection string is not parsed into the individual server name and port number components. Really bizarre when one part of the product does and the other does not, especially when it is in the same part of the configuration!</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">For further confirmation that the connection string is not parsed, see:</div><div class="MsoNormal"><a href="http://blogs.msdn.com/b/psssql/archive/2009/03/05/socketexception-when-creating-a-new-report-server-database.aspx">http://blogs.msdn.com/b/psssql/archive/2009/03/05/socketexception-when-creating-a-new-report-server-database.aspx</a></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">So after much Googling at the time, we discovered the link above, as well as the following one, which at the time did <i>not</i> include a solution.</div><div class="MsoNormal"><a href="http://blogs.msdn.com/b/sameersurve/archive/2009/06/15/no-such-host-is-known-error-when-configuring-ssrs-2008.aspx">http://blogs.msdn.com/b/sameersurve/archive/2009/06/15/no-such-host-is-known-error-when-configuring-ssrs-2008.aspx</a></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">However, from both of those links we did get enough information in order to determine what we needed to do. Still, I’m not sure why specifying the instance name as well as the port number works (as detailed in the second of those links) over just the port number as that’s a bit weird, but if it works, hey why not use it. <i>Note: I haven’t tested that the instance name and port number does actually work.</i></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">In our case though, we went with the *nix philosophy that you can always do more with the command line tools than you can with the GUI. So we did that. Essentially we used the GUI to configure Reporting Services as far as it would let us, including setting up the databases and allowing it to fail when it tried to configure the “rights scripts”. We then switched to using the command line tools by connecting as the relevant user and then ran the following:</div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><span style="color: black; font-family: "Courier New";">rsconfig -c -m <rs_server_name> <SERVER_NAME> -s <DATABASE_NAME,PORT> <database_name,port> -d reportserver -a Windows</database_name,port></rs_server_name></span></div><div class="MsoNormal"><br />
</div><div class="MsoNormal"><style>
@font-face {
font-family: "Cambria";
}p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; font-size: 12pt; font-family: "Times New Roman"; }div.Section1 { page: Section1; }
</style> <style>
@font-face {
font-family: "Cambria";
}p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; font-size: 12pt; font-family: "Times New Roman"; }div.Section1 { page: Section1; }
</style> <span style="font-family: inherit; font-size: 12pt;">Where <RS_SERVER_NAME> is the server name for the Reporting Services server and <DATABASE_NAME,PORT> is the database name and port number for the SQL Server where we were trying<span> </span>to install the RS databases.</span> <rs_server_name><database_name,port></database_name,port></rs_server_name></div><div class="MsoNormal"><br />
</div><div class="MsoNormal">After running the command, we restarted Reporting Services, went back into the configuration tool to apply the changes there and continued.</div><div class="MsoNormal"><br />
</div><span style="font-family: Cambria; font-size: 12pt;">Clearly this is a bit of a hack, at best, and most likely not supported but in our case it worked and we were up and running after a couple of hours of head scratching and bemoaning the insanity that is Reporting Services.</span><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com1tag:blogger.com,1999:blog-6334481233407743503.post-66394943023238779152011-04-13T21:11:00.000+01:002011-04-13T21:11:59.918+01:00SQL Server - PARSENAME Function<style>
@font-face {
font-family: "Courier New";
}@font-face {
font-family: "Wingdings";
}@font-face {
font-family: "Cambria";
}p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; font-size: 12pt; font-family: "Times New Roman"; }div.Section1 { page: Section1; }
</style> <br />
<div class="MsoNormal">Similar to the QUOTENAME function, another one of those often unknown or overlooked functions is the PARSENAME function. I’ll confess that I’m not entirely sure why it isn’t PARSE_NAME, inline with other functions such as OBJECT_NAME etc. but then I guess the string functions all seem to be concatenated. Anyhoo, let’s ignore all of that for now.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">The beauty of this function is that it allows you to get the individual components of a given 4-part object name presented as a string. So, given <span style="font-family: "Courier New";">'[ServerNameFoo].[DatabaseBar].[SchemaBaz].[ObjectCaz]</span>' we can get the server name component or the database component if we want, maybe to ensure that what we are evaluating exists in the current database for example. We can also get the schema or object names too. I agree that its usefulness is probably limited to esoteric edge cases but it is one of those functions that when you need it, it’s really handy. Especially when you consider trying to implement this functionality yourself and catering for object names with or without square brackets or full stops etc. in their name.</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">To use the function you would write something like:</div><div class="MsoNormal"><span style="color: #000090; font-family: "Courier New";">SELECT</span><span style="font-family: "Courier New";"> <span style="color: #ff66ff;">PARSENAME</span><span style="color: #595959;">(</span><span style="color: red;">'server.database.schema.object'</span>, 2<span style="color: #595959;">);</span></span> </div><div class="MsoNormal"><br />
</div><div class="MsoNormal">This would return the value “schema”. Note that the function doesn’t evaluate whether or not the object exists and doesn’t care. All it does is return the requested component of the string if it is available else NULL. For an example of it in use, have a look at the internals of the <span style="color: #943634; font-family: "Courier New";">sp_spaceused</span> stored procedure. (i.e. Execute <span style="color: #943634; font-family: "Courier New";">sp_helptext </span><span style="color: red; font-family: "Courier New";">'sp_spaceused'</span>.)</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">Also note that there are some articles on the web about using this function in order to split strings for other reasons (eg. IP Addresses) which could be quite a neat solution. (See: <a href="http://www.sqlteam.com/article/using-the-parsename-function-to-split-delimited-data">http://www.sqlteam.com/article/using-the-parsename-function-to-split-delimited-data</a>) However, remember that the function is SQL Server delimiter aware so you need to be careful. Running the function on the string 'foo.[bar]' to return the object name component will return "bar" and not "[bar]".</div><div class="MsoNormal"><br />
</div><div class="MsoNormal">I’ll be honest and say that I’ve never really had a reason to use it but at least I know it’s there if I do. And now you do too. <span style="font-family: Wingdings;"><span>:-)</span></span></div><div class="MsoNormal"><br />
</div><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-53059753538679905132011-02-22T08:31:00.003+00:002011-02-22T08:46:50.579+00:00Analysis Services SlicingI must admit that I never cease to be amazed how you can work with a product for years and still every now and again a little nugget appears that makes you go "Really? Does it <i>really</i> work like that?"<br />
<br />
I had one of those moments recently whilst answering posts on the Analysis Services forum regarding why one query hit only one partition whilst another query hit all the partitions in a measure group. You can read about all of this here: <span class="Apple-style-span" style="font-family: monospace; white-space: pre-wrap;"><a href="http://social.msdn.microsoft.com/Forums/en-US/sqlanalysisservices/thread/b4b4f28a-2ddd-4335-91eb-1732b371eb74">http://social.msdn.microsoft.com/Forums/en-US/sqlanalysisservices/thread/b4b4f28a-2ddd-4335-91eb-1732b371eb74</a></span> where Greg Galloway provides some excellent insight into all of this.<br />
<br />
So, for the most part people know about partitioning in Analysis Services and if not, someone at some point on the forums will mention that "you really should be partitioning your data" etc. This eventually evolves into "oh yes and if you are partitioning you should be setting the slice as well" then queue many links to various articles on slicing etc. and the world is good. Or is it...<br />
<br />
I will admit that I have been one of those citizens posting about the virtues of partitioning and slicing whilst apparently being blissfully (and dangerously) ignorant of the real mechanics of slicing. As far as I can tell, all Microsoft documentation appears to indicate that "ProcessIndexes" is required for aggregations but nowhere does it state that it is required for slicing too. For those of you that are now going "huh, you what?", yessssssss, welcome to my world. Note too, how I am deliberately ignoring the debate regarding whether or not one should manually set the slice instead of relying on auto-slicing, as funnily enough manual slicing is affected too, albeit in a different way.<br />
<br />
Essentially it boils down to this. If you are relying on auto-slicing (either by design or merely for those attributes where it may just happen to only contain a small subset of members) then you need to guarantee that you call "ProcessIndexes" (which is naturally "called" automatically when using "ProcessFull") else auto-slicing will not take place. Yup, that's the fundamental point here. Auto-slicing, or at least the capturing of the min and max data IDs for an attribute, does <i>not</i> happen whilst processing the data into the partition but rather during the processing of indexes. Similarly, if you set the slice on a partition, unless you call "ProcessIndexes" on the partition, the data it contains will not be validated against the slice and thus you can actually process incorrect data into a partition.<br />
<br />
I guess this makes sense from a programming perspective, in that tracking every value whilst processing data into the partition would make the act of processing more expensive. However, when processing indexes this is essentially what this part of processing is doing anyway I would suspect and thus it makes sense to happen here. Note that due to this, slicing is also governed by the IndexBuildThreshold property too. The problem is, other than this link <span class="Apple-style-span" style="color: #333333; font-family: 'Segoe UI', 'Lucida Grande', Verdana, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 16px;"><a href="http://cwebbbi.wordpress.com/2007/11/08/viewing-partition-slice-information/" style="border-bottom-style: none; border-bottom-width: 0px; border-color: initial; border-color: initial; border-left-style: none; border-left-width: 0px; border-right-style: none; border-right-width: 0px; border-style: initial; border-top-style: none; border-top-width: 0px; border-width: initial; color: #0066dd; cursor: pointer; font-family: inherit; font-style: inherit; font-weight: inherit; list-style-type: none; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; outline-color: initial; outline-style: initial; outline-width: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-decoration: none;" target="_blank" title="http://cwebbbi.wordpress.com/2007/11/08/viewing-partition-slice-information/">http://cwebbbi.wordpress.com/2007/11/08/viewing-partition-slice-information</a></span> I have not seen anything else that indicates that you need ProcessIndexes in order to make slicing work completely.<br />
<br />
Note also, that it is often stated in Microsoft performance tuning articles to use ProcessData followed by ProcessIndexes instead of the generic ProcessFull. However, once again it is usually stated that ProcessIndexes is required in order to rebuild aggregations and nowhere does it mention slicing.<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-3661610429156558752010-10-23T10:00:00.001+01:002011-04-27T19:59:21.133+01:00Analysis Services Stored Procedure Best PracticesWhilst answering questions on the Microsoft Analysis Services forum the other day, I came across a question regarding recursive MDX. At first read I thought that an Analysis Services stored procedure might be quicker than recursive MDX, which was an incorrect assumption.<br />
<br />
However, in the discussion Darren Gosbell posted a list of best practices with regards Analysis Services stored procedures that I hadn't seen before, so I figured I would post them here too.<br />
<br />
So, the "best practices" for Analysis Services stored procedures (ASSP) are apparently as follows:<br />
<ul><li>for administrative functions </li>
<li>for static sets, scopes, LHS of assignment and other early-binding things </li>
<li>It is usually OK to use sprocs for query axes </li>
<li>It is usually OK to use sprocs if they don’t need to get cell data (but only look at metadata and members) </li>
<li>inside calculations if there is good NEB that can be defined on the calculation </li>
<li>inside calculations without NEB if sproc is executed over small amount of cells, i.e. inside WHERE clause etc. </li>
</ul><br />
The thread where you can see all of this is here: <a href="http://social.msdn.microsoft.com/Forums/en-US/sqlanalysisservices/thread/9feb1ec0-d5f4-4b8c-9d7c-0195d25d7adc">http://social.msdn.microsoft.com/Forums/en-US/sqlanalysisservices/thread/9feb1ec0-d5f4-4b8c-9d7c-0195d25d7adc</a><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com3tag:blogger.com,1999:blog-6334481233407743503.post-83540850129382594062010-03-04T22:38:00.001+00:002010-03-05T21:18:06.609+00:00SQL Server Dynamic SQLThe use of dynamic SQL is unfortunately one of those necessary evils that plagues developers and DBAs alike.<br />
<br />
Now I know that the use of the word "necessary" will irk some people but after developing BI systems for about 9 years I can assure you that it is. Sure, there are alternatives in a lot of cases, which I have learnt over time, but even so there are occasions where even those don't help. Things like synonyms can help as can linked views but there are still times when dynamic SQL is required. <br />
<br />
Either way, I'm not aiming this post to discuss the merits or demerits of dynamic SQL but rather at giving some airtime to a friendly yet oft unused SQL Server function. First off, hands up me 'cos I very rarely use this function too though I do have a mitigating factor. <br />
<br />
Essentially we all know (or at least we should) that it is good practice to use qualified object names and that one should delimit object names to prevent runtime errors with bad practice object names. Some column and table names I've seen in my time include names with spaces, dollar signs, quotation marks etc. all of which I regard as evil. Let's not also forget the use of reserved words as object names which cannot always be easily avoided.<br />
<br />
So here's my mitigating factor. I have been lucky enough to be the technical lead on most projects where I am a bit of a hardcase on naming conventions so I have control over what objects are called and created. For those that aren't so lucky...<br />
<br />
Enter from stage left: The QUOTENAME function. <br />
<br />
Look it up in BOL, it's great. That little function will place the correct delimiters around a given string to present a well formed object name. This means you don't have to specify square brackets, or whatever delimiter you are using in your dynamic SQL. Obviously though, you will have that function scattered throughout your code unless you declare object names up front using the function, placing the results into parameters and then using those parameters in the string concatenation.<br />
<br />
Whether or not you use the function is by the by I guess, the main thing is to always delimit your object names. Still, it's good to know that the functionality exists if you ever need it. <br />
<br />
- Posted using BlogPress from my iPhone<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com1tag:blogger.com,1999:blog-6334481233407743503.post-2752564362274311092010-02-11T19:38:00.000+00:002010-02-17T08:15:12.619+00:00SSIS Script Task Custom EventsSo, an interesting observation regarding SSIS 2008, or should I say anoyance?<br /><br />At the moment I am part of a team building a data warehouse for an investment bank. Part of this system uses SSIS 2008 (or DTS100 in object model speak) in order to load batches at regular intervals into the warehouse. To ease the monitoring and issue resolution aspects of systems of this nature, we are aiming to use NetAgent to poll the database for new events of interest. Events such as load starts, failures, completion and dimension and partition processing activities all need to trigger an email or something to notify support of the system state.<br /><br />Well, now you might think, like me, that rather than just polling for "PackageStart" events or any of the other "standard" events we could create our own events that could be used to trigger alerts. Yup, now normally I'd say good idea, but alas this time I can't, I don't think... <br /><br />See, now in SSIS you could add a script task and using either C# or, shudder, VB .net, use Dts.Events.FireCustomEvent, or a derivation thereof, depending on the language chosen, to fire an event. Using this approach you could quite nicely craft your own custom events, giving you the ability to uniqely name this event. (I would presume that doing this would provide a unique name in the [source] column in the [sysssislog] table such that the event would now be uniquely identifiable, though documentation around all of this appears sparse, at best). One snag though...<br /><br />Now before I get to the proposed gotcha I guess I should 'fess up... I've only been using SSIS in any guise for about 9 months, so by no means am I a seasoned veteran of the product. Thus quite possibly there is a solution to this gotcha. Just maybe not an intuative one? (Hmmmm speaking of intuative, just don't get me started on case sensitive lookups. I know that they may well be quicker but really? WTF?)<br /><br />Anyhoo, so now that you have your über cool custom event, here's the issue. How do you get the SSIS package to log it? If you edit the logging properties of the package, even specifically selecting the script task, you are only presented with the predefined events for logging. You may be able to "load" the custom events or perhaps edit the package XML but really?<br /><br />So long story short, if someone knows of a way to get an SSIS package to log script task defined custom events, please don't be shy and let me know...<br /><br /><br /><br />- Posted using BlogPress from my iPhone<br /><p class='blogpress_location'>Location:<a href='http://maps.google.com/maps?q=Somewhere%20on%20South%20West%20Trains&z=10'>Somewhere on South West Trains</a></p><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com2tag:blogger.com,1999:blog-6334481233407743503.post-62706792433147293452009-12-17T06:49:00.002+00:002010-03-05T21:19:23.739+00:00SQL Server 2008 SP1 - Cannot drop database because it is currently in use.<div>Recently I came across an issue in SQL Server 2008 SP1 where I was trying to rebuild our DEV databases from script (we have Nant scripts that perform a continuous build process so we know that they work) but during the rebuild the process failed because one of the databases could not be dropped. At first I thought that there must be existing connections to the database but a quick review of the output of "sp_who2" showed no such thing.</div><div><br />
</div><div>Anyway, to shortcut the whole build process I figured I would just use SQL Server Management Studio to manually drop the database and enable the "force close existing connections" option. However, this too failed saying that the database was currently in use, even with the "force close" option set and even more bizarrely once again when I checked the output of "sp_who2", I could not see any connections to the particular database in question. Restarting the SQL Server service didn't help either.</div><div><br />
</div><div>A quick Google search on this error message produced quite a few hits (as you probably know if you found this page that way), a lot of which seemed to indicate that the way to resolve this is to alter the database into single user mode with the immediately rollback option set. Using this produced no joy for me either, which wasn't really surprising considering that there appeared to be no connections in the first place.</div><div><br />
</div><div>In the end, this is how I solved it… You need to get SQL Server to tell you who is blocking the drop command. Not rocket science is it, once you know the answer. ;-) So…</div><div><br />
</div><div><ul><li>First of all, using SQL Server Management Studio, open a query window on to the server and ensure that it is connected to the [master] database.</li>
<li>Next, also using SQL Server Management Studio, right click on the database in question and select the option to drop the database and enable the "close existing connections" option. Click OK.</li>
<li>While this is trying to drop the database, quickly switch to the open query window and run "sp_who2". Look through the result set for the row with a status of "SUSPENDED" and note the value in the "BlkBy" column.</li>
<li>Also in the query window, execute the kill command to kill the spid with the value noted in the point above.</li>
</ul></div><div>And there you go, the database will have been dropped as soon as you killed the SPID.</div><div><br />
</div><div>Wierd eh?</div><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-41052815118488619302009-06-22T12:05:00.003+01:002009-06-22T13:47:44.936+01:00Analysis Services 2005 - Dynamic Default MemberWhilst migrating a database from AS2000 to AS2005 I came across in interesting issue when trying to replicate the same behaviour as the "legacy" version. Firstly, a little background...<br /><br />For the sake of expediency I used the migration wizard to convert most of the AS2000 database over to AS2005. I say most because although the validation checker stated that everything was a-okay, when it came to actually do the migration the wizard whinged about a dimension that was joined to different cubes at different levels within the dimension. In order to progress this, I deleted the dimension and migrated the rest.<br /><br />So, what I was left with was a pretty complete system that, although not overly complex, it wasn't trivial either. The database contained a number of cubes and virtual cubes etc. and they contained a financial line dimension making use of unary operators and custom MDX for specific members. When designing the AS2000 database originally, I specifically avoided calculated cells so there were none of those but it did contain quite a number of calculated members. I must say that I was actually quite impressed with the conversion process once it worked. Certainly the dimensions were migrated quite well, though it made a bit of a mess of migrating the "alternate hierarchy" dimensions. I'm also not a big fan of using linked measure groups etc. so I'll probably back those out into a series of cubes using multiple measure groups etc. but I digress.<br /><br />Whilst going through all the dimensions, to compare the migrated version to the original version, I noticed that the [Currency] dimension had not been migrated to be the same as the original. The dynamic default member definition was missing and needed to be added back. Now, based on AS2000 functionality, the [Currency] dimension had the default member defined using the "Filter" function to filter the members of the dimension based on a "Default Flag" member property such that when the member property was "1" it identified the default member.<br /><br />In AS2005 the preferred method is to use the "Exists" function and it performs a lot better than filtering. Indeed, there is also a known issue in AS2005/8 where use of the "Properties" function when specifying a default member causes heap corruption during processing so it should be avoided. Now the interesting bit, The currency dimension does not have an "all" level so I set the "IsAggregatable" property to false, changed the "Default Flag" attribute's "AttributeHierarchyEnabled" property to true, to change it from a member property to a true attribute and set about deploying and processing the revised dimension. All of that resulted in the following error:<br /><span style="font-family:courier new;">Errors in the metadata manager. The 'Currency' attribute with IsAggregatable=false must not have any relationship to 'Default Flag' attribute that has AttributeHierarchyEnabled=true</span><br /><br />So, rather interestingly, you cannot have attribute 'x' related to attribute 'y' if attribute 'y' has its "IsAggregatable" property set to false. Converting attribute 'x' to a member property serves to allow the dimension to deploy but prevents the use of the attribute in the "Exists" function. One would have to revert back to the use of the "Filter" function which we really need to avoid. Now I'm not sure why this limitation exists, it just does. So how to work around it?<br /><br />Well what I did, was to create a copy of the key attribute and have it related to the key. I changed the attribute relationship to "Rigid", as this should never change, and the cardinality to "one to one" even though this latter property isn't used in AS2005. Then, on the key attribute, I set the "IsAggregatable" property to true, the "AttributeHierarchyVisible" property to false and left the "Default Flag" attribute relationship on the key. The key also had to be renamed so I added an underscore to the end of it.<br /><br />On the copied attribute (i.e. the copy of the key) I renamed it to the name of the key attribute but without the underscore, set the "IsAggregatable" property to false and defined the default member with MDX using the "Exists" function and the "Default Flag" attribute as follows:<br /><span style="font-family:courier new;"><span style="color: rgb(153, 0, 0);">Exists</span>([Currency].[Currency].[Currency].<span style="color: rgb(51, 51, 255);">Members</span>, [Currency].[Default Flag].&[1]).<span style="color: rgb(51, 51, 255);">Item</span>(0)</span><br /><br />This appears to do the trick at the expense of duplicating the attribute, providing a dynamically set default member on an attribute that is not aggregatable.<br /><br />I hope this helps others out there who may face the same issue and hey, if you know why you can't do this straight on the key, please enlighten me!<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com1tag:blogger.com,1999:blog-6334481233407743503.post-63085762831478530362009-05-11T14:36:00.006+01:002009-05-11T15:15:11.920+01:00Installing Subversion from source on CentOS 5.2Okay so this not strictly BI related but hey, most of us BI types have a slight geek inclination don't we, or is that just me?<br /><br />I guess the main reason for blogging about this is that I really didn't expect this to be that hard. I mean, I've been installing Subversion from source since about Fedora Core 3 without issues (other than when the Subversion/Berkley DB integration underwent some changes that shafted access to my repositories) so I kinda expected the same here. Um, wrong! At least this time the issue related to a fresh install rather than suddenly finding that I can no longer access my repositories. Needless to say I now use FSFS rather than Berkley DB as the back-end but still. A friend of mine also works on FSFS (see: <a href="http://www.farside.org.uk/200704/tree_structured_fsfs">http://www.farside.org.uk/200704/tree_structured_fsfs</a>) so he'd been going on at me for a while to switch. Still took that heartache to make me use FSFS though, groan...<br /><br />Anyway, so a while back (meant to blog about this a long time ago but based on how long it has been since my last blog, I can see that it really was a loooong time ago) I set about compiling Subversion from source code. I guess there are many reasons for installing Subversion from source code but that's immaterial here. Needless to say that I started and soon came to realise after running <span style="font-family:courier new;">./configure</span> that there were some missing dependencies when trying to enable SSL. After a little bit of searching and running <span style="font-family:courier new;">rpm -qa</span> etc. to find if certain libraries were installed I found that my install of CentOS was missing the <span style="font-family:courier new;">openssl-devel</span> library. So, a quick install using <span style="font-family:courier new;">yum</span> and I was away, or was I?<br /><br />Okay, so maybe not. After installing the missing library another error occurred during the <span style="font-family:courier new;">./configure</span> script run. This particular issue, however, is documented in the Subversion documentation and requires you to amend the parameters passed to the <span style="font-family:courier new;">configure</span> command in order to have the information passed through to the "<span style="font-family:courier new;">sub-configure</span>" scripts. Rather bizarrely you need to specify the <span style="font-family:courier new;">--with-libs</span> parameter, specifying "<span style="font-family:courier new;">/usr/kerberos</span>" as the value. (i.e. <span style="font-family:courier new;">--with-libs=/usr/kerberos</span>)<br /><br />I guess the part that really got me for a while was the fact that when you run the <span style="font-family:courier new;">configure</span> script, passing in the above mentioned switch, a message is generated on the first line stating: "<span style="font-family:courier new;">configure: WARNING: unrecognized options: --with-libs</span>" however this message can be safely ignored. That little tidbit of information is not specified in the documentaion. So, if you leave the script to run it should actually run to completion, barring any other issues naturally.<br /><br />Long and short of it is that in order to compile Subversion with SSL enabled on CentOS 5.2 (well with the my install base anyway) I had to do the following:<br /><br /><span style="font-family:courier new;"># Unpack the source</span><br /><span style="font-family:courier new;">tar -zxvf subversion-<version><version><version>.tar.gz</version></version></span><br /><span style="font-family:courier new;">cd subversion-</span><span style="font-family:courier new;"><version></span><span style="font-family:courier new;"><version></version></span><br /><span style="font-family:courier new;"># Check that openssl-devel has been installed.</span><br /><span style="font-family:courier new;">yum list openssl-devel</span><br /><span style="font-family:courier new;"># If not, install using the following:</span><br /><span style="font-family:courier new;">yum install openssl-devel</span><br /><span style="font-family:courier new;"># Configure and install subversion with FSFS,<br /># ignoring message "configure: WARNING:<br /># unrecognized options: --with-libs".</span><br /><span style="font-family:courier new;">./configure --without-berkeley-db --with-ssl --with-libs=/usr/kerberos</span><br /><br />And that's all there is to it!<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-14787194105706787672009-03-10T22:38:00.003+00:002009-03-10T23:35:07.309+00:00Analytic Workspace Manager LockingSo, following on from my previous blog about plugins for the AWM, I thought I would provide a little information about something I learned whilst writing my own plugin.<br /><br />Writing a plugin for the AWM and testing it can be cumbersome if you have to constantly start the AWM, login and then navigate to a node in the tree that allows you to activate your plugin. No, arguably a better way is to create your own testbed to simulate the AWM environment. That way you can run your code with less effort and interaction and are also afforded the ability to step through and debug your code if, like me, you need to.<br /><br />In my case I merely created a Java class that effectively created an Oracle database connection and then called my plugin code, passing in the connection and anything else that it required. This was all fine and dandy whilst developing the code and afforded me the luxury of being able to test my code with the minimum of effort. However, when I eventually placed my code into the plugin framework (which to be fair I was doing simultaneously anyway) my code, well, didn't really stop working but rather, well... just seemed to stall.<br /><br />This was masked by the fact that I was using multiple threads and thus parts of the plugin, though still functioning, arguably produced incorrect results. After a little investigation (okay, okay, so more than a little and certainly more than I would have liked) I discovered the reason...<br /><br /><span style="font-weight: bold; font-style: italic;">There appears to be no fine-grained locking in Oracle OLAP, certainly as far as the AWM is concerned.</span><br /><br />So what do I mean by that? Well, just that it is geared towards a single developer updating a given analytic workspace. Multiple updates to different parts of the workspace simultaneously are not supported nor, as far as I can tell, even possible.<br /><br />So what does that mean to us? Well, when the AWM connects to the analytic workspace it attaches it in "read/write" mode. This means that any plugin code can only affect the contents of that analytic workspace by using the connection provided to it when the plugin is invoked. Retrieving/creating a new connection using the data source made available in the Map object presented to the plugin means that any code executed over that connection is in fact in a different session. As such, any code intended to affect the same analytic workspace that was attached by the AWM session created when the analytic workspace was attached will be blocked and will not be able to make changes or even process any objects in that analytic workspace.<br /><br />At first I thought that that was it, game over but there is a "trick". This "trick", albeit a bit of hack and one not to be taken lightly, involves the use of the <span style="font-family: courier new;">DBMS_AW</span> package . More specifically, the use of the <span style="font-family: courier new;">DETACH</span>, <span style="font-family: courier new;">UPDATE</span> and <span style="font-family: courier new;">ATTACH</span> sub-programs allowing us to detach the analytic workspace over the main connection provided by the AWM to the plugin code. We can then "re-attach" it on the new connection in read-only mode (or read/write if you want) and perform whatever actions you would like on the given analytic workspace. The <span style="font-family: courier new;">UPDATE</span> sub-program is required in order to commit any changes that have already been made to the analytic workspace whilst it was in read/write mode prior to detaching it.<br /><br />Note that there is a potential issue here. Detaching the analytic workspace and re-attaching it introduces the risk that in the meantime another session locks the workspace before the plugin secures it for its own use. Also, failure to ensure that the analytic workspace is attached in read/write mode before the plugin exits breaks the environment in which the AWM expects to function. (i.e. The AWM still "thinks" that the workspace is attached in read/write mode and will allow a user to try to make changes even though this may not be the case.)<br /><br />Clearly the functionality that this provides needs to be weighed in conjunction with the expected working environment and the associated risks. If the environment is inherently single-user then no harm is done. However, if there is a multi-user environment where multiple people are likely to request read/write locks on the same analytic workspace, well, then your mileage may vary. Clearly you may be able to use transactions to mitigate some, if not all, of these risks but that remains to be seen.<br /><br />As mentioned previously, oh how nice it would have been to be able to lock a specific dimension or cube etc. which, based on the metadata stored in the database, appears quite possible but just not implemented. This could have opened up opportunities for multi-user development environments to allow teamed development, maintenance and testing etc. What a novel concept, though sorely lacking here...<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com2tag:blogger.com,1999:blog-6334481233407743503.post-91318860268699397422009-02-16T08:23:00.006+00:002009-02-17T08:41:48.521+00:00Analytic Workspace Manager Plugin Best PracticesThe Analytic Workspace Manager (or AWM for short) is the tool to use when wanting to quickly create OLAP structures in the Oracle OLAP engine embedded within the Oracle relational database. Clearly you can use OWB etc. but AWM provides a lightweight easy to use interface for creating quick demos, restructuring content or processing etc. However, what the AWM provides may well not be everything to everyone and thus it is possible to create your own plugins, using Java, to get it to do what <span style="font-style: italic;">you</span> want.<br /><br />The documentation around doing this, I found, is a little light on the ground so to speak. So I have tried to document my findings here to help those that may wish to follow suit. However, before I start I should probably point out that in no way is the following post endorsed by Oracle. These are merely my observations after coding my own plugin for the Analytic Workspace Manager.<br /><br />So here goes...<br />Step one is to find the <a href="http://www.oracle.com/technology/products/bi/olap/11g/awm_plugin/developing_awm_plugins_11g.pdf">Developing_AWM_Plugins_11g.pdf</a> document. When I started coding my plugin for the 11g version of AWM, I could only find the 10g document which is not quite accurate for 11g. The OLAP API has changed somewhat in 11g and this is reflected in the OLAP API interface between the AWM and user plugin code. Looking at the document, I guess the pertinent points are that the 11g version of AWM requires the plugin to be compiled with Java 5 SE. (Or version 1.5 in "old school", just why did Sun confuse matters?) We'll come back to this but suffice to say that you'll need to remember that Java 5 brings with it support for generics.<br /><br />Also in the document, if you have coded for 10g plugins, you may notice that the interface method signatures have changed a little. The <span style="font-style: italic;">AW</span> object passed into the <span style="font-style: italic;">handle</span> method is now an <span style="font-style: italic;">oracle.AWXML.AW </span>object. The <span style="font-style: italic;">params</span> parameter to the <span style="font-style: italic;">handle</span> method provides a map, where the DATAPROVIDER key provides the ability to get a connection to the underlying Oracle database without requiring username/password information.<br /><br />Step two, and arguably the most important step, is the understanding that on startup the Analytic Workspace Manager loads all Java code in the plugin directory and looks for any class files that implement the <span style="font-style: italic;">AWMPlugin</span> interface. This is also documented in the above mentioned document, however, what is not made clear is that there will naturally be a performance impact on the startup time of AWM, the more classes and JAR files that you add to the plugin directory. Also, if you use 3rd-party JAR files you are at the mercy of those maintainers.<br /><br />For example, placing the "jfreechart" JAR files in the plugin directory causes exceptions to be thrown in the AWM command window regarding missing Eclipse files. (I'm guessing that "jfreechart" is coded using Eclipse and some code dependencies are left behind.) Allowing this to happen with a user-defined plugin is pretty inelegant at best but most likely just down-right rude. We should avoid that, and we can.<br /><br />The best practice I have come up with is as follows:<br /><ul><li>The interface between the AWM and your plugin should reside in its own JAR file and only contain the minimum number of class files etc. in order to start the actual plugin. This keeps the startup time for the AWM to the minimum.<br /></li><li>The actual plugin code should be packaged into its own JAR file and placed elsewhere in the file system. (I use a subdirectory of the plugin directory so that it can be found using relative paths from the plugin interface.)</li><li>Associated plugin dependencies should also be placed into a subdirectory (I use the same one as my own code as mentioned above) of the plugin directory.<br /></li></ul>Now, Oracle kindly provide a directory from which plugins can be found and executed but this clearly isn't scalable from a startup point of view if you require the use of large dependencies or lots of plugins. Oracle unfortunately <span style="font-style: italic;">don't</span> provide the equivalent of an "<span style="font-style: italic;">Ext</span>" directory into which dependencies could be placed. So here's the dilemma... Do we customise the Windows batch file (or *nix shell script) to include our dependencies in the classpath, or do we place our dependencies in one of the directories that is already referenced by the Oracle prescribed classpath?<br /><br />My answer... neither! Customising the startup script is prone to failure if Oracle ever decide to update it. It also means deploying the plugin is a pain, in that everyone's installation may be different so deploying the script needs to take that into consideration. Hijacking the Oracle directories is also pretty "rude" and prone to cause issues down the line, not to mention taking into consideration once again the uniqueness of each installation. No, best practice would be to customise a URLClassLoader in order to dynamically load the dependencies at runtime and start the plugin. This unfortunately requires the use of reflection and is a bit more long winded but it will be far more robust and stand you in good stead during further developments.<br /><br />My plugin used both "log4j" and "jfreechart", both of which had to be loaded onto the classpath with "log4j" needing to be instantiated in order to log progress. <span style="font-style: italic;">I may blog more on this in detail in the future, as doing this can be tricky and I couldn't find a definitive guide on this on the web.</span><br /><br />Finally, coming back to generics, note that the <span style="font-style: italic;">AWMPlugin</span> interface needs to be backwards compatible and as such does not make use of generics. This tends to generates compiler warnings. The way I would recommend handling this is to annotate the interface methods with "<span style="font-style: italic;">@SuppressWarnings("unchecked")</span>" to suppress those warnings but only on the methods provided by Oracle. If you need to assign one of the variables found in the interface parameter list to to your own variable, you can use the generic wildcard, such as declaring "Map<?>", indicating the supertype.<br /><br />And that's all there is to it.<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-51273012041420102512009-02-02T11:55:00.005+00:002009-02-16T08:22:43.182+00:00Analysis Services 2005/2008 Heap CorruptionRecently I have been working for a financial institution who are using Analysis Service 2005 for their ad-hoc analysis. This particular client was experiencing issues with one of the Analysis Services servers producing memory mini-dump files during processing and causing service crashes and stalls whilst other servers were performing acceptably well.<br /><br />The analysis of this issue started towards the end of 2007 and the reason for this has only now been diagnosed with the able help of Microsoft support. The particular system setup for this client is quite complex, using Oracle 10gR2 as the back-end relational database using flashback for referential integrity and consistency, the 11g (11.1.0.6.0) 64 bit OLE DB driver for connectivity from AS to Oracle and SSIS for scheduled processing. The AS database also makes extensive use of linked measure groups in order to provide a single cube of data with mixed granularity.<br /><br />In order to diagnose the cause of the heap corruption we had to jump through quite a series of hoops. We initially went down the route of sending the mini-dump files to Microsoft for analysis but these naturally only provided limited and static information. Sending full dump files proved very tricky in the short term as the information that the cubes contain is confidential and cannot be sent off-site. In the end, restarting AS and only processing the dimensions and cubes (i.e. no queries being sent to AS) proved adequate to be able to send the full memory dump files off-site, as it would be extremely hard to put this in-memory information together in any meaningful way.<br /><br />Still, the full dump files are also static and thus proved inconclusive. It could be seen from the dump files that heap corruption was indeed occuring during processing and there always appeared to be an Oracle error in the dump file as well. It seemed logical that the Oracle 11g driver could be the cause, as most clients tend to use the 10.2.0.3.0 Oracle OLE DB driver when connecting to Oracle 10.2.0.3.0 or later. In order to try and eliminate the 11g driver as the cause, we backed out the 11g driver and installed the 10.2.0.3.0 driver. (<span style="font-style: italic;">Note that in true Oracle fashion, this proved to be an exercise in and of itself. There is no Oracle 10.2.0.3.0 64 bit client installation. Noooooooo, that's waaaaay too easy! You have to install 10.2.0.1.0 and then patch it to 10.2.0.3.0. Oh, but wait, there is a patch before you apply the patch in order to get the patch to work etc. yadayadayada.</span>) Anyhoo, I digress...<br /><br />In the end, we found that using the Oracle 10.2.0.3.0 driver did not fix the problem. The next step then, was to divide and conquer so to speak...<br /><br />Part one was to try and create a reduced test case by systematically removing complexity from the AS database. This was achieved by first removing the linked measure groups (I'm not aware of many people using this feature) and then to remove cubes and dimensions until a simple AS database could be created in which the issue could still be reproduced. The idea of this approach was to be able to get a small AS database with a tiny amount of non-confidential data so that Microsoft could perform in-house testing.<br /><br />Part two was to use Time Travel Trace testing (TTT) which effectively allows one to debug the issue by being able to play forward and rewind the process over a given time span. This would allow one to see the changes made to the heap and replay them to identify the point at which the heap was corrupted. Rather amusingly though, there is a slight catch. This system was using AS2005 on Windows Server 2003 as are most installations I would suspect. However, TTT only works on Windows Server 2003 on a 32 bit architecture or Windows Server 2008 on a 64 bit architecture or if virtualised, only on Hyper-V.<br />Right, so a few changes to the test case then. As it happened we used a 32 bit environment and as luck would have it we were actually able to reproduce the issue, though TTT failed to work. Initially it exhibited the same symptoms as seen when used on Vista, where it "watched" the incorrect "thread" for activity. This should have been fixed be setting the processor affinity for AS. It wasn't...<br /><br />As it happens, the TTT testing wasn't required. The reduced test case was effective and we were able to remove all confidential data. Microsoft took this in-house and managed to find the answer. So, are you ready for this? Do you want to know why memory heap corruption was occurring during processing? Well, do you?<br /><br />Rather bizarrely, the reason for the heap corruption was the use of the "<span style="font-family:courier new;">.Properties</span>" function when specifying the default member in a dimension. Yup, the use of a specific function when specifying the default dimension member caused heap corruption during processing, not querying but <span style="font-style: italic;">processing</span>. So how lucky am I that the reduced test case that I created used one of the only two dimensions out of 30 odd using that function when specifying the default member? Now I'm not sure why that function causes the issue and nor are the AS development team. They are still looking into it and from what I understand, were equally surprised. As it happens, the MDX that was being used to specify the default member wasn't particularly efficient in the first place (I must point out that it wasn't my code) and that once the code was changed to use the "<span style="font-family:courier new;">Exists</span>" function, it solved the problem.<br /><br />Clearly your mileage may vary but nonetheless please be aware that the use of the "<span style="font-family:courier new;">.Properties</span>" function when specifying the default dimension member can cause heap corruption during processing. This is true for both AS2005 CU11 (or SP3 CU1) and AS2008 CU2. I'm still not sure why this only occurred on one of the servers when the other servers have the exact same database build but hey, removing the "<span style="font-family:courier new;">.Properties</span>" function solved the issue so clearly that was the problem.<br /><br />You have been warned...<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com4tag:blogger.com,1999:blog-6334481233407743503.post-18653498896524339362008-10-21T18:55:00.004+01:002008-10-21T19:49:26.322+01:00Is Oracle AWM 11.1.0.7.0A Better?So, I'm about to present at a workshop tomorrow on Oracle 11g's Interval Partitioning and on the OLAP option and in preparation for the event I have had to create a demo. A while back I patched our 11.1.0.6.0 relational database to patch 8 but although both patch 10 and 11.1.0.7.0 have since been released, I decided not to risk upsetting things too much by installing those and have thus gone with the status quo. (Note that we have <span style="font-style: italic;">lots</span> of Oracle software on that machine for demos and breaking things at any time is just not on!)<br /><br />Incidentally, I just <span style="font-weight: bold;">have</span> to ask, does anyone actually <span style="font-style: italic;">know</span> what each number in Oracle's version numbers stand for? I searched a while back but to no avail. But I digress...<br /><br />Searching around on 11g versions and patches I came across an article that said that in order to patch the OLAP option you need to install either Patch 'A' or Patch 'B' but in order to patch the relational side of the engine you use the Patches 6, 8, 10 etc. Huh? When I installed patch 8 it had to back out patch 'A' (which is what the person who posted on the forum also found) so does that mean that the OLAP patches are mutually exclusive from the relational patches? That's a question I have yet to answer 'cos maybe you are meant to re-apply Patch 'A' after patch 8 etc. but that's a subject for a later post. (Especially since 11.1.0.7.0 has been released which appears to be for both relational and OLAP with patch #6890831. See the <a href="http://www.oracle.com/technology/products/bi/olap/collateral/olap_certification.html">OLAP Certification</a> page.)<br /><br />Anyhoo, my big grumble with the Oracle Analytic Workspace Manager is that it seems to contain more bugs than an anthill. Seriously, does anyone actually <span style="font-style: italic;">test</span> this thing? Within 2 minutes of using it I can get it to break. Lol, now I appreciate that my ineptitude is clearly a culprit in this issue in that if I did everything correctly it wouldn't break. However, exceptions are just that, exceptions and they need to be catered for.<br /><br />Documentation seems to indicate that the preferred method of creating analytic workspaces etc. is to use Oracle Warehouse Builder and that the Analytic Workspace Manager is for "end users" who don't have access to the ETL/ELT process. It can also be used where OWB is not the ETL/ELT tool being employed.<br /><br />Really? Whenever an exception is thrown I seem to get some Java exception ramblings about not being able to create a cursor or transaction or something equally inane. I'm sorry. It's coding like this that gives Java a bad name! Issues such as not being able to switch between a "star-schema" dimension and "snowflake" dimension after it has been built. Sure, you click on the drop down box and select it but sometimes the relevant member is selected but you don't get the correct representation in the mapping pane (i.e. visible/invisible "parent" member) or it just won't select.<br /><br />Other irritations include:<br /><ul><li>After defining a cube you can click on the cube name in the schema tree and even though the dimensions are greyed out, you can double click an available dimension and it will appear to be added to the cube's dimension list. It hasn't really, click off the cube and come back and the model is back as expected.</li><li>Try creating a dimension over the "Sales Territory" dimension as available in the Microsoft AdventureWorks database and it will build. You can even browse it. However, join that dimension to a cube built off of the Internet Sales fact table and whoa... nasty exception.</li><li>Why does the above nasty exception terminate my connection and cause random stuff to happen?</li><li>How come building cubes off a database using the WE8MSWIN1252 characterset causes ORA-12704 characterset mismatch errors seemingly at random? Sometimes when I merely process something but always when trying to create cube organized materialized views. Sure I should be using UTF8 but the default for the "warehouse" database created by dbca is to use WE8MSWIN1252. What gives with that?<br /></li><li>...</li></ul>It is probably worth pointing out that the version of AWM that I was using was 11.1.0.7.0A and apparently that is expected to work against an 11.1.0.6.0 database. Maybe I should log these as bugs for Oracle to fix, I get that. My complaint though, is how did some of the issues I experience (maybe not listed here) even get through the door?<br /><br />Does anyone on the development team actually use the product in a way that is not based on contrived samples? We all know that clinical test cases will work but what about the real world?<br /><br />After all that, is the new version of AWM better? Yes. The fact that you can now create dimension levels at the time when you create a dimension (which I always thought was odd that you couldn't) is accepted with open arms. Despite all the ramblings above, it does seem a little more stable though that really isn't saying much. The default way of mapping columns to OLAP structures has changed from the graphical mapping view to the table mapping view which I think is for the better.<br /><br />Bottom line, if you haven't switched yet, switch now. It's better for sure but don't expect an "Analysis Services development environment (i.e. BIDS)" type experience or you'll be sorely disappointed!<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com3tag:blogger.com,1999:blog-6334481233407743503.post-91491770025427709112008-10-13T22:25:00.004+01:002008-10-13T23:34:12.964+01:00Hyperion EPM on Windows Server 2008For an upcoming workshop we are running, covering the Oracle BI offering, I had to upgrade the relevant Oracle software to later versions. This included upgrading Oracle 11g to 11.1.0.6 patch 8 (11.1.0.7 not available for Windows at the time), upgrading Hyperion 9.3 to EPM Fusion edition and upgrading OBIEE plus. <span style="font-style: italic;">As an aside, the upgrade to Oracle 11g wasn't exactly seamless due to some Hyperion 9.3 service mainting a reference to the Oracle client dlls despite the fact that I had "uninstalled" Hyperion prior to the 11g patching. However, the use of ProcessExplorer soon highlighted the offending process and I was able to complete the patching in due course.</span><br /><br />Installing Oracle/Hyperion Enterprise Performance Management Fusion Edition on Windows Server 2008 however, seemed to pose some interesting challenges. I'm not sure if this is as a result of running the Windows Server 2008 as the OS, the fact that the OS is actually running in Hyper-V, the fact that I uninstalled Hyperion 9.3 first and then installed EPM or something else but the net result was that it took me almost 2 days to solve an issue with OpenLDAP.<br /><br />Attempts to start the Hyperion OpenLDAP service were unsuccessful and thus none of the other services were able to register with Shared Services. (i.e. The Shared Services service requires the OpenLDAP service to be up and running before it can start.) The failure to start the service provided little in the way of messages that would help debug the issue but consulting the EPM installation documentation (and Google) showed that you can start the OpenLDAP service from the command line using the "-d" switch in order to get some logging to sdtout. A switch of "-d 1" provides copious volumes of logging information and "-d -1" even more so. ;-)<br /><br />Although this did produce some logging, in the end it was of little benefit as I got mixed results. Those mixed results were a combination of getting the OpenLDAP service to start from the command line (after tweaking some command line arguments to the "slapd" exe by adding a reference to the config file) to the service no longer starting thereafter. When the service would no longer start, I got the dreaded "slapd starting" message in the console whereupon the service would do little else. According to Google searches, the solution appeared to be to "download a later version of OpenLDAP" which clearly wasn't an option as I needed to use the Oracle implementation of OpenLDAP.<br /><br />At this point I figured that a re-install was probably on the cards so I uninstalled EPM, deleted the directory into which it had been installed and then reinstalled the EPM software. Guess what... The OpenLDAP service started! oooOOOOOooooo. So a quick config of the services and... D'OH! still no joy! None of the services were able to register with Shared Services. Grumble, grumble, grumble. What now?<br /><br />Even more debugging and looking at the Shared Service log files showed messages such as "Native Directory is not reachable. Attempting to re-connect" with references to the server's hostname and a port number of 28089. This seemed to indicate that services were attempting to connect to OpenLDAP on port 28089 and couldn't get through. Further investigations showed that OpenLDAP does not use that port number by default, so it needs to be set at startup.<br /><br />Now that's where the fun and games started. Rather than go through all the possible places where they can be set depending on which article you read (which I unfortunately tried), I'll just tell you the right place. It would appear (and I'm guessing here) that the installation of EPM on Windows Server 2008 does not install some much needed registry entries. A colleague of mine installed EPM on Windows XP and it all went well. A quick check of the registry on that machine confirmed that this is what was missing. So...<br /><br />What you need to do, is to ensure that the following registry entries (and structure) exists in the registry:<br /><br /><span style="font-family:courier new;">[HKEY_LOCAL_MACHINE\SOFTWARE\OpenLDAP\Parameters]</span><br /><br />with keys:<br /><br /><span style="font-family:courier new;">ConfigFile PathToOpenLDAPDirectory<pathtoopenldapdirectory>\slapd.conf</pathtoopenldapdirectory></span><br /><span style="font-family:courier new;">DebugLevel 0</span><br /><span style="font-family:courier new;">Urls ldap://:28089</span><br /><br /><span style="font-style: italic;">Note that the "ConfigFile" and "Urls" parameters are String settings whereas "DebugLevel" is a DWORD32</span><br /><br />And that's it. A restart of the OpenLDAP service and Shared Services service meant that I could register all the other Hyperion services. The "Urls" parameter is the main setting, as that dictates that OpenLDAP is to listen on port 28089 which is what is required by the rest of the Hyperion services.<br /><br />It may also be worth noting that a quick glance at the default <span style="font-family:courier new;">slapd.conf</span> file supplied by Oracle lists that a "pid" file and "arg" file be created in the ".../var/run" directory. Clearly a *nix setting but rather amusingly there is no "run" directory under the "var" directory in the Windows structure. If you create it, those files will be created. Also, it may well be worth you adding in an entry for the creation of a logfile. I added an entry in the "slapd.conf" file, immediately below the entries for the "run" and "arg" files to do this. The key looks like:<br /><br /><span style="font-family:courier new;">logfile <pathtoopenldapdirectory\log\slapd.log></pathtoopenldapdirectory\log\slapd.log></span> <span style="font-family:courier new;">PathToOpenLDAPDirectory\logs\slapd.log</span><br /><br />To get logging to appear in this file you will need to change the value in the registry entry "DebugLevel" created earlier to a value other than zero. The number 4 is probably a good value to go for or 1 if you wish to debug issues.<br /><br />And there you have it. I hope that this helps others to have more time to do things other than the configuration of EPM.<br /><br />Good luck.<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com15tag:blogger.com,1999:blog-6334481233407743503.post-29443567305651741142008-04-19T08:53:00.008+01:002008-04-19T13:18:45.098+01:00The ProClarity API - Programmatic changes to ProClarity briefing booksWe have a client who is using Analysis Services 2000 and ProClarity Analytics Server 6.3 in order to provide balance sheet and financial line information to their business. The system that I designed had to be able to aggregate financial data up a customer hierarchy but be able to aggregate the data into parents as they stood at the time the data was loaded and against the current parent. (i.e. A slowly changing dimension.) However, this dimension consists of over 1.5 million members and there are effectively two versions of this in the database.<br /><br />Now this on its own is fine-ish, in that with the 3GB switch enabled and some tweaks to the cleaner thread interval the AS solution is stable and performs reasonably well. However, the original requirement did not specify security on these dimensions. As you can guess, there is now a requirement to place security on these dimensions, partially to limit access to the data but more so to provide a way for a given user's reports to open, defaulted to the customers for which they are responsible.<br /><br />Now trying to add security using a "security cube" isn't really conducive to performance and adding 440 roles to AS, each with a different security context, isn't really good for maintenance or memory. (i.e. Think replica dimensions.) So, what else?<br /><br />Well, as an approach, I wondered if it is possible to take a template ProClarity briefing book located in a PAS Store, load it and customise it for a given user and write it back to the PAS store. From previous experiences I know that just updating the XML in the PAS database for a given briefing book and pages causes problems down the line, to the point that they may no longer work. So how else? Can you make programmatic changes? I know that there is an API for ProClarity but the documentation is all for VB etc. and not .Net.<br /><br />In the end I decided to give it a try and started to write an application that would retrieve a result set from a database specifying the template book and pages etc. that are to be customised and the customisations to be made. It also specifies the PAS store into which the book should be ultimately published and security assignments for the new book.<br /><br />After contacting Microsoft on TechNet for some hints and tips (whose responses are pretty quick and impressive actually) I was on my way. See <a href="http://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=2723139&SiteID=17">Hints and Tips</a> for that thread.<br /><br />The essentials to know, when using C#, are effectively as follows:<br /><ol><li>In order to have a briefing book loaded within a ProClarity application in memory, use the <span style="color: rgb(51, 204, 255);">KProClarityClass</span>.StartupBook method.</li><li>Once you have a <span style="color: rgb(51, 204, 255);">KProClarityClass</span> object, use the following objects, properties or methods as shown below...<br /><br /><span style="font-family:courier new;">Application (Object)</span><br /><span style="font-family:courier new;"> |</span><br /><span style="font-family:courier new;">CurrentView (Property)</span><br /><span style="font-family:courier new;"> |</span><br /><span style="font-family:courier new;">PageCtrl (Object)</span><br /><span style="font-family:courier new;"> |</span><br /><span style="font-family:courier new;">KPCommand (Object)</span><br /><span style="font-family:courier new;"> |</span><br /><span style="font-family:courier new;">GetAxisMemberSet (Method)</span><br /><span style="font-family:courier new;"> |</span><br /><span style="font-family:courier new;">KMemberSet</span><br /><br />As an example, use the <span style="color: rgb(51, 204, 255);">KProClarityClass</span>'s Application property to retrieve a reference to the <span style="color: rgb(51, 204, 255);">Application</span> object. Now use the Application object's CurrentView property to retrieve a reference to the the <span style="color: rgb(51, 204, 255);">ICurrentView</span> interface etc. etc.<br /></li><li>If you make any changes to a <span style="color: rgb(51, 204, 255);">KMemberSet</span>, you must use that object's associated <span style="color: rgb(51, 204, 255);">KCommand</span> object's execute method in order update all associated entities within the ProClarity object model.</li><li>If you copy elements etc. be sure to update the copied element's ID otherwise you will get errors when trying to publish the briefing book. (i.e. You will have two elements with the same ID which understandably is not allowed.) To do this, set the ID for the given element to: <span style="color: rgb(204, 0, 0);">"{00000000-0000-0000-0000-000000000000}"</span></li><li>In order to commit changes you have made to a given briefing book page, you have to copy the "page" within the book, using the <span style="color: rgb(51, 204, 255);">CurrentView</span>'s AddPageToBook method and then delete the original page. Please don't shout at me, I know, that sucks but that's just how it is okay?<br /></li></ol><br />In the end I changed my application to run as a custom SSIS task and to be multi-threaded using a blocking-queue in order to hand out template briefing books for updates to consumer threads etc. That all seemed to work although I did experience exceptions when running the task in debug mode. As can be seen by the following thread with Microsoft <a href="http://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=2967022&SiteID=17">here</a>, this was related to my code not being aware of the COM aspects of the ProClarity API.<br /><br />All in all it was quite fun to develop, creating mini-caches for PStore connections etc. and to implement a solution that runs within SSIS. I added in the ability to set properties such as the number of threads to use and the ability to set the table and column names that store the relevant updates to be made.<br /><br />Using simple test cases it appears to work quite nicely. Reports remain static, such that reports with both grids, totals and graphs etc. retain that layout when the member selections are changed. The task allows the ability to either update members by axis or to simply replace the MDX for the report. (Actually you could replace the MDX for a report and then customise the member selection immediately thereafter if you so wished but why?)<br /><br />Before it's a finished beta v0.0.0.0.0.0.1 "product" (Oracle style versioning there) the task needs to accommodate pages within nested folders (i.e. currently only handles pages at the root or one level below) and to complete the security aspect. I also need to normalise the table structures that store the updates to be made against the template briefing book etc.<br /><br />Anyhoo, if anyone out there is interested in using this please add a comment to this blog and I'll see if I can add it to our company's website for download. That naturally assumes anyone actually reads my blog...<div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com3tag:blogger.com,1999:blog-6334481233407743503.post-64185837851955862012007-12-04T17:01:00.000+00:002008-01-01T12:32:30.677+00:00Oracle 11g on Oracle Linux<span style="font-weight: bold;font-size:130%;" >Intro</span><br />So here's the thing...<br /><br />I decided to have a more detailed look at Oracle 11g. I like the Oracle relational databases, really I do. They are a mature, stable, scalable database which is feature rich. It can run on Linux, Unix, Windows and even a Mac if you want. However, my focus in this blog is the installation of the database on Linux. Oracle's own in fact...<br /><br />So Oracle offer a "distro" of Linux. Sounds good as a concept, Oracle offering an OS on which you can install their database and all. However, if you are a newbie to Linux and/or Oracle you gonna need to set aside quite a bit of time for this. (By quite a bit, read: "a lot!")<br /><br />Now my issue isn't so much the number of settings required during installation, it's a complex piece of software, nor the planning on how it should be or where it should be installed. All that is fine. I <span style="font-style: italic;">understand</span> that. It's just that the actual act of installing Oracle 11g on Oracle Linux should be, well, seamless should it not?<br /><br /><span style="font-weight: bold;font-size:130%;" >Grumbles</span><br />I'm sorry, the fact that I installed Oracle linux with practically all package options selected (didn't select the KDE development ones) yet still didn't get the "oracleasm" packages installed mystifies me. The fact that I didn't get prompted with a question asking "are you intending to use this installation as a platform for another Oracle product" and then providing me with a list, is a little concerning. Some way of being able to configure the installation of the OS based on what I want to do later with other Oracle products seems somewhat natural, yet it is lacking. But what really sends me down a rabbit hole of despair, is the fact that of the 3 "oracleasm" packages required for using Automated Storage Management, one of them is not included in any of the 5 disks of Oracle Enterprise 5 ISO images.<br /><br />I cannot help but wonder if I am just being picky. It's just that it seems natural to me to include <span style="font-style: italic;">all</span> requirements for a successful installation in the installation software. In order to use ASM I need to have already installed the ASM libraries, yet to do that I need to go to OTN and download the missing package. To make matters worse, the package seems to have been released a long time ago yet the ISO images for Oracle Linux Enterprise 5 have not been updated to include them.<br /><br />Then, to top it all off, once you actually get the dang thing installed, (i.e. the OS and 11g) there are no installations of start up scripts or anything. Nope. Nada, bupkiss, didley-squat! You want Oracle 11g to start up automatically you darn well get to write them yourself or find someone else's on the web and use that. As it happens, using someone else's is probably natural seeing as by the time you've actually managed to install the software you are probably on to your 2nd or 3rd blog, the writers of which have probably included theirs.<br /><br />Add to this that if you are using ASM without RAC, you need to include the marking of your RAW disks for oracle ASM in your start up scripts in order to get the ASM service to know about else the Oracle database won't start. (Maybe this is meant to be included in a config file somewhere but I couldn't find any documentation on that. Some blogs talk about using "rawdevices" but that has been deprecated now.)<br /><br /><span style="font-weight: bold;font-size:130%;" >Finally</span><br />The long and short of all of this is that I can fully understand now, why someone would install Microsoft SQL Server for a demo etc. You could have Windows installed, the SQL Server software installed and configured and the demo built whilst you are still faffing about trying to get everything you need for the Oracle installation.<br /><br />What a shame... In my opinion, for what its worth, the Oracle RDBMS is far better and complete in its offering than SQL Server. I guess I mean it is more mature. But lets face it, money talks, and if at a fraction of the price you can have a database and have it installed dancing on one leg whistling Dixie in the fraction of the time of something else, why wouldn't you?<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Links I used:</span></span><br /><ol><li><span style="font-size:100%;"><a href="http://startoracle.com/2007/09/30/so-you-want-to-play-with-oracle-11gs-rac-heres-how/">Install Oracle 11g for RAC</a></span></li><li><span style="font-size:100%;"><a href="http://www.dba-oracle.com/real_application_clusters_rac_grid/raw_devices_linux.html"><span style="font-size:10;">Create RAW devices using LVM</span></a></span></li></ol><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com0tag:blogger.com,1999:blog-6334481233407743503.post-43212168389197061022007-11-01T13:42:00.000+00:002008-12-13T07:37:58.154+00:00Custom SSIS Control Flow TaskOkay, so if you're reading this chances are you're looking to create a custom SSIS task using C# to do your bidding. Either that or you've just stumbled across this blog on your tea break whilst surfing the web. Either way, you have my sympathies. ;-)<br /><br />So, why this entry? Well, one morning I woke up and suddenly thought "how cool to write a custom SSIS task that will process Analysis Services objects as defined by information in a relational database." Now I know I can use a "for-loop" task along with an Analysis Services DDL task but (a) where's the challenge in that (b) I want access to the lower level calls and information that SSAS returns and (c) how does that help me understand the SSIS internals I ask you?<br /><br />Now as it happens you may, like I did, have the dismal mis-conception that it should be fairly easy to create a "nice" custom task, what with all the information in BOL and on the internet. Alright, maybe that's a bit harsh. To create the task itself isn't really that hard I suppose, but it's the stuff around it that I find <span style="font-style: italic;">really</span> annoying and time consuming. Things that really should be easy, aren't. Stuff that you have to do before you even get to build the task is just badly documented or scattered around, not in one place. In some cases there's even confusion amongst developers and posts are clearly incorrect. Only, it's only clearly incorrect after you know the answer.<br /><br />So, in a nutshell, here are my thoughts and findings. If you are a seasoned C# developer then maybe these things are trivial, in which case this blog isn't for you. However, for the rest of us:<br /><br /><ol><li>The SSIS model, as compared to DTS, is actually okay. Microsoft appear to have thought about this somewhat and came up the logic of allowing the separation of the UI from the task, such that at runtime the amount of code to be loaded is reduced etc. Good idea! They even specify that that is the best practice. <rant><sarcasm>Well, thank goodness for Microsoft's life saving documentation then!</sarcasm>So why is it, that if according to Microsoft's own recommendations for splitting the UI from the task, does their own "definitive guide", and by that I mean the sample to which we are continually referred, for creating custom tasks have the UI and the task in one assembly? Just how is that helpful?</rant><br /><br />This reference to the <a href="http://technet.microsoft.com/en-us/library/ms345156.aspx">Increment Task</a> includes the following statement:<br />"<a style="font-style: italic;" name="sectionToggle0">A separate assembly for the user interface is recommended for ease of deployment because it allows you to update and redeploy the connection manager or its user interface independently.</a>"<br />And this Microsoft <a href="http://technet.microsoft.com/en-us/library/ms136080.aspx">link</a> states:<br />"<span style="font-style: italic;">A task and its user interface are separate entities. They should be implemented in separate assemblies to reduce localization, deployment, and maintenance work.</span>"<br />Further "Increment Task" sample links:<br /><a href="http://www.codeplex.com/MSFTISProdSamples/Wiki/View.aspx?title=SS2005%21Creating%20a%20Custom%20Increment%20Task%20Sample&referringTitle=Home">Creating a Custom Increment Task</a><br />or<br /><a href="http://msdn2.microsoft.com/en-us/library/ms160699.aspx">Creating a Custom Increment Task</a><br /></li><li>So you would like to use your own icon for your task eh? Pity lots of documentation out their is either grossly inaccurate or totally out of date.</li><li>Resizing list boxes smoothly by keeping it in sync. with a PropertyGrid when the form is resized, like the Analysis Services DDL Task, isn't a particularly intuitive thing to achieve.<br /></li><li>Then there's the PropertyGrid. It seems to me that with the ".net" languages Microsoft discovered the concept of reflection and like XML, it must be used everywhere! Now don't get me wrong, I'm not saying that they didn't know about it before. I mean Delphi (not MS I know) had RTTI etc. so it's a general concept but it just seems that <span style="font-style: italic;">everything</span> uses reflection, including the PropertyGrid.<br /></li><li>Anyone found any decent documentation on using ConnectionManagers? So we have a ConnectionManager that can define a connection of varying types which is cool. Very handy. The connections can be OLE DB, ADO, ADO.NET, MSOLAP.2 (or 3) etc. Yet most of the documentation seems to imply that you can just call AcquireConnection, cast the object returned to an object of type SqlServer and "Bob's your uncle". Yeeeeesssss, if only.<br /></li></ol><p>Those are the ones that have caused me the most grief so far. I'll add more as and when I find them, but in the meantime, to save you the pain, here are my hints and tips to prevent this from happening to you, starting with the concept of keeping the task and UI separate.<br /><br /><br /><b>Separating the UI from the task</b><br />I reckon that this is a solid approach and one which should be followed as a matter of course. Once you've worked out how it all works it actually wouldn't be that hard to knock up some boilerplate code or a project set at a starting point for all future tasks. The idea is as follows:<br /></p><ul><li>Identify all the properties about the task that you need to capture from the user. Things like connection types and connection managers, starting values and filter conditions etc. Once you know what they are, you're pretty much set.<br /><br /></li><li>In the task (i.e. the class that extends <span style="color: rgb(51, 255, 255);font-family:courier new;" >Task</span> and contains the methods InitializeTask, Validate and Execute), create private, class level variables of the appropriate type for each of the properties identified above. Naturally include the DtsTaskAttribute required to link the task to the UI as described in all documentation and the samples etc.<br /><br /></li><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_vDEbVIy1omQ/Ry-g70lSkXI/AAAAAAAAAAU/dsC9U3x8bIM/s1600-h/TaskClass100.JPG"><img id="BLOGGER_PHOTO_ID_5129495450186060146" style="margin: 0pt 20px 20px 0pt; cursor: pointer;" alt="DtsTask DtsTaskAttribute" src="http://3.bp.blogspot.com/_vDEbVIy1omQ/Ry-g70lSkXI/AAAAAAAAAAU/dsC9U3x8bIM/s400/TaskClass100.JPG" border="0" /></a><br /><li>In the same class, create properties for the task (i.e. "methods" using <span style="color: rgb(0, 0, 153);font-family:courier new;" >get</span> and <span style="color: rgb(0, 0, 153);font-family:courier new;" >set</span>) allowing each of the required variables identified above to be set and retrieved.</li><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vDEbVIy1omQ/Ry-h7klSkYI/AAAAAAAAAAc/wdi19B9Lxx0/s1600-h/TaskProperty100.JPG"><img id="BLOGGER_PHOTO_ID_5129496545402720642" style="margin: 0pt 20px 20px 0pt; cursor: pointer;" alt="Property" src="http://2.bp.blogspot.com/_vDEbVIy1omQ/Ry-h7klSkYI/AAAAAAAAAAc/wdi19B9Lxx0/s400/TaskProperty100.JPG" border="0" /></a><br /><li>Create a new assembly for the UI. Add a class that extends <span style="color: rgb(51, 255, 255);font-family:courier new;" >Form</span>, and include the class identified by the DTSAttribute annotating the Task that is to be called to instantiate the UI. The constructor for the form should, at the very least, require the <span style="color: rgb(51, 255, 255);font-family:courier new;" >TaskHost</span> to be supplied on instantiation in order to allow the retrieval and setting of the Task's properties. Note that there is nothing really special here. Just follow the standard documentation regarding building a UI for your task but do so in a separate assembly.<br /></li><br /><u>UI Class</u><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_vDEbVIy1omQ/Ry-iMUlSkZI/AAAAAAAAAAk/yFtsC_fYE4w/s1600-h/TaskUI100.JPG"><img id="BLOGGER_PHOTO_ID_5129496833165529490" style="margin: 0pt 20px 20px 0pt; cursor: pointer;" alt="C# SSIS custom task UI" src="http://1.bp.blogspot.com/_vDEbVIy1omQ/Ry-iMUlSkZI/AAAAAAAAAAk/yFtsC_fYE4w/s400/TaskUI100.JPG" border="0" /></a><br /><u>UI Class Methods (Initialize method repeated here)</u><br />Note the "GetView" method that passes the TaskHost object into the form's constructor.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_vDEbVIy1omQ/Ry-jYklSkaI/AAAAAAAAAAs/T42bRrD5dw0/s1600-h/TaskUIMethods100.JPG"><img id="BLOGGER_PHOTO_ID_5129498143130554786" style="margin: 0pt 20px 20px 0pt; cursor: pointer;" alt="C# SSIS custom task methods" src="http://2.bp.blogspot.com/_vDEbVIy1omQ/Ry-jYklSkaI/AAAAAAAAAAs/T42bRrD5dw0/s400/TaskUIMethods100.JPG" border="0" /></a><br /><li>In the constructor for the form, record the TaskHost variable passed into the constructor in a class level global variable of type <span style="color: rgb(51, 255, 255);font-family:courier new;" >TaskHost</span> for ease of access.</li><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_vDEbVIy1omQ/Ry-pUElSkbI/AAAAAAAAAA0/ZPnZd3vRB2I/s1600-h/FrmTaskUI100.JPG"><img id="BLOGGER_PHOTO_ID_5129504662890910130" style="margin: 0pt 20px 20px 0pt; cursor: pointer;" alt="SSIS task UI form" src="http://4.bp.blogspot.com/_vDEbVIy1omQ/Ry-pUElSkbI/AAAAAAAAAA0/ZPnZd3vRB2I/s400/FrmTaskUI100.JPG" border="0" /></a><br /><li>Now to save any changes made in the UI back to the Task's property methods, use code similar to the following, where "g_TaskHost" is the global variable for the TaskHost object, "SQLConnectionType" is the property created on the Task and "ADO.NET" is the value to which it should be set.<br /><span style="font-size:85%;"><span style="font-family:courier new;">g_TaskHost.Properties["SQLConnectionType"].SetValue<br />(g_TaskHost, "ADO.NET")</span><span style="font-family:courier new;">;</span></span></li><br /><li>To load the values from the Task for display in the UI, use code similar to the following, using the same conventions as described in the point immediately above.<br /><span style=";font-family:courier new;font-size:85%;" >g_TaskHost.Properties["SQLConnectionType"].GetValue<br />(g_TaskHost).ToString();</span></li><br /></ul><p><br /><b>Custom Icon</b><br />I have seen a lot of documentation on the web regarding the value for "IconResource" as it appears in the DtsTaskAttribute and what it should be. They state things like the name of the icon <span style="font-style: italic;">must</span> be "MyTaskIcon.ico" and/or the resource must be fully qualified with the namespace etc. This may or may not have been correct in beta versions etc. but as it stands today you can call the icon whatever you want and the qualified name must be the name of the assembly in which the icon resides "dot" the name of the file.<br /></p><p>See: <a href="http://msdn2.microsoft.com/en-us/library/microsoft.sqlserver.dts.runtime.dtstaskattribute.iconresource.aspx"><span style="text-decoration: underline;">DtsTaskAttribute.IconResource</span></a><br /><br />So, if your assembly is called: "<span style="font-family:courier new;">foo.bar.dll</span>" using a namespace of "<span style="font-family:courier new;">me.baz</span>" and the name of your icon is "<span style="font-family:courier new;">Designer.ico</span>", then the correct value for "IconResource" is: <span style="font-family:courier new;">foo.bar.Designer.ico</span><br /><br /><br /><b>Resize List Boxes in sync. with a PropertyGrid</b><br />Set the ListBox property "<span style="font-family:courier new;">IntegralHeight</span>" to "<span style="font-family:courier new;">False</span>". That's it!<br /><br /><br /><b>Using PropertyGrids</b><br />Hmmmm, this is a section all on its own. If anyone ever actually reads this blog and would like some information on this I'll post more but beware of what you ask for...<br /><br /><br /><b>ConnectionManagers</b><br />I've yet to follow this through myself. Currently I'm coding my task specifically around the ADO.NET connection type which allows me to cast the connection to "SqlServer". I will support more connection types later.<br /><br />My feelings thus far are that to accommodate different connection types in a way that minimizes code rework, one could either create a class that encapsulates the nuances of the different connection types, providing common functionality, or use method overloading in some way.<br /><br /><br /><br />Well that's it. If you got this far either pat yourself on the back for your perseverance or shake your head in disgust at how geeky you really are. :-)<br /><br />'Till next time...<br />Phil </p><div class="blogger-post-footer"><a href="http://feedburner.google.com/fb/a/mailverify?uri=BiLog&loc=en_US">Subscribe to BI Log by Email</a></div>Philip Stephensonhttp://www.blogger.com/profile/12268504284150608108noreply@blogger.com3