CHAPTER 29 Creating and Managing User-Defined Functions Creating and Using CLR Functions Prior to SQL Server 2005, the only way to extend the functionality of SQL Server beyond what was
Trang 1CHAPTER 29 Creating and Managing User-Defined Functions
Creating and Using CLR Functions
Prior to SQL Server 2005, the only way to extend the functionality of SQL Server beyond
what was available using the T-SQL language was to create extended stored procedures or
Component Object Model (COM) components The main problem with these types of
extensions was that if not written very carefully, they could have an adverse impact on
the reliability and security of SQL Server For example, extended stored procedures are
implemented as DLLs that run in the same memory space as SQL Server An access
viola-tion raised in a poorly written extended stored procedure could crash SQL Server itself
In addition, neither extended stored procedures nor COM components allow you to create
custom user-defined functions that can be written in any programming language other
than T-SQL, which has a limited command set for operations such as complex string
comparison and manipulation and complex numeric computations
In SQL Server 2008, you can write custom user-defined functions in any Microsoft NET
Framework programming language, such as Microsoft Visual Basic NET or Microsoft
Visual C# SQL Server supports both scalar and table-valued CLR functions, as well as CLR
user-defined aggregate functions These extensions written in the CLR are much more
secure and reliable than extended stored procedures or COM components
For information on the methods and tools to actually create and compile CLR
user-defined functions, see Chapter 46 This chapter focuses only on how to install and use
CLR functions in a SQL Server database
NOTE
The CLR function examples presented in the following sections are provided as
illustra-tions only The sample code will not execute successfully because the underlying CLR
assemblies have not been provided
Adding CLR Functions to a Database
If you’ve already created and compiled a CLR function, your next task is to install that CLR
function in the database The first step in this process is to copy the NET assembly to a
location that SQL Server can access, and then you need to load it into SQL Server by
creat-ing an assembly The syntax for the CREATE ASSEMBLY command is as follows:
CREATE ASSEMBLY AssemblyName [AUTHORIZATION Owner_name]
FROM { <client_assembly_specifier> | <assembly_bits> [ , n ] }
[WITH PERMISSION_SET = (SAFE | EXTERNAL_ACCESS | UNSAFE) ]
AssemblyName is the name of the assembly client_assembly_specifier specifies the local
path or network location where the assembly being uploaded is located, and also the
manifest filename that corresponds to the assembly It can be expressed as a fixed string or
an expression evaluating to a fixed string, with variables The path can be a local path, but
Trang 2ptg Creating and Using CLR Functions
The WITH clause is optional, and it defaults to SAFE Marking an assembly with the SAFE
permission set indicates that no external resources (for example, the Registry, Web
services, file I/O) are going to be accessed
The CREATE ASSEMBLY command fails if it is marked as SAFE and assemblies like System.IO
are referenced Also, if anything causes a permission demand for executing similar
opera-tions, an exception is thrown at runtime
Marking an assembly with the EXTERNAL_ACCESS permission set tells SQL Server that it will
use resources such as networking, files, and so forth Assemblies such as
System.Web.Services (but not System.Web) can be referenced with this set To create an
EXTERNAL_ACCESS assembly, the creator must have EXTERN ACCESS_permission
Marking an assembly with the UNSAFE permission set tells SQL Server that not only might
external resources be used, but unmanaged code may be invoked from managed code An
UNSAFE assembly can potentially undermine the security of either SQL Server or the CLR
Only members of the sysadmin role can create UNSAFE assemblies
After the assembly is created, the next step is to associate the method within the assembly
with a user-defined function You do this with the CREATE FUNCTION command, using the
following syntax:
CREATE FUNCTION [ schema_name ] function_name
( [ { @parameter_name [AS] [ schema_name.]scalar_datatype [ = default ] }
[ , n ] ] )
RETURNS { return_data_type | TABLE ( { column_name data_type } [ , n ] ) }
[ WITH { [ , RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT ]
[ , EXECUTE_AS_Clause ] } ]
[ AS ] EXTERNAL NAME assembly_name.class_name.method_name
After creating the CLR function successfully, you can use it just as you would a T-SQL
func-tion The following example shows how to manually deploy a table-valued CLR function:
CREATE ASSEMBLY fn_EventLog
FROM ‘F:\assemblies\fn_EventLog\fn_eventlog.dll’
WITH PERMISSION_SET = SAFE
GO
CREATE FUNCTION ShowEventLog(@logname nvarchar(100))
RETURNS TABLE (logTime datetime,
Message nvarchar(4000), Category nvarchar(4000), InstanceId bigint) AS
EXTERNAL NAME fn_EventLog.TabularEventLog.InitMethod
GO
SELECT * FROM dbo.ReadEventLog(N’System’) as T
go
Trang 3CHAPTER 29 Creating and Managing User-Defined Functions
NOTE
The preceding examples show the steps involved in manually registering an assembly
and creating a CLR function If you use Visual Studio’s Deploy feature, the
CREATE/ALTER ASSEMBLY and CREATE FUNCTION commands are issued automatically
by Visual Studio For more details on using Visual Studio to create and deploy
user-defined CLR functions, see Chapter 46
Deciding Between Using T-SQL or CLR Functions
One question that often comes up regarding user-defined functions is whether it’s better
to develop functions in T-SQL or in the CLR The answer really depends on the situation
and what the function will be doing
The general rule of thumb is that if the function will be performing data access or large
set-oriented operations with little or no complex procedural logic, it’s better to create that
function in T-SQL to get the best performance The reason is that T-SQL works more
closely with the data and doesn’t require multiple transitions between the CLR and SQL
Server engine
On the other hand, most benchmarks have shown that the CLR performs better than
T-SQL for functions that require a high level of computation or text manipulation The
CLR offers much richer APIs that provide capabilities not available in T-SQL for
opera-tions such as text manipulation, cryptography, I/O operaopera-tions, data formatting, and
invoking of web services For example, T-SQL provides only rudimentary string
manipula-tion capabilities, whereas the NET Framework supports capabilities such as regular
expressions, which are much more powerful for pattern matching and replacement than
the T-SQL replace() function
Another good candidate for CLR functions is user-defined aggregate functions
User-defined aggregate functions cannot be User-defined in T-SQL To compute an aggregate value
over a group in T-SQL, you would have to retrieve the values as a result set and then
enumerate over the result set, using a cursor to generate the aggregate This results in slow
and complicated code With CLR user-defined aggregate functions, you need to
imple-ment the code only for the accumulation logic The query processor manages the
itera-tion, and any user-defined aggregates referenced by the query are automatically
accumulated and returned with the query result set This approach can be orders of
magnitude faster than using cursors, and it is comparable to using SQL Server built-in
aggregate functions For example, the following shows how you might use a user-defined
aggregate function that aggregates all the authors for a specific BookId into a
comma-separated list:
use bigpubs2008
go
SELECT t.Title_ID, count(*), dbo.CommaList(a.au_lname) as AuthorNames
Trang 4ptg Summary
JOIN Titles t on ta.title_id = t.title_id
GROUP BY t.title_id
having count(*) > 2
go
Title_ID AuthorNames
-
-TC7777 O’Leary, Gringlesby, Yokomoto
NOTE
The preceding example will not execute successfully because we have not created the
CommaList() CLR function It is provided merely as an example showing how such a
function could be used if it was created
In a nutshell, performance tests have generally shown that T-SQL generally performs
better for standard CRUD (create, read, update, delete) operations, whereas CLR code
performs better for complex math, string manipulation, and other tasks that go beyond
data access
Summary
User-defined functions in SQL Server 2008 allow you to create reusable routines that can
help make your SQL code more straightforward and efficient
In this chapter, you saw how to create and modify scalar functions and inline and
multi-statement table-valued functions and how to invoke and use them in queries Scalar
func-tions can be used to perform more complex operafunc-tions than those provided by the
built-in scalar functions Table-valued functions provide a way to create what are
essen-tially parameterized views, and you can include them inline in your queries, just as you
would in a table or view
With the introduction of CLR-based functions, SQL Server 2008 greatly increases the
power and capabilities of user-defined functions, and CLR functions can also provide
performance improvements over T-SQL functions that need to perform complex
computa-tions or string manipulacomputa-tions
In the next chapter, you learn how to create and manage triggers in SQL Server 2008
Trang 5This page intentionally left blank
Trang 6CHAPTER 30 Creating and Managing
Triggers
IN THIS CHAPTER
What’s New in Creating and Managing Triggers
Using DML Triggers Using DDL Triggers Using CLR Triggers Using Nested Triggers Using Recursive Triggers
auto-matically based on the occurrence of a database event Prior
to SQL Server 2005, the database events that fired triggers
were based only on data manipulations, such as insertions,
updates, or deletions Triggers in SQL Server 2005 and SQL
Server 2008 can also fire on events related to the definition
of database objects The two types of triggering events are
referred to as Data Manipulation Language (DML) and Data
Definition Language (DDL) events
Most of the benefits derived from triggers are based on their
event-driven nature Once created, triggers automatically
fire (without user intervention) based on an event in the
database This differs from other database code, which must
be called explicitly in order to execute
Say, for example, that you would like to keep track of
historical changes to the data in several key tables in a
data-base Whenever a change is made to the data in the tables,
you would like to put a copy of the data in a historical table
before the change is made You could accomplish this via
the application code that is making the change to the data
The application code could copy the data to the history
table before the change occurs and then execute the actual
change You could also manage this in other ways, such as
by using stored procedures that are called by the
applica-tion and subsequently insert records into the history tables
These solutions work, but a trigger-based solution has some
distinct advantages over them With a trigger-based
solu-tion, a trigger can act on any modifications to the key
tables In the case of the history table example, triggers
would automatically insert records into the history table
whenever a modification was made to the data This would
Trang 7CHAPTER 30 Creating and Managing Triggers
all happen within the scope of the original transaction and would write history records for
any changes made to these tables, including ad hoc changes that may have been made
directly to the tables outside the application
This is just one example of the benefits and uses of triggers This chapter discusses the
different types of triggers and further benefits they can provide
What’s New in Creating and Managing Triggers
The features and methods available for creating and managing triggers are essentially the
same in SQL Server 2008 as they were in SQL Server 2005 The upside to this is that you
can take the knowledge and skills that you have with SQL Server 2005 and apply them
directly to SQL Server 2008
One area that has had some minor changes in SQL Server 2008 relates to events captured
by DDL triggers In SQL Server 2008 more system stored procedures that perform DDL-like
operations fire DDL triggers and event notification In SQL Server 2005 certain system
stored procedures would fire DDL triggers, but there are many more included in SQL
Server 2008 For example, the execution of the sp_rename stored procedure would not fire
a DDL trigger in SQL Server 2005, but it does in SQL Server 2008 Refer to the “Using DDL
Triggers” section later in this chapter for a complete list of DDL statements and system
stored procedures that DDL triggers respond to
Using DML Triggers
DML triggers are invoked when a DML event occurs in the database DML events
manipulate or modify the data in a table or view These events include insertions,
updates, and deletions
DML triggers are powerful objects for maintaining database integrity and consistency
They are able to evaluate data before it has been committed to the database During this
evaluation period, these triggers can perform a myriad of actions, including the following:
Compare before and after versions of data
Roll back invalid modifications
Read from other tables, including those in other databases
Modify other tables, including those in other databases
Execute local and remote stored procedures
Based on the nature of these actions, triggers were originally used in many cases to
enforce referential integrity Triggers were used when foreign key columns in one table
had to be validated against primary keys or unique index values in another table The
Trang 8Using DML Triggers
The advent of declarative referential integrity (DRI) diminished the need for referential
integrity triggers DRI is now generally implemented with database objects such as foreign
key constraints that perform the referential integrity validation internally Because of this,
triggers generally handle more complex integrity concepts and enforce restrictions that
cannot be handled through data types, constraints, defaults, or rules Following are some
examples of trigger uses:
Maintenance of duplicate and derived data—A denormalized database generally
introduces data duplications (that is, redundancy) Instead of exposing this
redun-dancy to end users and programmers, you can keep the data in sync by using
trig-gers If the derived data is allowed to be out of sync, you might want to consider
handling refreshes through batch processing or some other method instead
Complex column constraints—If a column constraint depends on other rows
within the same table or rows in other tables, using a trigger is the best method for
that column constraint
Complex defaults—You can use a trigger to generate default values based on data
in other columns, rows, or tables
Inter-database referential integrity—When related tables are found in two
differ-ent databases, you can use triggers to ensure referdiffer-ential integrity across the databases
You can use stored procedures for all these tasks, but the advantage of using triggers is
that they fire on all data modifications Stored procedure code or SQL in application code
is executed only when it makes the data modifications With triggers, all data
modifica-tions are subject to the trigger code, except for bulk copy and a few other nonlogged
actions Even if a user utilizes an ad hoc tool, such as SQL Server Management Studio
(SSMS) to make changes to the database, the integrity rules cannot be bypassed after the
trigger is in place
NOTE
Triggers and stored procedures are not mutually exclusive You can have both triggers
and stored procedures that perform modifications and validation on that same table If
desired, you can perform some tasks via triggers and other tasks via stored procedures
Creating DML Triggers
You can create and manage triggers in SQL Server Management Studio or directly via
Transact-SQL (T-SQL) statements The Object Explorer in SSMS provides a simple means of
creating triggers that you can use to generate the underlying T-SQL code You expand the
Object Explorer tree to the user table level and then right-click the Triggers node When
you select the New Trigger option, as shown in Figure 30.1, the trigger template shown in
the right pane of Figure 30.1 appears
Trang 9ptg CHAPTER 30 Creating and Managing Triggers
FIGURE 30.1 Using SSMS to create triggers
You can populate the trigger template by manually editing it, or you can select the Query
menu option Specify Values for Template Parameters When you select Specify Values for
Template Parameters, a screen appears, allowing you to fill in the basic values for the
trigger, including the table that the trigger will be on and the events to respond to
You can launch the New Trigger template and other templates related to triggers via the
Template Explorer, which you open by selecting View, Template Explorer in SSMS Figure
30.2 shows a partial list of the available templates, including those related to triggers
All the trigger templates provide a basic framework for you to create a trigger, but the core
logic is up to you Existing triggers or sample triggers are often good alternatives to the
templates because they offer more of the core logic You can right-click a trigger in the
Object Explorer and select the Script Trigger As option This option contains several
differ-ent methods to script the trigger After you script a trigger, you can modify it as necessary
to meet your needs
TIP
Using the sys.triggers catalog view is a good way to list all the triggers in a
data-base To use it, you simply open a new query editor window in SSMS and select all the
rows from the view as shown in the following example:
Trang 10Using DML Triggers
FIGURE 30.2 The Template Explorer
After you have a basic trigger template, you can code the trigger, with limited restrictions
Almost every T-SQL statement you would use in a SQL batch or stored procedure is also
available for use in the trigger code However, you cannot use the following commands in
a DML trigger:
ALTER DATABASE
CREATE DATABASE
DISK RESIZE
DROP DATABASE
LOAD DATABASE and LOAD LOG
RECONFIGURE
RESTORE DATABASE and RESTORE LOG
The following sections describe the different types of DML triggers that can be coded and
some of their common uses
Using AFTER Triggers
An AFTER trigger is the original mechanism that SQL Server created to provide an
auto-mated response to data modifications Prior to the release of SQL Server 2000, the AFTER
trigger was the only type of trigger, and the word AFTER was rarely used in its name Any
trigger written for prior versions of SQL Server or documentation referring to these triggers
is for AFTER triggers
SQL Server 2000 introduced a new type of trigger called an INSTEAD OF trigger This trigger
is discussed later in the section titled “INSTEAD OF Triggers.” The introduction of that new