<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://sqlblog.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results matching tags 'Best Practices', 'alias types', and 'UDTs'</title><link>http://sqlblog.com/search/SearchResults.aspx?o=DateDescending&amp;tag=Best+Practices,alias+types,UDTs&amp;orTags=0</link><description>Search results matching tags 'Best Practices', 'alias types', and 'UDTs'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61129.1)</generator><item><title>Bad habits to kick : using alias types</title><link>http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/14/bad-habits-to-kick-using-alias-types.aspx</link><pubDate>Thu, 15 Oct 2009 02:07:00 GMT</pubDate><guid isPermaLink="false">21093a07-8b3d-42db-8cbf-3350fcbf5496:17697</guid><dc:creator>AaronBertrand</dc:creator><description>&lt;p&gt;&lt;i&gt;In my &lt;a href="http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/14/bad-habits-to-kick-using-the-visual-designers.aspx" title="http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/14/bad-habits-to-kick-using-the-visual-designers.aspx" target="_blank"&gt;last post in this series&lt;/a&gt;, I talked about using the visual designers in SSMS.&amp;nbsp; This time, I wanted to treat the use of alias types.&lt;/i&gt; &lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;br&gt;To clarify what I am talking about here, alias types used to be called "&lt;a href="http://msdn.microsoft.com/en-us/library/aa933121%28SQL.80%29.aspx" title="http://msdn.microsoft.com/en-us/library/aa933121%28SQL.80%29.aspx" target="_blank"&gt;user-defined data types&lt;/a&gt;."&amp;nbsp; Then, when CLR came around in SQL Server 2005, they gave us the ability to create our own &lt;a href="http://msdn.microsoft.com/en-us/library/ms131120.aspx" title="http://msdn.microsoft.com/en-us/library/ms131120.aspx" target="_blank"&gt;CLR user-defined types&lt;/a&gt;
(UDTs) - a different beast altogether.&amp;nbsp; I won't get into the differences, but
to avoid confusion, they came up with a new name (an alias, if you
will; how ironic) for the old-style user-defined data types, which better
reflects what they actually do: alias types. &lt;br&gt;
&lt;/p&gt;

&lt;p&gt;In general, the thinking behind &lt;strike&gt;user-defined data types&lt;/strike&gt; alias types is that you can use this central definition to declare
the properties of a column type across your entire database.&amp;nbsp; For example,
if you wanted to always store e-mail addresses in a VARCHAR(320)
column, you could do this:&lt;/p&gt;


