type transact tipo tabla query jerarquica dato data sql tree

transact - Consulta SQL "tipo árbol": la mayoría de los grupos principales



tipo de dato hierarchyid (6)

En T-SQL, puede escribir un ciclo while. No probado:

@group = <starting group> WHILE (EXISTS(SELECT * FROM Gruppe_Gruppe WHERE ChildGruppeId=@group)) BEGIN SELECT @group=ParentGruppeId FROM Gruppe_Gruppe WHERE ChildGruppeId=@group END

Tengo problemas para hacer una consulta tipo "árbol" (¿cómo lo llamamos?) En SQL.

Eche un vistazo a mi diagrama a continuación (los nombres de las tablas y columnas están en danés, lo siento):

Diagrama DB http://img197.imageshack.us/img197/8721/44060572.jpg Con MSSQL Server 2005, el objetivo es encontrar el grupo principal (Gruppe) para cada cliente (Kunde).

Cada grupo puede tener muchos grupos de padres y muchos grupos de niños.

Y, también me gustaría saber cómo mostrar el árbol de esta manera:

Customer 1 - Parent group 1 - Child group 1 - ChildChild group n - Child group n - Parent group n - ... - ... Customer n - ...

Otra pregunta:

¿Cómo se ve la consulta para obtener TODOS los grupos para todos los clientes? Grupos de padres e hijos.


No puedo decirlo mejor que Joe Celko. El problema suele ser que los modelos construidos no se prestan bien para construir jerarquías, y que esos modelos deben tener en cuenta las características de su jerarquía. ¿Es muy profundo? ¿Es demasiado ancho? ¿Es estrecho y superficial?

Una clave para el éxito en árboles anchos y poco profundos es tener el camino completo en la jerarquía en una columna, como menciona Celko en el primer enlace.


Puede usar CTE para construir la columna "la ruta completa" sobre la marcha

--DROP TABLE Gruppe, Kunde, Gruppe_Gruppe, Kunde_Gruppe CREATE TABLE Gruppe ( Id INT PRIMARY KEY , Name VARCHAR(100) ) CREATE TABLE Kunde ( Id INT PRIMARY KEY , Name VARCHAR(100) ) CREATE TABLE Gruppe_Gruppe ( ParentGruppeId INT , ChildGruppeId INT ) CREATE TABLE Kunde_Gruppe ( KundeId INT , GruppeId INT ) INSERT Gruppe VALUES (1, ''Group 1''), (2, ''Group 2''), (3, ''Group 3'') , (4, ''Sub-group A''), (5, ''Sub-group B''), (6, ''Sub-group C''), (7, ''Sub-group D'') INSERT Kunde VALUES (1, ''Kunde 1''), (2, ''Kunde 2''), (3, ''Kunde 3'') INSERT Gruppe_Gruppe VALUES (1, 4), (1, 5), (1, 7) , (2, 6), (2, 7) , (6, 1) INSERT Kunde_Gruppe VALUES (1, 1), (1, 2) , (2, 3), (2, 4) ;WITH CTE AS ( SELECT CONVERT(VARCHAR(1000), REPLACE(CONVERT(CHAR(5), k.Id), '' '', ''K'')) AS TheKey , k.Name AS Name FROM Kunde k UNION ALL SELECT CONVERT(VARCHAR(1000), REPLACE(CONVERT(CHAR(5), x.KundeId), '' '', ''K'') + REPLACE(CONVERT(CHAR(5), g.Id), '' '', ''G'')) AS TheKey , g.Name FROM Gruppe g JOIN Kunde_Gruppe x ON g.Id = x.GruppeId UNION ALL SELECT CONVERT(VARCHAR(1000), p.TheKey + REPLACE(CONVERT(CHAR(5), g.Id), '' '', ''G'')) AS TheKey , g.Name FROM Gruppe g JOIN Gruppe_Gruppe x ON g.Id = x.ChildGruppeId JOIN CTE p ON REPLACE(CONVERT(CHAR(5), x.ParentGruppeId), '' '', ''G'') = RIGHT(p.TheKey, 5) WHERE LEN(p.TheKey) < 32 * 5 ) SELECT * , LEN(TheKey) / 5 AS Level FROM CTE c ORDER BY c.TheKey

