2013-06-06 14 views
7

Mam strukturę drzewa i jego kolejną tablicę przydziałów dla kategorii klientów w bazie danych serwera sql.Znajdź wszystkie węzły liści poniżej poddrzewa w strukturze drzewa w serwerze sql

CustomerCategory (CategoryID, ParentId) 
CustomerInCategory(CustomerID, CategoryID) 

Jeśli CustomerCategory ma żadnego klienta przypisanego do niego, nie możemy dodać kolejną podkategorię do niego. Tak więc Klient może być dodany tylko do najniższego poziomu w każdym drzewie podrzędnym. W innym sensie wynik tego zapytania powinien dać węzły liści. Inną rzeczą jest to, że drzewo to może mieć poddrzew na różnych poziomach, a my także nie chcemy ograniczać liczby poziomów, jednak nasi użytkownicy nie będą potrzebować więcej niż 10 poziomów. Potraktuj to jako ilustracja

CategoryID------ParentID---------------Name 
1    NULL     All Customers 
2    1      Domestic 
3    1      International 
4    2      Independent Retailers 
5    2      Chain Retailers 
6    2      Whole Sellers 
7    5      A-Mart 
8    5      B-Mart 
9    4      Grocery Stores 
10    4      Restaurants 
11    4      Cafes 

CustomerID---------CustomerName----------Category 
1     Int.Customer#1    3 
2     Int.Customer#2    3 
3     A-Mart.Branch#1    7 
4     A-Mart.Branch#2    7 
5     B-Mart.Branch#1    8 
6     B-Mart.Branch#2    8 
7     Grocery#1     9 
8     Grocery#2     9 
9     Grocery#3     9 
10     Restaurant#1     10 
11     Restaurant#2     10 
12     Cafe#1      11 
13     Wholeseller#1    6 
14     Wholeseller#2    6 

Moje wymogiem jest coś takiego „zważywszy węzeł w kategoriach, Return wszystkich klientów przyłączonych do dowolnego węzła pod nim”.

Jak to zrobić z sql?

Oczywiście można to zrobić za pomocą wywołania rekurencyjnego w kodzie, ale jak możemy to zrobić w t-sql (bez wywoływania procedury składowanej kilka razy lub przy użyciu wyszukiwania tekstowego)?

Czy dowolny element, użyj CTE, aby rozwiązać ten problem?

Mam zestaw wyników czegoś takiego w umyśle

CustomerID--------Customer Name----------------CategoryId----------CAtegoryName 

12    Cafe#1      11     Cafes 
12    Cafe#1      4     IndependentRetailers 
12    Cafe#1      2     Demoestic 
12    Cafe#1      1     AllCustomers 
. 
. 
. 
4     A-Mart.Branch#2    7     A-Mart 
4     A-Mart.Branch#2    5     Chain Retailers 
4     A-Mart.Branch#2    2     Domestic 
4     A-Mart.Branch#2    1     All Customers 
. 
. 
. 
14     Wholeseller#2    6     WholeSellers 
14     Wholeseller#2    2     Domestic 
14     Wholeseller#2    1     All Customers 

Niekoniecznie jest to dobry pomysł, aby układ wynik takiego, byłoby to zbyt dużo miejsca, coś, co może nie być wymagane, jednak wyszukiwanie w takim zestawie wyników byłoby bardzo szybkie. Jeśli chcę, aby znaleźć wszystkie poniższe klienci mówią IDkategorii = 2, chciałbym po prostu zapytać

SELECT * FROM resultset where category ID = 2 

Wszelkie sugestie, aby poprawić model danych jest bardzo mile widziani! Jeśli pomaga rozwiązać ten problem.

Po raz kolejny nie jestem związany z tym zestawem wyników. Każda inna sugestia, która rozwiązuje problem, "Biorąc pod uwagę węzeł w kategoriach, Zwróć wszystkich klientów dołączonych do dowolnego węzła poniżej", jest dobrze akceptowana.

Odpowiedz

9

Można użyć CTE rekursywnie zbudować tabelę zawierającą wszystkie relacje rodzic-dziecko i skorzystać z klauzuli WHERE uzyskać tylko poddrzewa co potrzeba (w moim przykładzie everyting pod IDkategorii 5):

WITH CategorySubTree AS (
    SELECT cc.CategoryId as SubTreeRoot, 
      cc.CategoryId 
      FROM CustomerCategory cc 
UNION ALL 
    SELECT cst.SubTreeRoot, cc.CategoryId 
     FROM CustomerCategory cc 
     INNER JOIN CategorySubTree cst ON cst.CategoryId = cc.parentId 
) 
SELECT cst.CategoryId 
FROM CategorySubTree cst 
WHERE cst.SubTreeRoot = 5 

można zmodyfikować tę kwerendę, aby dodać co trzeba, na przykład, aby zdobyć klientów związanych z węzłami kategorii w poddrzewie:

WITH CategorySubTree AS (
    SELECT cc.CategoryId as SubTreeRoot, 
      cc.CategoryId 
      FROM CustomerCategory cc 
UNION ALL 
    SELECT cst.SubTreeRoot, cc.CategoryId 
     FROM CustomerCategory cc 
     INNER JOIN CategorySubTree cst ON cst.CategoryId = cc.parentId 
) 
SELECT cst.CategoryId,cic.CustomerId 
FROM CategorySubTree cst 
     INNER JOIN CustomerInCategory cic ON cic.CategoryId = cst.CategoryId 
WHERE cst.SubTreeRoot = 5 

i oczywiście można dołączyć dodatkowe tabele, aby etykiety i inne potrzebne informacje.

+0

bardzo sprytny ... bardzo sprytny ... Dzięki. – user1155391

+0

Czy można to zrobić na serwerze MS SQL? – sajushko