1. Trang chủ
  2. » Công Nghệ Thông Tin

Hướng dẫn học Microsoft SQL Server 2008 part 67 pptx

10 246 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 1,13 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Building User-DefinedFunctions IN THIS CHAPTER Creating scalar functions Replacing views with inline table-valued functions Using complex code within multi-statement table-valued functio

Trang 1

Proc A Raiserror Select from A

#temp table

(insert…exec) (try…catch)

Proc B

DML Select

exec

exec

Result set from B

Raiserror from B

Output Parameters

Return

Return

Result set from B Raiserror Output Parameters

Best Practice

With every returned record set, SQL Server will, by default, also send a message stating the number of

rows affected or returned Not only is this a nuisance, but I have found in my informal testing that it

can slow a query by up to 17 percent depending on the query’s complexity

Therefore, get into the habit of beginning every stored procedure with the following code:

CREATE PROC MyProc

AS

SET NOCOUNT ON;

Summary

Using stored procedures is a way to save and optimize batches Stored procedures are compiled and

stored in memory the first time they are executed No method is faster at executing SQL commands, or

more popular for moving the processing close to the data Like a batch, a stored procedure can return a

record set by simply executing aSELECTcommand

The next chapter covers user-defined functions, which combine the benefits of stored procedures with

the benefits of views at the cost of portability

Trang 2

Building User-Defined

Functions

IN THIS CHAPTER Creating scalar functions Replacing views with inline table-valued functions Using complex code within multi-statement table-valued functions to generate a result set

SQL Server 2000 introduced user-defined functions (UDFs), and the SQL

Server community was initially slow to adopt them Nevertheless, UDFs

were my personal favorite new feature in SQL Server 2000, and I still use

them frequently

The community discovered that UDFs can be used to embed complex T-SQL

logic within a query, and problems that were impossible or required cursors

could now be solved with UDFs The result is that UDFs have become a favorite

tool in the toolbox of any serious SQL Server database developer

The benefits of UDFs can be easily listed:

■ UDFs can be used to embed complex logic within a query This is huge

I’ve solved several nasty problems using user-defined functions

■ UDFs can be used to create new functions for complex expressions

■ UDFs offer the benefits of views because they can be used within

theFROMclause of aSELECTstatement or an expression, and they

can be schema-bound In addition, user-defined functions can accept

parameters, whereas views cannot

■ UDFs offer the benefits of stored procedures because they are compiled

and optimized in the same way

The chief argument against developing with user-defined functions has to do with

potential performance issues if they’re misused Any function, user-defined or

system that must be executed for every row in aWHEREclause will cripple

performance (see the sidebar on algebra in Chapter 8, ‘‘Introducing Basic

Query Flow.’’)

User-defined functions come in three distinct types (as shown in Figure 25-1.)

Management Studio groups inline table-valued functions with multi-statement

table-valued functions:

■ Scalar functions that return a single value

Trang 3

User-defined functions haven’t changed much since they were introduced in SQL Server 2000 If you’re

upgrading to SQL Server 2008 directly from SQL Server 2000, then it’s worth knowing that the APPLY

keyword, covered later in this chapter, was added in SQL Server 2005

Microsoft system functions are changing When they were introduced in SQL Server 2000, system functions

were all prefixed with a double colon, such as ::fn_SystemFunction The double colon has been

deprecated and will be disabled in a future version of SQL Server Instead, system functions are now in the

sys.schema — for example, sys.fn_SystemFunction

FIGURE 25-1

Management Studio’s Object Explorer lists all the user-defined functions within a database, organized

by table-valued and scalar-valued

Trang 4

Andrew Novick, who regularly presents about UDFs at user groups and SQL conferences,

has compiled a great resource of sample UDFs His website is www.novicksoftware.com

Scalar Functions

A scalar function is one that returns a single specific value The function can accept multiple parameters,

perform a calculation, and then return a single value For example, a scalar function could accept three

parameters, perform a calculation, and return the answer

Within the code of a scalar function, the value is passed back through the function by means of a

RETURNcommand Every possible codepath in the user-defined function should conclude with

aRETURNcommand

Scalar user-defined functions may be used within any expressions in SQL Server, even

expres-sions within check constraints (although I don’t recommend scalar function within check

constraints because that extends the duration of the transaction and it is difficult to locate and

maintain later)

Limitations

The scalar function must be deterministic, meaning it must repeatedly return the same value for

the same input parameters For this reason, nondeterministic functions — such asnewid()and

rand()— are not allowed within scalar functions Writing a UDF to return a random row is out of the

question

User-defined scalar functions are not permitted to update the database or callDBCCcommands, with

the single exception that they may update table variables They cannot return BLOB (binary large

object) data such astext,ntext,timestamp, andimagedata-type variables, nor can they return

table variables orcursordata types For error handling, UDFs may not includeTRY .CATCHor

