2010-11-23 12 views
8

pregunta simple .. simplemente no puede obtener el conjunto de resultados en el orden que necesito: pSelección de los registros en orden de ID de padre

Tengo una tabla "categorías"

id | name  | parent 
1  apple  0 
2  macintosh 1 
3  atari  0 
4  st   3 
5  lisa  1 

estoy se trata de seleccionar sale el siguiente conjunto de resultados:

1 apple  0 
5 lisa  1 
2 macintosh 1 
3 atari  0 
4 st   3 

Así, en otras palabras que quiero todas las columnas de todas las filas, donde las filas con los padres son inmediatamente después de su fila padre y todos están ordenados alfabéticamente.

parent a 
child a 
child b 
parent b 
child a 

La consulta que estoy usando ahora no volver a ordenar correctamente las filas de sus padres

SELECT a.*, b.* FROM categories a RIGHT JOIN categories b ON b.parent = a.id 
+0

@Fo - Parece ser un error tipográfico? Atari debe figurar en la lista justo después de la manzana – ajreal

+0

No, los niños de manzana deben aparecer después de manzana, luego atari, y luego los niños de atari. (Lisa fue la computadora que Apple lanzó antes de Macintosh) –

+0

¿Qué pasa con el nieto? Supongo que también deberían clasificarse (es decir, recursivamente)? – Tomalak

Respuesta

5

Para una solución simple, tal vez subóptima-escalable, recomiendo la codificación dura de esto con el número máximo de niveles que tendrá:

Por sólo 2 niveles:

SELECT p2.name as `Parent name`, p1.* 
FROM categories p1 
LEFT JOIN categories p2 on p1.categories_id = p2.id 

Eres realmente preguntar sobre la clasificación, así que recomiendo que genera un "camino" cadena -como: (ver más abajo para ejemplo del resultado de esta consulta)

SELECT Concat(If(isnull(p2.name),"",Concat("/",p2.name)),"/",p1.name) as `generated path`, p2.name as `Parent name`, p1.* 
FROM categories p1 
LEFT JOIN categories p2 on p1.parent_id = p2.id 
order by `generated path` 

para 3 niveles, TH ough sus datos no tiene esto todavía - ruta omite porque va a poner feo :)

SELECT p3.name as `Grandparent name`, p2.name as `Parent name`, p1.* 
FROM categories p1 
LEFT JOIN categories p2 on p1.categories_id = p2.id 
LEFT JOIN categories p3 on p2.categories_id = p3.id 

una solución más completa para seleccionar rápidamente todos los artículos en una categoría particular, a cualquier nivel, que requiere algo de trabajo en todo escribe, está implementando un 'right' and 'left' numbering concept. Pero, una discusión más profunda sobre eso está yendo más allá del alcance de lo que estás preguntando. Sin embargo, esa es la única buena manera en mi experiencia para hacer que este tipo de tabla de autorreferencia sea muy útil si va a ser grande (tal vez después de más de 1000 filas con 3 a 10 niveles).

Adición: ejemplo de salida de la segunda consulta:

generated path   Parent name   id   name   parent_id 
---------------------------------------------------------------------------- 
/apple          1   apple    0 
/apple/lisa     apple   5   lisa     1 
/apple/mac     apple   2   mac     1 
/atari          3   atari    0 
/atari/st     atari   4   st     3 
+0

p.s. Implementé con éxito una tabla autorreferencial con una profundidad de 4, por lo que no hay nada de malo en ese enfoque. Solo necesita mantenerse un poco ligero, quizás operar con datos estáticos y almacenar el resultado en caché. – zanlok

+0

Esto funciona mejor para resolver el problema tal como se describe sin requerir un cambio en los datos. –

0

ver si esto funciona:

SELECT Table1.ID, Table1.name, Table1.parent, Table1_1.name, Table1_1.parent 
FROM Table1 INNER JOIN Table1 AS Table1_1 ON Table1.ID = Table1_1.parent 
ORDER BY Table1.name; 

que construyeron esto con Micorsoft Acceda y se veía como lo que quería para mí. Creo que necesita un informe al grupo para darle visualmente lo que desea dar a un consumidor, pero por el bien de unirse correctamente para llegar a ese punto, esto funciona.

13

Si los que no tienen padres tenían null en su columna parent, su declaración sería muy simple:

SELECT id, name, parent FROM categories order by coalesce(parent, id), id; 

Si insiste en 0 que no representa padre, puede usar una declaración más detallada CASE WHEN ... THEN ....

Editar:

-- Sorting by name instead 
select a.id, a.name, a.parent 
from categories a left join categories b on a.parent=b.id 
order by coalesce(b.name, a.name), a.name 
+0

¿Funciona esto en MySQL? (Evito los nulos, pero eso casi parece útil.) – zanlok

+0

@zanlok: http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_coalesce – Tomalak

+0

No lo he necesitado en 10 años , pero es bueno saberlo, gracias. – zanlok

2

Esto funcionaría, pero no de forma recursiva.

SELECT 
    b.* 
FROM 
    categories a 
    RIGHT JOIN categories b ON b.parent = a.id 
ORDER BY 
    COALESCE(a.name, b.name), b.name 
Cuestiones relacionadas