When planning your implementation of UDTs, consider which methods are needed in the UDT assembly itself, and which methods should be created in separate assemblies and implemented as user-defined functions or stored procedures. Separating methods into separate assemblies allows you to update code without affecting data that may be stored in a UDT column in a table. You can modify UDT assemblies without dropping UDT columns and other dependent objects only when the new definition can read the former values and the signature of the type does not change.
Separating procedural code that may change from the code required to implement the UDT greatly simplifies maintenance. Including only code that is necessary for the UDT to function, and keeping your UDT definitions as simple as possible, reduces the risk that the UDT itself may need to be dropped from the database for code revisions or bug fixes.
The Currency UDT and Currency Conversion Function
The Currency UDT in the AdventureWorks sample database provides a useful example of the recommended way to structure a UDT and its associated functions. The Currency UDT is used for handling money based on the monetary system of a particular culture, and allows for storage of different currency types, such as dollars, euros, and so forth. The UDT class exposes a culture name as a string, and an amount of money as a decimal data type. All of the necessary serialization methods are contained within the assembly defining the class. The function that implements currency conversion from one culture to another is implemented as an external function named ConvertCurrency, and this function is located in a separate assembly. The ConvertCurrency function does its work by retrieving the conversion rate from a table in the AdventureWorks database. If the source of the conversion rates should ever change, or if there should be any other changes to the existing code, the assembly can be easily modified without affecting the Currency UDT.
The code listing for the Currency UDT and ConvertCurrency functions can be found by installing the common language runtime (CLR) samples. For more information, see Considerations for Installing SQL Server Samples and Sample Databases.
Using UDTs Across Databases
UDTs are by definition scoped to a single database. Therefore, a UDT defined in one database cannot be used in a column definition in another database. In order to use UDTs in multiple databases, you must execute the CREATE ASSEMBLY and CREATE TYPE statements in each database on identical assemblies. Assemblies are considered identical if they have the same name, strong name, culture, version, permission set, and binary contents.
Once the UDT is registered and accessible in both databases, you can convert a UDT value from one database for use in another. Identical UDTs can be used across databases in the following scenarios:
-
Calling stored procedure defined in different databases.
-
Querying tables defined in different databases.
-
Selecting UDT data from one database table UDT column and inserting it into a second database with an identical UDT column.
In these situations, any conversion required by the server occurs automatically. You are not able to perform the conversions explicitly using the Transact-SQL CAST or CONVERT functions.
Note that you do not need to take any action for using UDTs when SQL Server Database Engine creates work tables in the tempdb system database. This includes the handling of cursors, table variables, and user-defined table-valued functions that include UDTs and that transparently make use of tempdb. However, if you explicitly create a temporary table in tempdb that defines a UDT column, then the UDT must be registered in tempdb the same way as for a user database.