RAISERROR

A user-defined function may call other user-defined functions nesting up to 32 levels deep, or it can call

itself recursively up to 32 levels deep before it blows up

Creating a scalar function

User-defined functions are created, altered, or dropped with the same DDL commands used for other

objects, although the syntax is slightly different to allow for the return value:

CREATE FUNCTION FunctionName (InputParameters)

RETURNS DataType

AS

BEGIN;

Code;

RETURN Expression;

END;

Trang 5

eter includes a default value:

CREATE FUNCTION dbo.fsMultiply (@A INT, @B INT = 3)

RETURNS INT AS

BEGIN;

RETURN @A * @B;

END;

go SELECT dbo.fsMultiply (3,4),

dbo.fsMultiply (7, DEFAULT);

Result:

While I’m not a stickler for naming conventions (as long as they’re consistent), I can under-stand the practice of prefacing user-defined functions with an f

For a more complex scalar user-defined function, thefGetPricefunction from theOBXKitessample

database returns a single result via an output parameter It’s just a variation of thepGetPricestored

procedure Both the stored procedure and function determine the correct price for any given date and

for any customer discount Because the task returns a single value, calculating the price is a prime

candi-date for a scalar user-defined function As a function, it can be plugged into any query, whereas a stored

procedure is more difficult to use as a building block in other code

The function uses the same internal code as the stored procedure, except that the@CurrPriceis

passed back through the finalRETURNinstead of an output variable The function uses a default value

of NULLfor the contact code Here is the code for thefsGetPriceuser-defined scalar function:

CREATE FUNCTION fsGetPrice (

@Code CHAR(10),

@PriceDate DATETIME,

@ContactCode CHAR(15) = NULL) RETURNS MONEY

AS BEGIN;

DECLARE @CurrPrice MONEY ; DECLARE @DiscountPercent NUMERIC (4,2);

set the discount percent

Trang 6

if no customer lookup then it’s zilch discount

SELECT @DiscountPercent = CustomerType.DiscountPercent

FROM dbo.Contact

JOIN dbo.CustomerType

ON contact.CustomerTypeID =

CustomerType.CustomerTypeID WHERE ContactCode = @ContactCode;

IF @DiscountPercent IS NULL

SET @DiscountPercent = 0;

SELECT @CurrPrice = Price * (1-@DiscountPercent)

FROM dbo.Price

JOIN dbo.Product

ON Price.ProductID = Product.ProductID WHERE Code = @Code

AND EffectiveDate =

(SELECT MAX(EffectiveDate)

FROM dbo.Price JOIN dbo.Product

ON Price.ProductID = Product.ProductID WHERE Code = @Code

AND EffectiveDate <= @PriceDate);

RETURN @CurrPrice;

END;

Calling a scalar function

Scalar functions may be used anywhere within any expression that accepts a single value

User-defined scalar functions must always be called by means of at least a two-part name (owner.name) The

following script demonstrates calling thefGetPrice()function withinOBXKites:

USE OBXKites;

SELECT dbo.fsGetPrice(’1006’,CURRENT_TIMESTAMP,DEFAULT),

dbo.fsGetPrice(’1001’,’5/1/2001’,NULL);

Result:

The user-defined scalar function dbo.fTitleCase is created in Chapter 9, ‘‘Data Types,

Expressions, and Scalar Functions,’’ and is available on www.sqlserverbible.com

Inline Table-Valued Functions

The second type of user-defined function, the inline table-valued function, is very similar to a view Both

are wrapped for a storedSELECTstatement An inline table-valued user-defined function retains the

benefits of a view, and adds parameters As with a view, if the SELECTstatement is updateable, then

the function will be updateable

Trang 7

RETURN (Select Statement);

The following inline table-valued user-defined function is functionally equivalent to thevEventList

view created in Chapter 14, ‘‘Projecting Data Through Views.’’

USE CHA2;

go CREATE FUNCTION ftEventList () RETURNS Table

AS RETURN(

SELECT dbo.CustomerType.Name AS Customer, dbo.Customer.LastName, dbo.Customer.FirstName, dbo.Customer.Nickname,

dbo.Event_mm_Customer.ConfirmDate, dbo.Event.Code, dbo.Event.DateBegin, dbo.Tour.Name AS Tour,

dbo.BaseCamp.Name, dbo.Event.Comment FROM dbo.Tour

INNER JOIN dbo.Event

ON dbo.Tour.TourID = dbo.Event.TourID INNER JOIN dbo.Event_mm_Customer

ON dbo.Event.EventID = dbo.Event_mm_Customer.EventID INNER JOIN dbo.Customer

ON dbo.Event_mm_Customer.CustomerID

= dbo.Customer.CustomerID LEFT OUTER JOIN dbo.CustomerType

ON dbo.Customer.CustomerTypeID

= dbo.CustomerType.CustomerTypeID INNER JOIN dbo.BaseCamp

ON dbo.Tour.BaseCampID = dbo.BaseCamp.BaseCampID);

