sql >> Base de Datos >  >> RDS >> Mysql

Respuestas a comentarios de varios niveles:visualización y almacenamiento

Hay muchas maneras. Aquí hay un enfoque que me gusta (y uso regularmente).

La base de datos

Considere la siguiente estructura de base de datos:

CREATE TABLE comments (
  id int(11) unsigned NOT NULL auto_increment,
  parent_id int(11) unsigned default NULL,
  parent_path varchar(255) NOT NULL,

  comment_text varchar(255) NOT NULL,
  date_posted datetime NOT NULL,  

  PRIMARY KEY  (id)
);

sus datos se verán así:

+-----+-------------------------------------+--------------------------+---------------+
| id  | parent_id | parent_path             | comment_text             | date_posted   |
+-----+-------------------------------------+--------------------------+---------------+
|   1 | null      | /                       | I'm first                | 1288464193    | 
|   2 | 1         | /1/                     | 1st Reply to I'm First   | 1288464463    | 
|   3 | null      | /                       | Well I'm next            | 1288464331    | 
|   4 | null      | /                       | Oh yeah, well I'm 3rd    | 1288464361    | 
|   5 | 3         | /3/                     | reply to I'm next        | 1288464566    | 
|   6 | 2         | /1/2/                   | this is a 2nd level reply| 1288464193    | 

... and so on...

Es bastante fácil seleccionar todo de una manera útil:

select id, parent_path, parent_id, comment_text, date_posted
from comments 
order by parent_path, date_posted;

ordenar por parent_path, date_posted generalmente producirá resultados en el orden en que los necesitará cuando genere su página; pero querrá asegurarse de tener un índice en la tabla de comentarios que lo respalde correctamente; de ​​lo contrario, la consulta funciona, pero es muy, muy ineficiente:

create index comments_hier_idx on comments (parent_path, date_posted);

Para cualquier comentario individual dado, es fácil obtener el árbol completo de comentarios secundarios de ese comentario. Simplemente agregue una cláusula where:

select id, parent_path, parent_id, comment_text, date_posted
from comments 
where parent_path like '/1/%'
order by parent_path, date_posted;

la cláusula where agregada hará uso del mismo índice que ya definimos, así que estamos listos para comenzar.

Tenga en cuenta que no hemos utilizado el parent_id aún. De hecho, no es estrictamente necesario. Pero lo incluyo porque nos permite definir una clave externa tradicional para hacer cumplir la integridad referencial e implementar eliminaciones y actualizaciones en cascada si así lo deseamos. Las restricciones de clave externa y las reglas en cascada solo están disponibles en las tablas INNODB:

ALTER TABLE comments ENGINE=InnoDB;

ALTER TABLE comments 
  ADD FOREIGN KEY ( parent_id ) REFERENCES comments 
    ON DELETE CASCADE 
    ON UPDATE CASCADE;

Gestión de la jerarquía

Para usar este enfoque, por supuesto, deberá asegurarse de configurar parent_path correctamente al insertar cada comentario. Y si mueve los comentarios (lo que sin duda sería un caso de uso extraño), tendrá que asegurarse de actualizar manualmente cada parent_path de cada comentario que está subordinado al comentario movido. ... pero ambas son cosas bastante fáciles de seguir.

Si realmente quiere ser elegante (y si su base de datos lo admite), puede escribir disparadores para administrar parent_path de manera transparente. Dejaré esto como un ejercicio para el lector, pero la idea básica es que los disparadores de inserción y actualización se activarían. antes de que se confirme una nueva inserción. subirían al árbol (usando el parent_id relación de clave externa) y reconstruir el valor de parent_path en consecuencia.

Incluso es posible romper el parent_path en una tabla separada que se administra completamente mediante activadores en la tabla de comentarios, con algunas vistas o procedimientos almacenados para implementar las diversas consultas que necesita. Por lo tanto, aísla completamente su código de nivel medio de la necesidad de conocer o preocuparse por la mecánica de almacenamiento de la información de la jerarquía.

Por supuesto, no se requiere ninguna de las cosas sofisticadas de ninguna manera; por lo general, es suficiente simplemente colocar parent_path en la tabla y escribir un código en su nivel intermedio para asegurarse de que se administre correctamente junto con todos los demás campos. ya tienes que gestionar.

Imposición de límites

MySQL (y algunas otras bases de datos) le permite seleccionar "páginas" de datos usando el LIMIT cláusula:

SELECT * FROM mytable LIMIT 25 OFFSET 0;

Desafortunadamente, cuando se trata de datos jerárquicos como este, la cláusula LIMIT por sí sola no producirá los resultados deseados.

-- the following will NOT work as intended

select id, parent_path, parent_id, comment_text, date_posted
from comments 
order by parent_path, date_posted
LIMIT 25 OFFSET 0;

En su lugar, necesitamos una selección separada en el nivel en el que queremos imponer el límite, luego lo unimos nuevamente con nuestra consulta de "subárbol" para dar los resultados finales deseados.

Algo como esto:

select 
  a.*
from 
  comments a join 
  (select id, parent_path 
    from comments 
    where parent_id is null
  order by parent_path, post_date DESC 
  limit 25 offset 0) roots
  on a.parent_path like concat(roots.parent_path,roots.id,'/%') or a.id=roots.id)
order by a.parent_path , post_date DESC;

Observe la instrucción limit 25 offset 0 , enterrado en medio de la selección interior. Esta declaración recuperará los 25 comentarios de "nivel raíz" más recientes.

[editar:es posible que descubras que tienes que jugar un poco con las cosas para obtener la capacidad de ordenar y/o limitar las cosas exactamente como quieras. esto puede incluir agregar información dentro de la jerarquía que está codificada en parent_path . por ejemplo:en lugar de /{id}/{id2}/{id3}/ , puede decidir incluir post_date como parte de parent_path:/{id}:{post_date}/{id2}:{post_date2}/{id3}:{post_date3}/ . Esto haría que sea muy fácil obtener el orden y la jerarquía que desea, a expensas de tener que completar el campo por adelantado y administrarlo a medida que cambian los datos]

Espero que esto ayude. ¡Buena suerte!