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

Hướng dẫn học Microsoft SQL Server 2008 part 45 ppt

10 128 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 684,96 KB

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

Nội dung

1 Ken Sánchez Chief Executive Officer 267 Karen Berg Application Specialist 265 Ashvini Sharma Network Administrator 268 Ramesh Meyyappan Application Specialist 266 Peter Connelly Networ

Trang 1

FIGURE 17-1

Jean Trenary and her crew are the able Information Service Department at AdventureWorks

1 Ken Sánchez Chief Executive Officer

267 Karen Berg Application Specialist 265

Ashvini Sharma Network Administrator

268 Ramesh Meyyappan Application Specialist 266

Peter Connelly Network Administrator

269 Dan Bacon Application Specialist 272 Janaina Bueno Application Specialist

264 Stephanie Conroy Network Manager

263 Jean Trenary Information Services Manager

270 François Ajenstat Database Administrator 271 Dan Wilson Database Administrator

Adventure Works 2008 Information Service Department

The next query result shows the data from the Information Service Department:

- - - -

-263 Jean Trenary Information Services Manager 1 Ken S´ anchez

Trang 2

To examine one row from the employee perspective, Karen Berg’sBusinessEntityID(PK) is

264 HerManagerIDis 263 That’s theBusinessEntityIDfor Jean Trenary, so Karen reports

to Jean

From the supervisor’s point of view, hisBusinessEntityIDis stored in each of his direct report’s

rows in theManagerIDcolumn For example, Jean Trenary’sBusinessEntityIDis 263, so 263 is

stored in theManagerIDcolumn of everyone who reports directly to her

To maintain referential integrity, theManagerIDcolumn has a foreign key constraint that refers to

theBusinessEntityIDcolumn (the primary key) in the same table, as shown in Figure 17-2

TheManagerIDcolumn allows nulls so that the top person of the organization chart can report to

no one

FIGURE 17-2

The Employee table has a foreign key reference from the ManagerID column to the same table’s

primary key That’s why this pattern is often called theself-join pattern

Trang 3

Restoring AdventureWorks2008’s Adjacency List

With the advent of the HierarchyID data type in SQL Server 2008, Microsoft removed the adjacency

list pattern from AdventureWorks2008 and replaced it with HierarchyID The following script

repairs AdventureWorks2008 and readies the database for experimentation with the adjacency list pattern:

ALTER TABLE HumanResources.Employee

ADD ManagerID INT

CONSTRAINT FK_AdjPairs

FOREIGN KEY(ManagerID)

REFERENCES HumanResources.Employee(BusinessEntityID);

GO

Update new ManagerID Column using join condition to match

UPDATE E

SET ManagerID = M.BusinessEntityID

FROM HumanResources.Employee AS E

JOIN HumanResources.Employee AS M

ON M.OrganizationNode = E.OrganizationNode.GetAncestor(1);

CREATE INDEX IxParentID

ON HumanResources.Employee

(ManagerID)

AdventureWorks2008is now ready for some adjacency list fun with Ken S´anchez, the CEO; Jean Trenary,

the IT Manager; and Franc¸ois Ajenstat, the DBA

Single-level queries

The simplest hierarchical task is to match every node with a direct connection one level up the

hierar-chy In this case, it means listing allAdventureWorks2008employees and their supervisor

The crux of the query is the self-join between two instances of theemployeetable represented

in theLEFT OUTER JOINbetween the employee’s (E)ManagerIDcolumn and the manager’s (M)

BusinessEntityIDcolumn There’s still one physicalemployeetable, but the query contains two

Trang 4

Result (abbreviated):

Employee Manager

.

Of course, listing integers isn’t very useful The next query adds some meat to the bones and fleshes out

the data into a readable result set:

Employees and their Direct Supervisors

SELECT E.BusinessEntityID AS EmpID,

EP.FirstName + ‘ ‘ + EP.LastName AS EmpName, E.JobTitle AS EmpTitle,

E.ManagerID AS [MgrID],

MP.FirstName + ‘ ‘ + MP.LastName AS MgrName, M.JobTitle AS MgrTitle

FROM HumanResources.Employee AS E the employee

JOIN Person.Person AS EP the employee’s contact info

ON E.BusinessEntityID = EP.BusinessEntityID

LEFT OUTER JOIN HumanResources.Employee AS M the mgr(if there is one)

ON E.ManagerID = M.BusinessEntityID

LEFT JOIN Person.Person AS MP the manager’s contact info

ON M.BusinessEntityID = MP.BusinessEntityID

ORDER BY E.ManagerID , E.BusinessEntityID;

The abbreviated result is shown in Figure 17-3

FIGURE 17-3

Results from the query showing every employee and his manager

Trang 5

The reverse of ‘‘find all managers,’’ which searches one level up the hierarchy query, is searching