El rendimiento puede ser subóptimo si tiene muchas lecturas y pocas modificaciones.


Qué tal algo como esto:

DECLARE @Customer TABLE( CustomerID INT IDENTITY(1,1), CustomerName VARCHAR(MAX) ) INSERT INTO @Customer SELECT ''Customer1'' INSERT INTO @Customer SELECT ''Customer2'' INSERT INTO @Customer SELECT ''Customer3'' DECLARE @CustomerTreeStructure TABLE( CustomerID INT, TreeItemID INT ) INSERT INTO @CustomerTreeStructure (CustomerID,TreeItemID) SELECT 1, 1 INSERT INTO @CustomerTreeStructure (CustomerID,TreeItemID) SELECT 2, 12 INSERT INTO @CustomerTreeStructure (CustomerID,TreeItemID) SELECT 3, 1 INSERT INTO @CustomerTreeStructure (CustomerID,TreeItemID) SELECT 3, 12 DECLARE @TreeStructure TABLE( TreeItemID INT IDENTITY(1,1), TreeItemName VARCHAR(MAX), TreeParentID INT ) INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001'', NULL INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.001'', 1 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.001.001'', 2 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.001.002'', 2 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.001.003'', 2 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.002'', 1 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.003'', 1 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.003.001'', 7 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.001.002.001'', 4 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.001.002.002'', 4 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''001.001.002.003'', 4 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''002'', NULL INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''002.001'', 12 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''002.001.001'', 13 INSERT INTO @TreeStructure (TreeItemName,TreeParentID) SELECT ''002.001.002'', 13 ;WITH Structure AS ( SELECT TreeItemID, TreeItemName, TreeParentID, REPLICATE(''0'',5 - LEN(CAST(TreeItemID AS VARCHAR(MAX)))) + CAST(TreeItemID AS VARCHAR(MAX)) + ''//' TreePath FROM @TreeStructure ts WHERE ts.TreeParentID IS NULL UNION ALL SELECT ts.*, s.TreePath + REPLICATE(''0'',5 - LEN(CAST(ts.TreeItemID AS VARCHAR(5)))) + CAST(ts.TreeItemID AS VARCHAR(5)) + ''//' TreePath FROM @TreeStructure ts INNER JOIN Structure s ON ts.TreeParentID = s.TreeItemID ) SELECT c.CustomerName, Children.TreeItemName, Children.TreePath FROM @Customer c INNER JOIN @CustomerTreeStructure cts ON c.CustomerID = cts.CustomerID INNER JOIN Structure s ON cts.TreeItemID = s.TreeItemID INNER JOIN ( SELECT * FROM Structure ) Children ON Children.TreePath LIKE s.TreePath +''%'' ORDER BY 1,3 OPTION (MAXRECURSION 0)


Se me ocurrió una solución que resuelve el problema de listar TODOS los grupos para cada cliente. Grupos de padres e hijos.

¿Qué piensas?

WITH GroupTree AS ( SELECT kg.KundeId, g.Id GruppeId FROM ActiveDirectory.Gruppe g INNER JOIN ActiveDirectory.Kunde_Gruppe kg ON g.Id = kg.GruppeId AND (EXISTS (SELECT * FROM ActiveDirectory.Gruppe_Gruppe WHERE ParentGruppeId = g.Id) OR NOT EXISTS (SELECT * FROM ActiveDirectory.Gruppe_Gruppe WHERE ParentGruppeId = g.Id)) UNION ALL SELECT GroupTree.KundeId, gg.ChildGruppeId FROM ActiveDirectory.Gruppe_Gruppe gg INNER JOIN GroupTree ON gg.ParentGruppeId = GroupTree.GruppeId ) SELECT KundeId, GruppeId FROM GroupTree OPTION (MAXRECURSION 32767)


Usamos SQL Server 2000 y hay un ejemplo de expansión de jerarquías utilizando una pila en los Libros en pantalla de SQL, he escrito una serie de variantes para nuestro sistema ERP

http://support.microsoft.com/kb/248915

Deduzco que hay un método nativo que usa CTE en SQL 2005 pero no lo he usado yo mismo