&lt;blockquote&gt;
&lt;table cellpadding="0" cellspacing="0" bgcolor="#eeeeee"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;-moz-background-clip:border;-moz-background-origin:padding;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;&lt;font color="blue"&gt;CREATE TYPE&lt;/font&gt; &lt;font color="black"&gt;[email]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;FROM&amp;nbsp;VARCHAR&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;320&lt;/font&gt;&lt;font color="gray"&gt;)&amp;nbsp;NOT&amp;nbsp;NULL;&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;(In SQL Server 2000, you would use sp_addtype; for this discussion, I'll assume SQL Server 2005 or better.)&lt;/p&gt;


&lt;p&gt;Then you could create a table and procedure like this: &lt;br&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;table cellpadding="0" cellspacing="0" bgcolor="#eeeeee"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;-moz-background-clip:border;-moz-background-origin:padding;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;&lt;font color="blue"&gt;CREATE&amp;nbsp;TABLE&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;dbo.Contacts&lt;br&gt;&lt;/font&gt;&lt;font color="gray"&gt;(&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;ContactID&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;INT&amp;nbsp;PRIMARY&amp;nbsp;KEY&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;EmailAddress [email]&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;UNIQUE&lt;br&gt;&lt;/font&gt;&lt;font color="gray"&gt;);&lt;br&gt;&lt;br&gt;&lt;/font&gt;&lt;font&gt;&lt;font color="blue"&gt;CREATE PROCEDURE &lt;/font&gt;&lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;dbo&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;.&lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;Contact_Create&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;    &lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;@ContactID&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;    &lt;/font&gt;&lt;font&gt;&lt;font&gt;&lt;font&gt;&lt;font color="blue"&gt;INT&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;    &lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;@EmailAddress&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt; &lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;[email]&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;&lt;font&gt;&lt;font&gt;&lt;font color="blue"&gt;AS&lt;br&gt;BEGIN&lt;br&gt;    SET NOCOUNT ON&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;&lt;font&gt;&lt;font&gt;&lt;font color="blue"&gt;&lt;br&gt;    INSERT&lt;/font&gt;&lt;/font&gt;&lt;/font&gt; &lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;dbo.Contacts&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;    (&lt;br&gt;      &lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;ContactID&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;      &lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;EmailAddress&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;    &lt;br&gt;    )&lt;br&gt;    &lt;/font&gt;&lt;font&gt;&lt;font&gt;&lt;font&gt;&lt;font&gt;&lt;font color="gray"&gt;&lt;font&gt;&lt;font&gt;&lt;font color="blue"&gt;SELECT&lt;br&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;      &lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;@ContactID&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;,&lt;br&gt;      &lt;/font&gt;&lt;font&gt;&lt;font color="black"&gt;@EmailAddress&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font&gt;&lt;font&gt;&lt;font&gt;&lt;font&gt;&lt;font color="gray"&gt;&lt;font&gt;&lt;font&gt;&lt;font color="blue"&gt;END&lt;br&gt;GO&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;/font&gt;&lt;font color="gray"&gt;&lt;br&gt;&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;


&lt;p&gt;This would ensure that your developers always use a VARCHAR(320) column for e-mail addresses, because they are instructed to use the [email] data type instead of picking their own at random.&amp;nbsp; This provides consistency throughout your tables, and prevents you from losing data when someone accidentally declares a variable or parameter as VARCHAR(100) or VARCHAR(255).&amp;nbsp; Of course someone can still do that, if they "forget" that they are supposed to use the [email] data type... but SQL Server can't help you solve that problem.&lt;br&gt;&lt;/p&gt;&lt;p&gt;One issue with this approach is that the definition of e-mail address (or at least how you understood it at the time you created the type) can change over time.&amp;nbsp; I know that many people use VARCHAR(128) or VARCHAR(255) for e-mail addresses, even though those are far too short (at least according to the standard).&amp;nbsp; In this example, if you picked a big enough size, it is unlikely to affect you, as the standard hasn't really changed (apart from the inclusion of Far East languages, requiring Unicode).&amp;nbsp; Do you want a real example of a supposedly fixed size data element that has changed?&amp;nbsp; ISBN.&amp;nbsp; I would bet that at one point Barnes &amp;amp; Noble thought it might be a good idea to create an alias type called "ISBN" from CHAR(10) so that people wouldn't be using VARCHAR(10), NVARCHAR(10), VARCHAR(50), VARCHAR(MAX), and other silly ways to define the ISBN column.&amp;nbsp; Then when ISBN-13 codes became standard, they would have regretted doing so.&amp;nbsp;&amp;nbsp; Why?&amp;nbsp; Well, let's try modifying an alias type once it's in use; let's say we need to expand our email type from above to support 350 characters.&amp;nbsp; Our instinct would be to use DDL like this:&lt;br&gt;&lt;/p&gt;


&lt;blockquote&gt;
&lt;table cellpadding="0" cellspacing="0" bgcolor="#eeeeee"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;-moz-background-clip:border;-moz-background-origin:padding;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;&lt;font color="blue"&gt;ALTER&amp;nbsp;TYPE&amp;nbsp;&lt;/font&gt;&lt;font color="black"&gt;[email]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;FROM&amp;nbsp;VARCHAR&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;320&lt;/font&gt;&lt;font color="gray"&gt;)&amp;nbsp;NOT&amp;nbsp;NULL;&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;But we can't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;table cellpadding="0" cellspacing="0" bgcolor="#eeeeee"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;-moz-background-clip:border;-moz-background-origin:padding;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;&lt;font color="red"&gt;Msg 102, Level 15, State 1, Line 1&lt;br&gt;Incorrect syntax near 'TYPE'.&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;In fact, there is no DDL statement that supports ALTER TYPE.&amp;nbsp; (And no, sp_rename or using synonyms won't help you here, nor is there a system procedure called sp_altertype.)&amp;nbsp; So can't we just drop the type and re-create it?&amp;nbsp; You would think you could do the following:&lt;br&gt;&lt;/p&gt;


&lt;blockquote&gt;
&lt;table cellpadding="0" cellspacing="0" bgcolor="#eeeeee"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;-moz-background-clip:border;-moz-background-origin:padding;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;&lt;font color="blue"&gt;DROP TYPE&lt;/font&gt;&lt;font color="black"&gt; [email]&lt;/font&gt;&lt;font color="gray"&gt;;&lt;br&gt;&lt;/font&gt;&lt;font&gt;&lt;font color="blue"&gt;GO&lt;/font&gt;&lt;/font&gt;&lt;br&gt;&lt;font color="blue"&gt;&lt;br&gt;CREATE TYPE&lt;/font&gt;&lt;font color="black"&gt; [email]&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="blue"&gt;FROM&amp;nbsp;VARCHAR&lt;/font&gt;&lt;font color="gray"&gt;(&lt;/font&gt;&lt;font color="black"&gt;350&lt;/font&gt;&lt;font color="gray"&gt;)&amp;nbsp;NOT&amp;nbsp;NULL;&lt;br&gt;&lt;/font&gt;&lt;font&gt;&lt;font color="blue"&gt;GO&lt;/font&gt;&lt;/font&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;