down the hierarchy This query uses a downward looking join to locate every employee who has

direct reports The key to understanding this query is the self-join between theEmployeetable asM,

representing the managers, and theEmployeeasE, representing the employees:

Every Manager and their direct Reports SELECT M.BusinessEntityID AS ‘MgrID’,

MP.FirstName + ‘ ‘ + MP.LastName AS ‘MgrName’, M.JobTitle AS ‘MgrTitle’,

E.BusinessEntityID AS ‘EmpID’, EP.FirstName + ‘ ‘ + EP.LastName AS ‘EmpName’, E.JobTitle AS EmpTitle

FROM HumanResources.Employee AS M the manager JOIN Person.Person AS MP the manager’s contact info

ON M.BusinessEntityID = MP.BusinessEntityID JOIN HumanResources.Employee AS E the direct report

ON E.ManagerID = M.BusinessEntityID JOIN Person.Person AS EP the manager’s contact info

ON E.BusinessEntityID = EP.BusinessEntityID ORDER BY M.BusinessEntityID

The result is shown in Figure 17-4

FIGURE 17-4

Results of the query showing every manager and his direct reports

Trang 6

WHERE ManagerID IS NOT NULL

GROUP BY ManagerID) AS C

ON M.BusinessEntityID = C.ManagerID;

ORDER BY Manager

Result (abbreviated):

- -

47 Andrew Hill Production Supervisor - WC10 7

192 Brenda Diaz Production Supervisor - WC40 12

273 Brian Welcker Vice President of Sales 3

228 Christian Kleinerman Maintenance Supervisor 4

.

Subtree queries

The preceding queries work well with one level If you need to return all the nodes for two levels,

then you could add another self-join As the number of levels needed increases, the queries become

complex and the query is fixed to a certain number of levels A continuing parade of self-joins is not

the answer

SQL queries should be able to handle any amount of data, so an adjacency list subtree query should be

able to handle any number of levels There are two solutions to the subtree problem when using the

adjacency model: a recursive CTE or a looping user-defined function

Recursive CTE down the hierarchy

The most direct solution to the subtree problem is the recursive common table expression, introduced

in SQL Server 2005 This variant of the CTE (the basic CTE is covered in Chapter 11, ‘‘Including Data

with Subqueries and CTEs’’) uses aUNION ALLand twoSELECTstatements

The firstSELECTstatement defines the anchor node from which the recursion will start, i.e., the top of

the subtree When the recursion starts, the row(s) returned by this query are added to the CTE

The secondSELECTdefines how rows are recursively added to the result set ThisSELECTstatement

joins with the CTE itself — similar to the earlier self-join — and uses theUNION ALLto add the rows

to the output of the CTE The key is that the secondSELECTwill continue to self-join through the

lay-ers of the hierarchy until no more rows are found

The loop stops executing when no more data is returned from the recursive step of the CTE The

first example focuses on the recursive nature of the CTE The firstSELECTin the CTE locates

the employee with aManagerIDof null, which should be the top of the hierarchy The name of

the CTE isOrgPath, so when the second select joins withOrgPathit can find all the related

nodes The CTE continues to execute the secondSELECTfor every level of the hierarchy until the

hierarchy ends:

Find all - Recursive CTE down the OrgChart

All employees who report to the CEO

simple query

Trang 7

WITH OrgPath (BusinessEntityID, ManagerID, lv)

AS ( Anchor SELECT BusinessEntityID, ManagerID, 1 FROM HumanResources.Employee

WHERE ManagerID IS NULL should only be EmployeeID 1

Recursive Call

UNION ALL SELECT E.BusinessEntityID, E.ManagerID, lv + 1

FROM HumanResources.Employee AS E

JOIN OrgPath

ON E.ManagerID = OrgPath.BusinessEntityID

) SELECT BusinessEntityID, ManagerID, lv FROM OrgPath

ORDER BY Lv, BusinessEntityID OPTION (MAXRECURSION 20);

Result (abbreviated):

BusinessEntityID ManagerID lv -

.

Because you join to the CTE in the recursive section of the CTE, you can use columns from this

iteration to calculate the level in the hierarchy In the previous query, theLvcolumn is calculated

using thelvcolumn from the previous iteration+ 1 Thus, each iteration is given a sequential level

number

If the adjacency list data had a cyclic error (A reports to B, who reports to C, who reports to A), then

Trang 8

The next query extends the previous recursive CTE by adding joins to flesh out the data It also uses a

different anchor node — Jean Trenary, Adventure Works’ IT Manager:

Find Subtree - Recursive CTE

All employees who report to IT Manager

full query with joins

WITH OrgPath (BusinessEntityID, ManagerID, lv)

