Beginning Microsoft SQL Server 2008 ... - S3 Tech Training
Beginning Microsoft SQL Server 2008 ... - S3 Tech Training Beginning Microsoft SQL Server 2008 ... - S3 Tech Training
Chapter 13: User-Defined Functions CREATE FUNCTION dbo.PriceDifference(@Price money) RETURNS money AS BEGIN RETURN @Price - dbo.AveragePrice(); END Notice that it’s completely legal to embed one UDF in another one. Note that the WITH SCHEMABINDING option works for functions just the way that it did for views — if a function is built using schema-binding, then any object that function depends on cannot be altered or dropped without first removing the schema-bound function. In this case, schema-binding wasn’t really necessary, but I wanted to point out its usage and also prepare this example for something we’re going to do with it a little later in the chapter. Now let’s run our query using the new functions instead of the old subquery model: USE AdventureWorks2008 SELECT Name, ListPrice, dbo.AveragePrice() AS Average, dbo.PriceDifference(ListPrice) AS Difference FROM Production.Product WHERE ProductSubCategoryID = 1; -- The Mountain Bikes Sub-cat This yields us the same results we had with our subquery. Note that, beyond the readability issue, we also get the added benefit of reuse out of this. For a little example like this, it probably doesn’t seem like a big deal, but as your functions become more complex, it can be quite a time saver. UDFs That Retur n a Table 416 User-defined functions in SQL Server are not limited to just returning scalar values. They can return something far more interesting — tables. Now, while the possible impacts of this are sinking in on you, I’ll go ahead and add that the table that is returned is, for the most part, usable much as any other table is. You can perform a JOIN against it and even apply WHERE conditions against the results. It’s very cool stuff indeed. To make the change to using a table as a return value is not hard at all — a table is just like any other SQL Server data type as far as a UDF is concerned. To illustrate this, we’ll build a relatively simple one to start: USE AdventureWorks2008 GO CREATE FUNCTION dbo.fnContactList() RETURNS TABLE
AS RETURN (SELECT BusinessEntityID, LastName + ‘, ‘ + FirstName AS Name FROM Person.Person); GO This function returns a table of selected records and does a little formatting — joining the last and first names, and separating them with a comma. At this point, we’re ready to use our function just as we would use a table: SELECT * FROM dbo.fnContactList(); Now, let’s add a bit more fun into things. What we did with this table up to this point could have been done just as easily — more easily, in fact — with a view. But what if we wanted to parameterize a view? What if, for example, we wanted to accept last-name input to filter our results (without having to manually put in our own WHERE clause)? It might look something like this: --CREATE our view CREATE VIEW vFullContactName AS SELECT p.BusinessEntityID, LastName + ‘, ‘ + FirstName AS Name, ea.EmailAddress FROM Person.Person as p LEFT OUTER JOIN Person.EmailAddress ea ON ea.BusinessEntityID = p.BusinessEntityID; GO This would yield us what was asked for, with a twist. We can’t parameterize things right in the view itself, so we’re going to have to include a WHERE clause in our query: SELECT * FROM vFullContactName WHERE Name LIKE ‘Ad%’; This should get you results that look something like this: BusinessEntityID Name EmailAddress ----------------------------------------------------------------------------------- 67 Adams, Jay jay0@adventure-works.com 301 Adams, Frances frances0@adventure-works.com 305 Adams, Carla carla0@adventure-works.com … … 16901 Adams, Adam adam46@adventure-works.com 16902 Adams, Eric eric57@adventure-works.com 16910 Adams, Jackson jackson47@adventure-works.com (87 row(s) affected) Chapter 13: User-Defined Functions 417
- Page 403: Chapter 11: Writing Scripts and Bat
- Page 406 and 407: Chapter 12: Stored Procedures Creat
- Page 408 and 409: Chapter 12: Stored Procedures Dropp
- Page 410 and 411: Chapter 12: Stored Procedures Suppl
- Page 412 and 413: Chapter 12: Stored Procedures 374 [
- Page 414 and 415: Chapter 12: Stored Procedures Confi
- Page 416 and 417: Chapter 12: Stored Procedures Now,
- Page 418 and 419: Chapter 12: Stored Procedures SQL S
- Page 420 and 421: Chapter 12: Stored Procedures 382 c
- Page 422 and 423: Chapter 12: Stored Procedures It wo
- Page 424 and 425: Chapter 12: Stored Procedures 386 r
- Page 426 and 427: Chapter 12: Stored Procedures 388 -
- Page 428 and 429: Chapter 12: Stored Procedures Note
- Page 430 and 431: Chapter 12: Stored Procedures 392 n
- Page 432 and 433: Chapter 12: Stored Procedures All t
- Page 434 and 435: Chapter 12: Stored Procedures Sproc
- Page 436 and 437: Chapter 12: Stored Procedures When
- Page 438 and 439: Chapter 12: Stored Procedures 400 @
- Page 440 and 441: Chapter 12: Stored Procedures I’d
- Page 442 and 443: Chapter 12: Stored Procedures match
- Page 444 and 445: Chapter 12: Stored Procedures There
- Page 446 and 447: Chapter 12: Stored Procedures 408 f
- Page 449 and 450: 13 User-Defined Functions Well, her
- Page 451 and 452: types!), except for BLOBs, cursors,
- Page 453: We get back the same set as with th
- Page 457 and 458: in your relational database. These
- Page 459 and 460: AS BEGIN ( EmployeeID int NOT NULL,
- Page 461 and 462: So, as you can see, we can actually
- Page 463 and 464: Despite being schema-bound, this on
- Page 465 and 466: 14 Transactions and Locks This is o
- Page 467 and 468: we are unable or do not want to com
- Page 469 and 470: Figure 14-1 Data needed Data in cac
- Page 471 and 472: Transaction 4 This transaction wasn
- Page 473 and 474: Oops — problem!!! Transaction 2 h
- Page 475 and 476: The only cure for this is setting y
- Page 477 and 478: Exclusive Locks Exclusive locks are
- Page 479 and 480: Also: ❑ The Sch-S is compatible w
- Page 481 and 482: The syntax for switching between th
- Page 483 and 484: As with most things in life, howeve
- Page 485 and 486: purchased. Process 2 records sales;
- Page 487: Chapter 14: Transactions and Locks
- Page 490 and 491: Chapter 15: Triggers the world’s
- Page 492 and 493: Chapter 15: Triggers WITH ENCRYPTIO
- Page 494 and 495: Chapter 15: Triggers FOR|AFTER The
- Page 496 and 497: Chapter 15: Triggers 458 To illustr
- Page 498 and 499: Chapter 15: Triggers 460 IF EXISTS
- Page 500 and 501: Chapter 15: Triggers ❑ Feeding de
- Page 502 and 503: Chapter 15: Triggers Trigger Firing
Chapter 13: User-Defined Functions<br />
CREATE FUNCTION dbo.PriceDifference(@Price money)<br />
RETURNS money<br />
AS<br />
BEGIN<br />
RETURN @Price - dbo.AveragePrice();<br />
END<br />
Notice that it’s completely legal to embed one UDF in another one.<br />
Note that the WITH SCHEMABINDING option works for functions just the way that it did for views — if<br />
a function is built using schema-binding, then any object that function depends on cannot be altered or<br />
dropped without first removing the schema-bound function. In this case, schema-binding wasn’t really<br />
necessary, but I wanted to point out its usage and also prepare this example for something we’re going<br />
to do with it a little later in the chapter.<br />
Now let’s run our query using the new functions instead of the old subquery model:<br />
USE AdventureWorks<strong>2008</strong><br />
SELECT Name,<br />
ListPrice,<br />
dbo.AveragePrice() AS Average,<br />
dbo.PriceDifference(ListPrice) AS Difference<br />
FROM Production.Product<br />
WHERE ProductSubCategoryID = 1; -- The Mountain Bikes Sub-cat<br />
This yields us the same results we had with our subquery.<br />
Note that, beyond the readability issue, we also get the added benefit of reuse out of this. For a little<br />
example like this, it probably doesn’t seem like a big deal, but as your functions become more complex,<br />
it can be quite a time saver.<br />
UDFs That Retur n a Table<br />
416<br />
User-defined functions in <strong>SQL</strong> <strong>Server</strong> are not limited to just returning scalar values. They can return<br />
something far more interesting — tables. Now, while the possible impacts of this are sinking in on you,<br />
I’ll go ahead and add that the table that is returned is, for the most part, usable much as any other table<br />
is. You can perform a JOIN against it and even apply WHERE conditions against the results. It’s very cool<br />
stuff indeed.<br />
To make the change to using a table as a return value is not hard at all — a table is just like any other<br />
<strong>SQL</strong> <strong>Server</strong> data type as far as a UDF is concerned. To illustrate this, we’ll build a relatively simple one<br />
to start:<br />
USE AdventureWorks<strong>2008</strong><br />
GO<br />
CREATE FUNCTION dbo.fnContactList()<br />
RETURNS TABLE