2013-06-06 30 views
7

Ho una struttura ad albero e la sua successiva tabella di assegnazione per le categorie di clienti in un database SQL Server.Trova tutti i nodi foglia sotto una struttura ad albero in una struttura ad albero in sql server

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

Se un CustomerCategory ha qualsiasi cliente assegnato ad esso, non possiamo aggiungere un altro sottocategoria ad esso. Quindi, il Cliente può essere aggiunto al livello più basso in ogni sottostruttura. In altri termini, il risultato di questa query

SELECT * FROM `CustomerCategory` WHERE `CategoryId` NOT IN 
(SELECT DISTINCT `parentid` FROM `CustomerCategory` WHERE `parentid` IS NOT NULL) 

produrrebbe nodi foglia. L'altra cosa è che, questo albero potrebbe avere sottoalberi di diversi livelli, e anche noi, non vogliamo vincolare il numero di livelli in ogni caso, tuttavia, i nostri utenti non avranno bisogno di più di 10 livelli. Consideriamo questo come un esempio

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 

La mia esigenza è qualcosa di simile, "Dato un nodo in Categorie, restituire tutti i clienti collegati a qualsiasi nodo di sotto di essa".

Come posso farlo con sql?

Ovviamente questo può essere fatto con una chiamata ricorsiva nel codice, ma come possiamo farlo in t-sql (senza chiamare una stored procedure più volte o utilizzando la ricerca basata su testo)?

Qualsiasi corpo, utilizzare un CTE per risolvere questo problema?

Ho un set di risultati di qualcosa come questo in mente

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 

Questo non è necessariamente una buona idea di layout di un risultato come questo, che richiederebbe troppo spazio, cosa che potrebbe non essere necessario, ancora, una ricerca in tale set di risultati sarebbe molto veloce. Se voglio trovare tutti i clienti sotto dicono categoryId = 2, vorrei semplicemente interrogare

SELECT * FROM resultset where category ID = 2 

Eventuali suggerimenti per migliorare il modello di dati è SUPER accolto favorevolmente! Se aiuta a risolvere questo problema.

Ancora una volta, non sono fissato su questo set di risultati. Qualsiasi altro suggerimento che risolva il problema, "Dato un nodo in Categorie, restituisce tutti i clienti collegati a qualsiasi nodo sottostante", è ben accettato.

risposta

9

È possibile utilizzare un CTE per costruire ricorsivamente una tabella contenente tutte le relazioni padre-figlio e utilizzare la clausola WHERE per ottenere solo la sottostruttura è necessario (nel mio esempio, everyting sotto CategoryId 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 

È possibile modificare questa query per aggiungere quello che vi serve, per esempio, per ottenere i clienti legati ai nodi di categoria nella sottostruttura:

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 

e naturalmente si può aderire ulteriori tabelle per ottenere le etichette e le altre informazioni necessarie.

+0

molto intelligente ... molto intelligente ... Grazie. – user1155391

+0

C'è un modo per farlo sul server MS SQL? – sajushko

Problemi correlati