2010-03-15 16 views
7

Estoy buscando construir una instalación que permita consultar datos con filtrado jerárquico. Tengo algunas ideas de cómo voy a hacerlo, pero me pregunto si hay alguna recomendación o sugerencia que pueda ser más eficiente.El mejor método para buscar datos jerárquicos

Como ejemplo, imagine que un usuario está buscando trabajo. Las áreas de trabajo serían las siguientes.

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

Un usuario puede buscar específico (es decir Glasgow) o en un área más grande (es decir, Escocia).

Los dos enfoques que estoy considerando son:

  1. mantener una nota de niños en la base de datos para cada registro (es decir, el gato 1 tendría 2, 3, 4 en sus hijos de campo) y consulta en ese registro con un SELECT * FROM Jobs WHERE Category IN Areas.childrenField.
  2. Utilice una función recursiva para encontrar todos los resultados que tienen una relación con el área seleccionada.

Los problemas que veo desde ambos son:

  1. Manteniendo estos datos en el PP significará tener que llevar un registro de todos los cambios en la estructura.
  2. La recursividad es lenta e ineficiente.

¿Alguna idea, sugerencia o recomendación sobre el mejor enfoque? Estoy usando C# ASP.NET con MSSQL 2005 DB.

+0

Usted puede hacer consultas recursivas, si su estructura de tabla que soporta: http: // msdn.microsoft.com/en-us/library/ms186243.aspx – FrustratedWithFormsDesigner

+0

¿Ha considerado modelar su información en XML y almacenarla en un atributo XML (en la tabla de la base de datos) para que luego pueda consultarla con XQuery? – XpiritO

Respuesta

2

Aquí es un enfoque que he visto utilizado:

crear un campo varchar (max) llamada hierarchyid. Genera identificadores base para todos los objetos raíz. Para cada objeto hijo, genere una identificación y anteponga a los ID de los padres.

Ejemplo Tabla

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

Ejemplo de consulta

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

¡Técnica interesante! – FrustratedWithFormsDesigner

+2

En SQL Server 2008, han introducido un tipo de datos, HierarchyID, para manejar este enfoque: http://msdn.microsoft.com/en-us/magazine/cc794278.aspx –

+0

Este enfoque parece una implementación ligeramente diferente de mi opción 1 idea. Agradable y simple, sin embargo, significa que cada vez que se realiza una actualización de la categoría, el HeiratchyID debería ser reevaluado. – WDuffy

1

Debe usar conjuntos anidados. Aquí hay una implementación en MySQL. http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

+0

Está usando MSSQL, no MySQL. – FrustratedWithFormsDesigner

+0

Esta respuesta trata de "conjuntos anidados" como una técnica para tratar con datos jerárquicos. Él acaba de vincular a una buena explicación de lo que sucede en un sitio MySQL. No hay nada involucrado en eso que sea específico de MySQL. – patmortech

2

Puede usar Common Table Expressions para realizar consultas recursivas. Encuentro esta técnica muy poderosa, fácil de leer y fácil de mantener.

1

¿Qué tal esto?

Tabla =>

Id parentid Nombre

agradable del vector de simple?

Entonces, ¿qué tal una pieza complicada y agradable de SQL para ir con eso? (Creo que CTEs rock)

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); 
} 

Ahora esto hace algo de magia SQL de la que no estoy muy seguro.Sin embargo, en términos simples, básicamente toma la primera parte como consulta raíz. Luego regresa a la mesa y ejecuta la segunda parte usando la respuesta de la primera parte a través de una unión, y continúa haciéndolo para que no pueda encontrar más coincidencias, básicamente un gran bucle. Es bastante rápido también.

Obtendrá un montón de filas con una clave de clasificación adjunta. Una vez que ordena la consulta por la clave de ordenación obtendrá la respuesta como:

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

podría ser lo que está buscando?

0

Utilizo el modelo de árbol de Joe Celko para la jerarquía del impuesto a las ventas (estado/condado/ciudad/misc) en nuestra aplicación y funciona bien.

Su "encontrar puestos de trabajo en esta área o por debajo de" consulta sería algo como esto:

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

Cuestiones relacionadas