17.06.2013 Views

Beginning Microsoft SQL Server 2008 ... - S3 Tech Training

Beginning Microsoft SQL Server 2008 ... - S3 Tech Training

Beginning Microsoft SQL Server 2008 ... - S3 Tech Training

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Chapter 13: User-Defined Functions<br />

420<br />

Again, at first glance, this might appear to give us what we want:<br />

EmployeeID JobTitle LastName FirstName<br />

----------- ------------------------------ -------------------- --------------------<br />

5 VP of Engineering Olsen Ken<br />

6 VP of Professional Services Cross Gary<br />

7 VP of Security Lebowski Jeff<br />

(3 row(s) affected)<br />

But, in reality, we have a bit of a problem here. At issue is that we want all of the people in Karla’s reporting<br />

chain — not just those who report to Karla directly, but those who report to people who report to Karla,<br />

and so on. You see that if you look at all the records in our newly created Employee2 table, you’ll find a<br />

number of employees who report to Ken Olsen, but they don’t appear in the results of this query.<br />

OK, so some of the quicker or more experienced among you may now be saying something like, “Hey, no<br />

problem! I’ll just join back to the Employee2 table one more time and get the next level of reports!”<br />

You could probably make this work for such a small data set, or for any situation where the number of<br />

levels of your hierarchy is fixed — but what if the number of hierarchy levels isn’t fixed? What if people<br />

are reporting to Robert Cheechov, and still others report to people under Robert Cheechov — it could go<br />

on virtually forever. Now what? Glad you asked. . . .<br />

What we really need is a function that will return all the levels of the hierarchy below whatever<br />

EmployeeID (and, therefore, ManagerID) we provide — we need a tree. To do this, we have a classic<br />

example of the need for recursion. A block of code is said to recurse any time it calls itself. We saw an<br />

example of this in the previous chapter with our spTriangular stored procedure. Let’s think about this<br />

scenario for a moment:<br />

1. We need to figure out all the people who report to the manager that we want.<br />

2. For each person in Step 1, we need to know who reports to him or her.<br />

3. Repeat Step 2 until there are no more subordinates.<br />

This is recursion all the way. What this means is that we’re going to need several statements to make our<br />

function work: some statements to figure out the current level and at least one more to call the same<br />

function again to get the next lowest level.<br />

Keep in mind that UDFs are going to have the same recursion limits that sprocs had — that is, you can<br />

only go to 32 levels of recursion, so, if you have a chance of running into this limit, you’ll want to get<br />

creative in your code to avoid errors.<br />

Let’s put it together. Notice the couple of changes in the declaration of our function. This time, we need<br />

to associate a name with the return value (in this case, @Reports) — this is required any time you’re<br />

using multiple statements to generate your result. Also, we have to define the table that we will be<br />

returning — this allows <strong>SQL</strong> <strong>Server</strong> to validate whatever we try to insert into that table before it is<br />

returned to the calling routine.<br />

CREATE FUNCTION dbo.fnGetReports<br />

(@EmployeeID AS int)<br />

RETURNS @Reports TABLE

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!