Calling an inline table-valued function

To retrieve data throughftEventList, call the function within theFROMportion of aSELECT

statement:

SELECT LastName, Code, DateBegin

FROM dbo.ftEventList();

Result (abridged):

Trang 8

LastName Code DateBegin

- -

-Anderson 01-003 2001-03-16 00:00:00.000

.

Using parameters

An advantage of inline table-valued functions over views is the function’s ability to include parameters

within the pre-compiledSELECTstatement Views, conversely, do not include parameters, and

restrict-ing the result at runtime is typically achieved by addrestrict-ing aWHEREclause to theSELECTstatement that

calls the view

The following examples compare adding a restriction to the view to using a function parameter The

following view returns the current price list for all products:

USE OBXKites;

go

CREATE VIEW vPricelist

AS

SELECT P.Code, Price.Price

FROM dbo.Price

JOIN dbo.Product P

ON Price.ProductID = P.ProductID

WHERE EffectiveDate =

(SELECT MAX(EffectiveDate)

FROM dbo.Price

WHERE ProductID = P.ProductID

AND EffectiveDate <= CURRENT_TIMESTAMP);

To retrieve the current price for a single product, the callingSELECTstatement adds aWHERE-clause

restriction when calling the view:

SELECT *

FROM vPriceList

WHERE = ‘1001’;

Result:

-

SQL Server internally creates a new SQL statement fromvPricelistand the callingSELECT

state-ment’sWHERE-clause restriction and then generates a query execution plan

Trang 9

SELECT Code, Price.Price FROM dbo.Price

JOIN dbo.Product P

ON Price.ProductID = P.ProductID WHERE EffectiveDate =

(SELECT MAX(EffectiveDate) FROM dbo.Price

WHERE ProductID = P.ProductID

AND EffectiveDate <= @PriceDate) AND (Code = @Code

OR @Code IS NULL) );

If the function is called with default code, then the price for the entered date is returned for all

products:

SELECT * FROM dbo.ftPriceList(DEFAULT, ‘20020220’);

Result:

-

If a product code is passed in the first input parameter, then the pre-compiledSELECTstatement within

the function returns the single product row:

SELECT * FROM dbo.ftPriceList(’1001’, ‘2/20/2002’);

Result:

-

Correlated user-defined functions

TheAPPLYcommand may be used with a table-valued user-defined function so that the UDF accepts a

different parameter value for each corresponding row being processed by the main query

Trang 10

Back in the SQL Server 2000 days, not having this capability was a serious limitation that caused me

a considerable amount of time to work around, so I’m pleased to see that Microsoft added theAPPLY

function in SQL Server 2005

TheAPPLYcommand has two forms The most common form, the CROSS APPLY, has a confusing

name because it operates more like an inner join than a cross join TheCROSS APPLYcommand will

join data from the main query with any table-valued data sets from the user-defined function If no

data is returned from the UDF, then the row from the main query is also not returned, as shown in the

following example:

USE CHA2;

go

CREATE FUNCTION ftEventList2 (@CustomerID INT)

RETURNS Table

AS

RETURN(

SELECT dbo.CustomerType.Name AS Customer,

dbo.Customer.LastName, dbo.Customer.FirstName,

dbo.Customer.Nickname,

dbo.Event_mm_Customer.ConfirmDate, dbo.Event.Code,

dbo.Event.DateBegin, dbo.Tour.Name AS Tour,

dbo.BaseCamp.Name, dbo.Event.Comment

FROM dbo.Tour

INNER JOIN dbo.Event

ON dbo.Tour.TourID = dbo.Event.TourID INNER JOIN dbo.Event_mm_Customer

ON dbo.Event.EventID = dbo.Event_mm_Customer.EventID INNER JOIN dbo.Customer

ON dbo.Event_mm_Customer.CustomerID

= dbo.Customer.CustomerID LEFT OUTER JOIN dbo.CustomerType

ON dbo.Customer.CustomerTypeID

= dbo.CustomerType.CustomerTypeID INNER JOIN dbo.BaseCamp

ON dbo.Tour.BaseCampID = dbo.BaseCamp.BaseCampID

WHERE Customer.CustomerID = @CustomerID

);

SELECT C.LastName, Code, DateBegin, Tour

FROM Customer C

CROSS APPLY ftEventList2(C.CustomerID)

ORDER BY C.LastName;

Result:

- - -

-Anderson 01-003 2001-03-16 00:00:00.000 Amazon Trek

Anderson 01-006 2001-07-03 00:00:00.000 Bahamas Dive

Ngày đăng: 04/07/2014, 09:20

TỪ KHÓA LIÊN QUAN