&lt;p&gt;But you get this error message: &lt;br&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;table cellpadding="0" cellspacing="0" bgcolor="#eeeeee"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;-moz-background-clip:border;-moz-background-origin:padding;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;&lt;font color="red"&gt;Msg 3732, Level 16, State 1, Line 1&lt;br&gt;Cannot drop type 'email' because it is being referenced by object 'Contacts'.&lt;br&gt;There may be other objects that reference this type.&lt;/font&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;


&lt;p&gt;You need to follow this process instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;find *all* of the objects that use this alias type (this includes parameters definitions and variable declarations);&lt;/li&gt;

&lt;li&gt;modify them all so that they point at the "regular" type (or a different alias type);&lt;/li&gt;

&lt;li&gt;drop the alias type using DROP TYPE;&lt;/li&gt;

&lt;li&gt;create the alias type with the new definition;&lt;/li&gt;

&lt;li&gt;modify all of your objects to point back at the original alias type again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now take the case with ISBN, which might also serve as the primary key and have related tables scattered throughout the database.&amp;nbsp; In addition to the above steps, before you start step 2 above, you will also have to temporarily drop all of the constraints, and drop them in the correct order.&amp;nbsp; &lt;/p&gt;

&lt;p&gt;Once you have finished all 5 (or 6) of these steps, why not just leave them that way, and point your users at your data dictionary and/or documentation to ensure that they choose the correct data type?&amp;nbsp; At least then when you have data type changes next time, you can phase the new type definition in gradually, instead of an all-or-nothing change.&lt;br&gt;&lt;/p&gt;

&lt;p&gt;Further to this, what if you need to use the same custom data type in multiple databases?&amp;nbsp; Now,
in addition to the above complications, you must also synchronize the alias types common to all of your
databases, or just hope and pray that their definitions will never change.
&lt;/p&gt;

&lt;p&gt;There are other complications with using alias types that you won't come across when using the built-in types.&amp;nbsp; For example, you cannot use CONVERT() or CAST() to change a column, variable or literal to an alias type; if you do, you get:&lt;/p&gt;


&lt;blockquote&gt;
&lt;table cellpadding="0" cellspacing="0" bgcolor="#eeeeee"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;-moz-background-clip:border;-moz-background-origin:padding;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;&lt;font color="red"&gt;Msg 243, Level 16, State 2, Line 1&lt;br&gt;Type email is not a defined system type.&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;You also don't get syntax highlighting in Management Studio, so unlike other data type names, your alias type names will appear black instead of blue in query editor windows. &lt;/p&gt;&lt;p&gt;You may also experience issues when you use external or 3rd party providers or drivers to access stored procedures with these alias types, or try to data-bind, or implement Entity Framework or Linq 2 SQL solutions.&amp;nbsp; I'll admit I haven't tried it, but I envision the integration will not be 100% seamless. &lt;br&gt;&lt;/p&gt;
Another anomaly with alias types is that you cannot declare #temp tables that use them, unless the alias type also exists in tempdb (but you can use them in @table variables, which also use tempdb; go figure):

&lt;blockquote&gt;
&lt;table cellpadding="0" cellspacing="0" bgcolor="#eeeeee"&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre style="padding:10px 20px;-moz-background-clip:border;-moz-background-origin:padding;font-size:12px;font-family:consolas,lucida console,courier new,courier;-moz-background-inline-policy:continuous;"&gt;&lt;font color="red"&gt;Msg 2715, Level 16, State 7, Line 1&lt;br&gt;Column, parameter, or variable #1: Cannot find data type email.&lt;/font&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/blockquote&gt;

&lt;p&gt;
For further clarification, you can select *into* a new #temp table from a source that includes a column with an alias type, however the #temp table inherits the properties of the base data type (so in the above example, the column would be defined as VARCHAR(320), not email). &lt;/p&gt;
&lt;p&gt;I hope I have demonstrated that, while tempting, the benefits of alias types are far outweighed by the potential problems they can cause down the road.&amp;nbsp; In fact, I am hard-pressed to think of a single implementation of an alias type that would provide any tangible benefits at all.&amp;nbsp; CLR UDTs are a different story, as these can be much more complex and can include additional features like properties and methods.&amp;nbsp; And since the CLR UDTs are based in .NET, you can implement validation rules using real regular expressions.&amp;nbsp; Of course, as with any complex feature, they come with a set of restrictions and prerequisites as well, so I will leave it as an exercise to the reader to determine how much of an advantage these provide *for you* over alias types.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;i&gt;I am working on a series of "Bad habits to kick" articles, in an
effort to motivate people to drop some of the things that I hate to see
when I inherit code.&amp;nbsp; Up next: &lt;a href="http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/bad-habits-to-kick-mishandling-date-range-queries.aspx" title="http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/bad-habits-to-kick-mishandling-date-range-queries.aspx" target="_blank"&gt;mis-handling date / range queries&lt;/a&gt;.&lt;/i&gt;&lt;br&gt;&lt;/p&gt;</description></item></channel></rss>