<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
	xmlns:media="http://search.yahoo.com/mrss/"
>

<channel>
	<title>Dave's Adventures in Business Intelligence &#187; VBA Tools</title>
	<atom:link href="http://www.dagira.com/category/vba-tools/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.dagira.com</link>
	<description>...you are in a twisty maze of passageways, all different...</description>
	<lastBuildDate>Wed, 28 Jul 2010 13:13:17 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<!-- podcast_generator="podPress/8.8" -->
		<copyright>&#xA9; </copyright>
		<managingEditor>blogmaster@dagira.com ()</managingEditor>
		<webMaster>blogmaster@dagira.com()</webMaster>
		<category></category>
		<ttl>1440</ttl>
		<itunes:keywords></itunes:keywords>
		<itunes:subtitle></itunes:subtitle>
		<itunes:summary>...you are in a twisty maze of passageways, all different...</itunes:summary>
		<itunes:author></itunes:author>
		<itunes:category text="Society &amp; Culture"/>
		<itunes:owner>
			<itunes:name></itunes:name>
			<itunes:email>blogmaster@dagira.com</itunes:email>
		</itunes:owner>
		<itunes:block>No</itunes:block>
		<itunes:explicit>no</itunes:explicit>
		<itunes:image href="http://www.dagira.com/wp-content/plugins/podpress/images/powered_by_podpress_large.jpg" />
		<image>
			<url>http://www.dagira.com/wp-content/plugins/podpress/images/powered_by_podpress.jpg</url>
			<title>Dave's Adventures in Business Intelligence</title>
			<link>http://www.dagira.com</link>
			<width>144</width>
			<height>144</height>
		</image>
		<item>
		<title>Using the Designer SDK to Ease Migrations</title>
		<link>http://www.dagira.com/2008/03/06/using-the-designer-sdk-to-ease-migrations/</link>
		<comments>http://www.dagira.com/2008/03/06/using-the-designer-sdk-to-ease-migrations/#comments</comments>
		<pubDate>Thu, 06 Mar 2008 23:31:57 +0000</pubDate>
		<dc:creator>Dave Rathbun</dc:creator>
				<category><![CDATA[Universe Design]]></category>
		<category><![CDATA[VBA Tools]]></category>

		<guid isPermaLink="false">http://www.dagira.com/2008/03/06/using-the-designer-sdk-to-ease-migrations/</guid>
		<description><![CDATA[The full client applications (Business Objects aka Desktop Intelligence) have had VBA (Visual Basic for Applications) for quite some time. The initial release of 4.x included a scripting language that was &#8220;like&#8221; VBA but was not quite the same. When 5.x was introduced they switched to Microsoft VBA. I have written more than a few [...]]]></description>
			<content:encoded><![CDATA[<p>The full client applications (Business Objects aka Desktop Intelligence) have had VBA (Visual Basic for Applications) for quite some time. The initial release of 4.x included a scripting language that was &#8220;like&#8221; VBA but was not quite the same. When 5.x was introduced they switched to Microsoft VBA. I have written more than a few VBA utilities over the years, some of which are published on the Integra Solutions library page. Today I want to share a utility that I put together to help migrate universes in a Teradata environment. I should point out that this utility does not require that you use Teradata; it can be used in any database environment where you need to do a mass-update to the owner or schema name.</p>
<h3>Executive Summary</h3>
<p>This utility is designed to automate the update of the schema or owner name in a universe. The host application is Microsoft Excel since the Universe Designer application cannot be a VBA host. You enter the &#8220;From&#8221; and &#8220;To&#8221; schema names into cells in the XLS and run the macro. At completion you will have a universe where the schema (or owner) has been updated.</p>
<p><span id="more-68"></span></p>
<h3>Explaining the Problem</h3>
<p>When I build a connection to Teradata, I do not connect to a database. I connect to a server. That server could be the host for more than one database or schema. That means that for my universe I have to fully qualify the tables as owner.tablename rather than referencing the tablename by itself. This presents a problem because my schema names change during the migration process. And most migration managers frown on editing code during the migration process. <img src='http://www.dagira.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>In this particular case the schema name is a short abbreviation of the project (I will use PROJ for this blog post) followed by a letter that designates the purpose of the schema. For example, _D is the development schema, _S is the System Test schema, and _P is for production. A table that is named <code>PROJ<strong>_D</strong>.tablename</code> in development will become <code>PROJ<strong>_P</strong>.tablename</code> in production. That&#8217;s a code change.</p>
<h3>First Solution</h3>
<p>If you have a simple universe you can highlight all of the tables, right-click and select the &#8220;rename table&#8221; option from the mouse menu. With this technique you can update the owner for every single table in the universe in one step. But what if you have aliases as well as regular tables? In that case, you have to selectively highlight all of the tables (ignoring the aliases) and rename only the source tables. The aliases will inherit the change.</p>
<p>The easiest way I have found to do this is to use the table listing on the &#8220;List Mode&#8221; panel that you can show on the top of the screen. That way all of the tables with the same owner are listed together, and rather than use the graphical structure to rename my tables I can use a list. This works well, and solves the problem.</p>
<p>Until you introduce Derived Tables into your universe. <img src='http://www.dagira.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Second Solution</h3>
<p>When you use a derived table those tables don&#8217;t really have owner names since they exist only in the universe. But they do reference tables in the database, and as discussed above, they will include the schema or owner name. In order to migrate derived tables correctly, I had to open each one and update the SQL manually. This was a problem.</p>
<p>The main issue is that I was changing the code during a migration. That means that a bug could be introduced. And introducing bugs during a migration (after system testing has been completed) is not a popular result. <img src='http://www.dagira.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>So what I did to solve this issue at first was to create an Excel spreadsheet that contained the SQL code required for each derived table. I created formulas where the schema name was a reference to a single cell in the sheet. To migrate a universe I would open this XLS, update the schema name in one place, and see that schema name updated in each different SQL statement. It becomes a simple copy / paste operation during the migration rather than an &#8220;edit&#8221; operation. This was certainly safer, because the code itself was verified and the only thing that was being updated was the schema name. But there were still problems.</p>
<p>For example, at one point we had someone new join our team, and their video resolution was smaller than mine. What does the video setting have to do with this? Smart question. <img src='http://www.dagira.com/wp-includes/images/smilies/icon_lol.gif' alt=':lol:' class='wp-smiley' />  The issue was on my screen I would see <strong>seven</strong> derived table definitions. On their screen, because it was smaller, they only saw <strong>five</strong>. That meant when they processed the instructions in the spreadsheet they only updated five of the seven derived tables, with the net result being we got code in production that was not working.</p>
<h3>Automate the Process</h3>
<p>So now, finally, the VBA solution. The advantage of VBA (or any programming language) is that it&#8217;s going to do exactly what you tell it to do.  It won&#8217;t do half of the derived tables and skip the rest. It won&#8217;t accidentally miss a table during the selection process. If you set up a program loop and tell it to process every table, that&#8217;s just what it will do.</p>
<h3>The Code</h3>
<p>The code is contained within a host application since Designer cannot host the code itself. I selected Excel as my host which is quite common. Many of the utilities on <a href="http://www.forumtopics.com/busobj/viewforum.php?f=25">BOB&#8217;s Downloads</a> do the same. I will detail the code here, and the entire file is presented as an attachment at the end of this post. <strong>Disclaimer: This code should be considered &#8220;beta&#8221; quality at this time.</strong> This means it is &#8220;use at your own risk&#8221; and make backups and all that good stuff.</p>
<p><strong>Getting Started</strong><br />
First there are some basic settings and declarations that appear at the top of every Business Objects utility that I write.</p>
<pre>Option Explicit                 ' Require variables to be declared before being used
Option Base 1                   ' Start array indexes at 1 as I think better that way

Dim boDesignerApp As Designer.Application
Dim boUniv As Designer.Universe
Dim xlSheet As Excel.Worksheet</pre>
<p>Next there is the main routine. In most cases my main routines are very short, often (as in this case) there is nothing in them except for function or subroutine calls. This means that the main routine reads more like a process flow and less like actual code. I think it&#8217;s easier to manage that way.</p>
<pre>Sub Main()

    Set xlSheet = Worksheets(1)
    Call UpdateSchema
    MsgBox ("Done")

End Sub</pre>
<p>The first line of code is a shortcut and would not be in the final code. I use it so I have a reference to the first sheet in the workbook where the schema names appear. I generally try to provide all of my input variables via excel cells rather than requiring a user to answer a prompt (because I&#8217;m lazy) or editing the code (because of the potential for mistakes). </p>
<p>Next, the function used to update the schema names. The &#8220;Private&#8221; declaration means that you cannot run this macro function directly. It can only be called from other code.</p>
<pre>Private Sub UpdateSchema()</pre>
<p>The next lines are declarations for variables that I need. The Designer reference is going to give me a handle for the application, and the tbl item will point to the collection of tables in my universe once it is open.</p>
<pre>    Dim tbl As Designer.Table
    Dim sSchemaFrom As String
    Dim sSchemaTo As String</pre>
<p>Those lines of code retrieve the &#8220;from&#8221; and &#8220;to&#8221; schema from the appropriate cells in the worksheet. Minor point: if you use this technique, I strongly suggest that you use named ranges rather than absolute cell references like &#8220;A1&#8243; as it makes the code much easier to maintain.</p>
<pre>    sSchemaFrom = xlSheet.Range("SchemaFrom").Value
    sSchemaTo = xlSheet.Range("SchemaTo").Value</pre>
<p>Next, log in to Designer. The code to do this is different depending on whether you&#8217;re using versions 6.5 or earlier or XI. Both syntaxes are shown here.</p>
<pre>    ' Establish a Designer session and log in
    Set boDesignerApp = New Designer.Application
    boDesignerApp.Visible = True

    ' Use this method instead for older versions
    ' Call boDesignerApp.LoginAs
    Call boDesignerApp.LogonDialog</pre>
<p>Next, open the universe. Since I don&#8217;t specify a universe name, I will be able to interact with the standard &#8220;File &#8211; Open&#8221; dialog box provided by Designer.</p>
<pre>    Set boUniv = boDesignerApp.Universes.Open</pre>
<p>After opening the universe it is time to process the tables. This next block of code loops through each table in the Tables collection. There is an attribute called <code>IsAlias</code> that is true if the table is an alias rather than a true source table. If that flag is true, then there is no processing done on that table. The &#8220;debug.print&#8221; command sends output to the debug window; a user will not see that information.</p>
<pre>    boDesignerApp.Visible = False

    For Each tbl In boUniv.Tables
        If tbl.IsAlias Then
            Debug.Print tbl.Name &#038; " is alias"</pre>
<p>Next, if the table is a derived table I have to update the schema name in the SQL. There is an called <code>IsDerived</code> that will be true if the table is a derived table. If it is true then the attribute <code>SqlOfDerivedTable</code> contains the SQL code.</p>
<p>One note: if the update fails the derived table will still exist but it will be in an invalid state. In this case what I have found is that a universe integrity check will fail in catastrophic fashion. <img src='http://www.dagira.com/wp-includes/images/smilies/icon_lol.gif' alt=':lol:' class='wp-smiley' /> </p>
<pre>        ElseIf tbl.IsDerived Then
            ' Update derived table SQL here
            Debug.Print tbl.Name &#038; " is derived"
            tbl.SqlOfDerivedTable = str_replace(tbl.SqlOfDerivedTable, sSchemaFrom, sSchemaTo)</pre>
<p>Finally, if it&#8217;s a normal table then the Name attribute contains the full name, which includes the schema. I update the name attribute then loop to the next table in the collection.</p>
<pre>        Else
            ' Update table owner
            Debug.Print tbl.Name &#038; " is table"
            tbl.Name = str_replace(tbl.Name, sSchemaFrom, sSchemaTo)
        End If
    Next tbl</pre>
<p>Finally, save the universe and exit.</p>
<pre>
    boUniv.Save

    ' Release the Designer app and recover memory
    boDesignerApp.Quit
    Set boDesignerApp = Nothing

End Sub</pre>
<p>This code is fairly simple, once you know which attributes (they are actually called &#8220;properties&#8221;) are available. The last bit of code is the <code>str_replace()</code> function. There is no function named <code>str_replace()</code> in VBA by default, but there is a <code>Replace()</code> function. So why did I create something brand new, if all I am going to do is call a built-in function? It&#8217;s a good question.</p>
<p>There are many advantages to creating a function wrapper. First, if I need to port my code to a different version of VBA there might not be a <code>Replace()</code> function. By creating my own function call I can write a replacement function without touching the rest of the code. The more important advantage, however, is that I can put extra code inside my function. Here is what my <code>str_replace()</code> function looks like right now:</p>
<pre>Private Function str_replace(ByRef sSql As String, sFrom As String, sTo As String) As String

    sSql = Replace(sSql, sFrom, sTo, 1, -1)
    str_replace = sSql

End Function</pre>
<p>As you can see, there&#8217;s not much going on other than a basic replacement of text. But what I thought about doing is writing a log to the Excel worksheet showing the &#8220;before&#8221; and &#8220;after&#8221; state of each table that gets processed in the loop. That will help create an audit trail and make debugging easier as well. At the moment that code does not exist. But by creating a wrapper for the <code>Replace()</code> function I can do that.</p>
<p>I use this technique all the time in various programming languages, not just VBA. It has served me well in the past.</p>
<p>So that&#8217;s the end of the code. What, you thought there was more? <img src='http://www.dagira.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h3>Conclusion</h3>
<p>I&#8217;ve done only very preliminary testing for this utility so far, but it seems to work just fine. I expect that it will really help my current client with their Teradata universe migrations.</p>
<h3>Downloads</h3>
<p><em>The following utility is released under the GPL or Gnu Public License. This means that you have the freedom to do whatever you like with the code but it must retain my copyright. There are no licensing costs associated with use in a corporate or any other environment. No warranty is expressed or implied.</em></p>
<ul>
<li><a href='http://www.dagira.com/wp-content/uploads/2008/03/dagiraschemachange.xls' title='Schema Change Utility'>Dagira Schema Change Utility</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.dagira.com/2008/03/06/using-the-designer-sdk-to-ease-migrations/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
	</channel>
</rss>