AS (

Anchor

SELECT BusinessEntityID, ManagerID, 1

FROM HumanResources.Employee

WHERE BusinessEntityID = 263 Jean Trenary - IS Manager

Recursive Call

UNION ALL

SELECT E.BusinessEntityID, E.ManagerID, lv + 1

FROM HumanResources.Employee AS E

JOIN OrgPath

ON E.ManagerID = OrgPath.BusinessEntityID )

SELECT Lv, Emp.BusinessEntityID,

C.FirstName + ‘ ‘ + C.LastName AS [Name],

Emp.JobTitle,

OrgPath.ManagerID,

M.FirstName + ‘ ‘ + M.LastName AS [Manager]

FROM HumanResources.Employee AS Emp

JOIN OrgPath

ON Emp.BusinessEntityID = OrgPath.BusinessEntityID

JOIN Person.Person AS C

ON C.BusinessEntityID = Emp.BusinessEntityID

LEFT JOIN Person.Person AS M

ON Emp.ManagerID = M.BusinessEntityID

ORDER BY Lv, BusinessEntityID

OPTION (MAXRECURSION 20);

Result (abbreviated):

- - - - -

-1 263 Jean Trenary Information Services Manager 1 Ken S´ anchez

2 264 Stephanie Conroy Network Manager 263 Jean Trenary

2 267 Karen Berg Application Specialist 263 Jean Trenary

2 268 Ramesh Meyyappan Application Specialist 263 Jean Trenary

2 269 Dan Bacon Application Specialist 263 Jean Trenary

2 270 Fran¸ cois Ajenstat Database Administrator 263 Jean Trenary

2 271 Dan Wilson Database Administrator 263 Jean Trenary

2 272 Janaina Bueno Application Specialist 263 Jean Trenary

3 265 Ashvini Sharma Network Administrator 264 Stephanie Conroy

3 266 Peter Connelly Network Administrator 264 Stephanie Conroy

.

Trang 9

User-defined function down the hierarchy

SQL Server 2005’s recursive CTE is not the only way to skin a hierarchy Before 2005, hierarchies were

handled with stored procedures or user-defined functions that looped through the hierarchy layers

adding each layer as a set to a temp table or table variable — effectively doing the same thing as a CTE

but with T-SQL

The following multiple-statement table-valued user-defined function accepts anEmployeeIDas a

parameter The function returns this employee and all the employees below them in the organization

tree The function definition includes the structure for the returned table variable, called@Tree The

function populates@Tree, first inserting the anchor node, the employee for theEmployeeIDpassed to

the function

This method jumps ahead a bit, using an advanced programming feature of SQL Server to solve the hierarchical problem For more information about one of my personal favorite features of SQL Server, see Chapter 25, ‘‘Building User-Defined Functions.’’

TheWHILEloop continues toINSERT INTO @treethe next hierarchy level until no more rows are

found (@@rowcount > 0)

Even though this is a loop, it’s still performing nice set-based inserts, one for every hierarchy level If

the hierarchy has a million nodes and is nine levels deep, then nine set-based inserts complete the entire

task from top to bottom:

User-Defined Functions for Navigating Adjacency list CREATE FUNCTION dbo.OrgTree

(@BusinessEntityID INT) RETURNS

@Tree TABLE (BusinessEntityID INT, ManagerID INT, Lv INT)

AS BEGIN DECLARE @LC INT = 1 insert the top level (anchor node)

INSERT @Tree (BusinessEntityID, ManagerID, Lv)

SELECT BusinessEntityID, ManagerID, @LC FROM HumanResources.Employee AS E the employee WHERE BusinessEntityID = @BusinessEntityID

Trang 10

END RETURN

END; end of function

A table-valued function returns a result set so it’s called in theFROMclause The following query returns

AdventureWorks2008’s entire organizational chart:

test UDF

find all

simple query

SELECT * FROM dbo.OrgTree(1);

Result (abbreviated):

BusinessEntityID ManagerID Lv

-

.

Best Practice

The recursive CTE in this case is about twice as fast as the user-defined function However, the function

can include more variations of code, so it’s useful to know both methods

Just as with the recursive CTE, it’s easy to expand the query and include the data necessary for a

human-readable result set Just like the previous recursive CTE example, this query finds only the

subtree of those who work for Jean Trenary in the IT dept:

find subtree

all who work in IT

full query with joins

SELECT Lv, Emp.BusinessEntityID, Emp.JobTitle,

C.FirstName + ‘ ‘ + C.LastName AS [Name],

OrgTree.ManagerID,

M.FirstName + ‘ ‘ + M.LastName AS [Manager]

FROM HumanResources.Employee AS Emp

JOIN dbo.OrgTree (263) Jean Trenary, IT Manager

ON Emp.BusinessEntityID = OrgTree.BusinessEntityID JOIN Person.Person AS C

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

TỪ KHÓA LIÊN QUAN