2010-03-15 22 views
7

Tôi đang xem xét việc xây dựng một cơ sở cho phép truy vấn dữ liệu có lọc phân cấp. Tôi có một vài ý tưởng như thế nào tôi sẽ đi về nó, nhưng đã tự hỏi nếu có bất kỳ đề nghị hoặc đề xuất có thể hiệu quả hơn.Phương pháp tốt nhất để tìm kiếm dữ liệu phân cấp

Ví dụ: tưởng tượng rằng người dùng đang tìm kiếm một công việc. Các khu vực công việc sẽ như sau.

1: Scotland 
2: --- West Central 
3: ------ Glasgow 
4: ------ Etc 
5: --- North East 
6: ------ Ayrshire 
7: ------ Etc 

Người dùng có thể tìm kiếm cụ thể (tức là Glasgow) hoặc ở khu vực rộng hơn (tức là Scotland).

Hai cách tiếp cận tôi đang xem xét là:

  1. giữ một lưu ý của trẻ em trong các cơ sở dữ liệu cho mỗi bản ghi (tức là mèo 1 sẽ có 2, 3, 4 ở trẻ em của trường) và truy vấn đối với kỷ lục mà với số SELECT * FROM Jobs WHERE Category IN Areas.childrenField.
  2. Sử dụng hàm đệ quy để tìm tất cả các kết quả có liên quan đến khu vực đã chọn.

Những vấn đề tôi thấy từ cả hai đều là:

  1. Giữ dữ liệu này trong db sẽ có nghĩa là phải theo dõi tất cả những thay đổi cấu trúc.
  2. Đuổi chậm và không hiệu quả.

Bất kỳ ý tưởng, đề xuất hoặc đề xuất nào về cách tiếp cận tốt nhất? Tôi đang sử dụng C# ASP.NET với MSSQL 2005 DB.

+0

Bạn có thể làm các truy vấn đệ quy, nếu cấu trúc bảng của bạn hỗ trợ nó: http: // msdn.microsoft.com/en-us/library/ms186243.aspx – FrustratedWithFormsDesigner

+0

Bạn đã xem xét mô hình hóa thông tin của mình trong XML và lưu trữ nó trong một thuộc tính XML (trên bảng cơ sở dữ liệu) sao cho bạn có thể truy vấn nó bằng XQuery? – XpiritO

Trả lời

2

Đây là cách tiếp cận mà tôi đã thấy được sử dụng:

Tạo trường varchar (max) có tên là hierarchyid. Tạo id cơ sở cho tất cả các đối tượng gốc. Đối với mỗi đối tượng con tạo ra một id và thêm nó với các id cha mẹ.

Ví dụ Bảng

ID(PK) HierarchyID Area 
1  sl   Scotland 
2  slwc  West Central 
3  slwcgg  Glasgow 

Ví dụ Query

SELECT * FROM Areas Where HierarchyID LIKE 'sl%' 
+0

Kỹ thuật thú vị! – FrustratedWithFormsDesigner

+2

Trong SQL Server 2008, họ đã giới thiệu một kiểu dữ liệu, HierarchyID, để xử lý phương pháp này: http://msdn.microsoft.com/en-us/magazine/cc794278.aspx –

+0

Cách tiếp cận này trông giống như việc thực hiện hơi khác ý tưởng tùy chọn 1 của tôi. Đẹp và đơn giản, tuy nhiên điều đó có nghĩa là mỗi lần cập nhật danh mục sẽ xảy ra HeiratchyID sẽ cần phải được đánh giá lại. – WDuffy

1

Bạn nên sử dụng các tập lồng nhau. Đây là một thực hiện trong MySQL. http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

+0

Anh ấy đang sử dụng MSSQL, không phải MySQL. – FrustratedWithFormsDesigner

+0

Câu trả lời này là về "bộ lồng nhau" như một kỹ thuật để xử lý dữ liệu phân cấp. Ông chỉ liên kết với một lời giải thích tốt về nó xảy ra trên một trang web MySQL. Không có gì liên quan đến nó, đặc biệt là MySQL. – patmortech

2

Bạn có thể sử dụng Common Table Expressions để thực hiện truy vấn đệ quy. Tôi thấy kỹ thuật này rất mạnh mẽ, dễ đọc và dễ bảo trì.

1

Làm thế nào về điều này?

Bảng =>

Id ParentId Tên

đẹp bảng đơn giản?

Sau đó, làm thế nào về một số phần mềm phức tạp đẹp pf SQL để đi với điều đó? (Đá CTEs tôi nghĩ)

public object FetchCategoryTree() 
{ 
    var sql = @"SET TRANSACTION ISOLATION LEVEL READ COMMITTED; 

    WITH AreaTree (ID, Name, ParentID, OrgLevel, SortKey) AS 
    (
     -- Create the anchor query. This establishes the starting 
     -- point 
     SELECT 
      a.ID, 
      cast('---- ' + a.Name as varchar(255)), 
      a.ParentID, 
      cast('----' as varchar(55)), 
      CAST(a.ID AS VARBINARY(900)) 
     FROM dbo.Area a 
     WHERE a.ParentID is null 
     UNION ALL 
     -- Create the recursive query. This query will be executed 
     -- until it returns no more rows 
     SELECT 
      a.ID, 
      cast('----' + b.OrgLevel + ' ' + a.Name as varchar(255)), 
      a.ParentID, 
      cast(b.OrgLevel+ '----' as varchar(55)), 
      CAST(b.SortKey + CAST (a.ID AS BINARY(4)) AS VARBINARY(900)) 
     FROM dbo.Area a 
       INNER JOIN AreaTree b ON a.ParentID = b.ID 
    ) 
    SELECT * FROM AreaTree 
    ORDER BY SortKey"; 

    return FetchObject(sql); 
} 

Bây giờ, điều này có một số phép thuật SQL không quá chắc chắn.Tuy nhiên trong điều khoản của giáo dân, về cơ bản nó có phần đầu tiên như truy vấn gốc. Sau đó, nó quay trở lại bảng và thực hiện phần thứ hai bằng cách sử dụng câu trả lời của phần đầu tiên thông qua một phép nối, và tiếp tục làm cho nó vẫn không thể tìm thấy bất kỳ trận đấu nào khác, về cơ bản là một vòng lặp lớn. Nó cũng khá nhanh.

Bạn sẽ nhận được một loạt các hàng có khóa sắp xếp được đính kèm. Khi bạn đặt hàng truy vấn bằng phím sắp xếp, bạn sẽ nhận được câu trả lời như:

---- parent 1 
-------- child 1 
-------- child 2 
------------ child 2.1 
---- parent 2 
-------- etc 

Có thể là những gì bạn đang tìm kiếm?

0

Tôi sử dụng mô hình cây của Joe Celko cho hệ thống phân loại thuế bán hàng (bang/quận/thành phố/misc) trong ứng dụng của chúng tôi và nó hoạt động tốt.

của bạn "tìm được việc làm tại khu vực này hoặc bên dưới" truy vấn sẽ giống như thế này:

SELECT * FROM Jobs WHERE Jobs.AreaID IN 
(SELECT P1.AreaID 
FROM Areas AS P1, Areas AS P2 
WHERE P1.lft BETWEEN P2.lft AND P2.rgt 
AND P2.Areas.AreaID = @selectedAreaID) 

Celko Tree in SQL article

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