2008-10-10 94 views
8

Tôi có một bảng trong máy chủ SQL có cấu trúc cây bình thường của Item_ID, Item_ParentID. Giả sử tôi muốn lặp lại và nhận được tất cả TRẺ EM của một Item_ID cụ thể (ở mọi cấp độ).Có phải đệ quy tốt trong SQL Server không?

Đệ quy có vẻ là một ứng cử viên trực quan cho vấn đề này và tôi có thể viết một hàm SQL Server để thực hiện việc này.

Điều này có ảnh hưởng đến hiệu suất nếu bảng của tôi có nhiều bản ghi không? Làm cách nào để tránh đệ quy và chỉ cần truy vấn bảng? Xin vui lòng bất cứ đề nghị?

Trả lời

4

Với sự mới MS SQL 2005 bạn có thể sử dụng từ khóa WITH

Check-out this question và đặc biệt là this answer.

Với Oracle, bạn có thể sử dụng từ khóa CONNECT BY để tạo truy vấn phân cấp (syntax).

AFAIK với MySQL bạn sẽ phải sử dụng đệ quy.

Hoặc bạn luôn có thể tạo bảng bộ nhớ cache cho hồ sơ của mình cha mẹ-> mối quan hệ con

0

Có lẽ một số chi tiết khác là theo thứ tự.

Nếu bạn có mối quan hệ chi tiết chính như bạn mô tả, thì JOIN sẽ không đơn giản nhận được những gì bạn cần?

Như trong:

SELECT 
    SOME_FIELDS 
FROM 
    MASTER_TABLE MT 
,CHILD_TABLE CT 
WHERE CT.PARENT_ID = MT.ITEM_ID 
1

Bạn đang sử dụng SQL 2005?

Nếu vậy bạn có thể sử dụng Biểu thức bảng chung cho việc này. Một cái gì đó dọc theo những dòng:

; 
with CTE (Some, Columns, ItemId, ParentId) as 
(
    select Some, Columns, ItemId, ParentId 
    from myTable 
    where ItemId = @itemID 
    union all 
    select a.Some, a.Columns, a.ItemId, a.ParentId 
    from myTable as a 
    inner join CTE as b on a.ParentId = b.ItemId 
    where a.ItemId <> b.ItemId 
) 
select * from CTE 
0

Bạn không nên cần đệ quy cho trẻ em - bạn chỉ nhìn vào mức độ trực tiếp bên dưới (ví dụ: select * from T where ParentId = @parent) - bạn chỉ cần đệ quy cho tất cả hậu duệ.

Trong SQL2005 bạn có thể nhận được các hậu duệ với:

with AllDescendants (ItemId, ItemText) as (
    select t.ItemId, t.ItemText 
     from [TableName] t 
    where t.ItemId = @ancestorId 
    union 
    select sub.ItemId, sub.ItemText 
     from [TableName] sub 
      inner join [TableName] tree 
      on tree.ItemId = sub.ParentItemId 
) 
+0

Tôi nghĩ vấn đề của ông là ông muốn "Tại một cấp độ cụ thể ". Trừ khi bạn lưu trữ số cấp, làm thế nào để bạn biết những gì là ở một mức độ cụ thể mà không đi root = cấp 1, trẻ em của root = cấp 2, trẻ em của trẻ em = cấp 3, vv ... Không phải đệ quy là cần thiết .. Nhưng có thể có nhiều cha mẹ. – Cervo

1

Vấn đề bạn sẽ phải đối mặt với đệ quy và hiệu suất là bao nhiêu lần nó sẽ phải recurse để trả lại kết quả. Mỗi cuộc gọi đệ quy là một cuộc gọi riêng biệt khác sẽ phải được kết hợp vào tổng số kết quả.

Trong SQL 2K5 bạn có thể sử dụng một biểu thức bảng chung để xử lý đệ quy này:

WITH Managers AS 
( 
--initialization 
SELECT EmployeeID, LastName, ReportsTo 
FROM Employees 
WHERE ReportsTo IS NULL 
UNION ALL 
--recursive execution 
SELECT e.employeeID,e.LastName, e.ReportsTo 
FROM Employees e INNER JOIN Managers m 
ON e.ReportsTo = m.employeeID 
) 
SELECT * FROM Managers 

hoặc giải pháp khác là để san bằng hệ thống phân cấp vào một bảng khác

Employee_Managers
ManagerId (PK , FK tới bảng nhân viên)
EmployeeId (PK, FK tới bảng nhân viên)

Tất cả các tàu liên quan con mẹ sẽ được lưu trữ trong bảng này, vì vậy nếu quản lý 1 quản lý quản lý 2 quản lý nhân viên 3, bảng sẽ trông như thế:

ManagerId EmployeeId 
1   2 
1   3 
2   1 

Điều này cho phép phân cấp để dễ dàng truy vấn:

select * from employee_managers em 
inner join employee e on e.employeeid = em.employeeid and em.managerid = 42 

trong đó sẽ trả lại toàn bộ nhân viên có quản lý 42. các lộn ngược sẽ được hiệu suất cao hơn, nhưng nhược điểm là sẽ được duy trì hệ thống phân cấp

2

Như một câu trả lời chung, chúng ta có thể làm một số công cụ khá tinh vi trong SQL Máy chủ không rmally cần đệ quy, đơn giản bằng cách sử dụng một thuật toán lặp. Tôi đã quản lý một trình phân tích cú pháp XHTML trong SQL Giao dịch hoạt động tốt một cách đáng ngạc nhiên. Trình tạo mã mà tôi đã viết đã được thực hiện trong một thủ tục lưu sẵn. Nó aint thanh lịch, nó là khá giống như xem trâu làm Ballet. nhưng nó đã có tác dụng .

+0

Tôi đã từng viết một trình phát video trong Transact-SQL! :-P –

+0

Bạn có thể, nhưng chắc chắn sẽ dễ dàng hơn khi viết một trình phân tích cú pháp XHTML bằng Python/Ruby/C#/Java/Perl/LISP/etc. Và hiệu suất có lẽ sẽ tốt hơn .... – Cervo

+0

Không thành thật. Nó ở đây! http://www.simple-talk.com/sql/t-sql-programming/getting-html-data-workbench/ –

1

Joe Celko có book (< - liên kết đến Amazon) cụ thể trên cấu trúc cây trong cơ sở dữ liệu SQL. Trong khi bạn sẽ cần đệ quy cho mô hình của bạn và chắc chắn sẽ có tiềm năng cho các vấn đề hiệu suất ở đó, có những cách khác để mô hình cấu trúc cây tùy thuộc vào vấn đề cụ thể của bạn có thể tránh được đệ quy và cho hiệu năng tốt hơn.

0

Bạn không cần đệ quy ở tất cả .... Lưu ý, tôi đã thay đổi cột để ItemID và ItemParentID để dễ gõ ...

 
DECLARE @intLevel INT 
SET @intLevel = 1

INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECT ItemID, ItemParentID, @intLevel WHERE ItemParentID IS NULL

WHILE @intLevel < @TargetLevel BEGIN SET @intLevel = @intLevel + 1 INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECt ItemID, ItemParentID, @intLevel WHERE ItemParentID IN (SELECT ItemID FROM TempTable WHERE Level = @intLevel-1) -- If no rows are inserted then there are no children IF @@ROWCOUNT = 0 BREAK END

SELECt ItemID FROM TempTable WHERE Level = @TargetLevel

Các vấn đề liên quan