2009-08-08 5 views
4
id | message | reply id | date 

1  | my new app.. |  0   | 10/10/2009 (latest message on top, follow by replies) 
5  | love ur app.. |  1   | 11/10/2009 (this should show under the main message) 
6  | another comm |  1   | 12/10/2009 
2  | application 2 |  0   | 09/10/2009 
3  | reply of 2 |  2   | 11/10/2009 

Je veux afficher les derniers commentaires et ses réponses après les commentaires principaux. Évidemment, les réponses auront la date la plus tardive, donc je ne peux pas trier par date, parce que les réponses seront au-dessus de la principale. Je ne suis pas sûr de savoir comment le faire correctement avec une requête. Toute idée est s'il vous plaît.complex sql commander par

vidage de base de données

: http://pastie.org/576963

+0

exemple si confus: http://pastie.org/577011 – Basit

Répondre

6

Je suppose que "réponse ID" est 0 pour les articles et est le numéro d'article pour les commentaires. Si tel est votre conception, cela devrait fonctionner:

select * from yourTable 
order by 
    case when "reply id" = 0 then id else "reply id" end, id 

AJOUTÉE: Merci pour les informations supplémentaires dans votre commentaire. Mettre les résultats dans l'ordre que vous voulez n'est pas si facile, car la première clé de commande est le created_date de la publication du thread-starter. Ce n'est pas dans la ligne de données, vous avez donc besoin d'une jointure. Voici ma meilleure estimation basée sur les informations supplémentaires (ce qui est pas encore assez complet pour me garder de deviner):

select 
    f.id, f.user_id, f.type, f.reply_id, f.text, f.url, f.created_date, 
    coalesce(parentfeed.created_date,f.created_date) as thread_date 
from feed as f left outer join feed as parentfeed 
on f.reply_id = parentfeed.id 
order by 
    thread_date desc, 
    case when f.reply_id = 0 then 0 else 1 end, 
    created_date desc, id; 

Vous devrez peut-être modifier la syntaxe pour postgre. J'ai testé cela dans SQL Server.

Si cela ne vous convient toujours pas, veuillez préciser comment vous souhaitez récupérer les données. De préférence, dites-moi l'ordre "id" que je devrais voir pour les données dans votre fichier de vidage, et aussi expliquer la base de cette commande. Voici ce que j'ai fait:

  1. Tous les messages d'un fil de discussion (fil = un message et ses commentaires) doivent être regroupés. Dans un fil, placez le message en haut, suivi de ses commentaires dans l'ordre chronologique inverse. Le thread avec le plus récent/_date créé doit être d'abord, puis le thread avec le second plus récent created_date, et ainsi de suite.(Vos données d'échantillon ont eu beaucoup de commentaires avec le même CREATED_DATE, donc j'ai utilisé « id » comme une clé de commande secondaire pour les commentaires dans un fil.)

Note: Votre décharge indique que CREATED_DATE est mis à jour à CURRENT_TIMESTAMP si un message est modifié. S'il s'agit d'un forum de discussion en direct, sachez que cela peut entraîner la date avant le message parent, ce qui signifie qu'un thread restera en haut s'il est fréquemment modifié (même sans modification réelle de son texte). (Ce n'est pas pertinent pour ma solution, mais je pensais que cela valait la peine d'être noté.)

Parce qu'une jointure est requise, cette requête sera maintenant beaucoup plus lente. Ma suggestion: maintenir deux colonnes de date, "thread_last_modified" et "item_last_modified". Vous devrez mettre en cascade les mises à jour de thread-starters aux commentaires, mais je pense que ça vaut le coup s'il n'y a pas beaucoup de mises à jour, car la requête peut être beaucoup plus simple. Je ne l'ai pas testé car il nécessite plusieurs modifications à votre conception:

select 
    id, user_id, type, reply_id, text, url, thread_last_modified, item_last_modified 
from feed 
order by 
    thread_last_modified desc, 
    case when f.reply_id = 0 then 0 else 1 end, 
    item_last_modified desc, id; 

AJOUTÉE # 2: Si vous ne souhaitez que le fil contenant le commentaire avec id :: thisOne, je pense que vous pouvez ajouter cette ligne entre la marche et la clause ORDER BY (pour ma première solution ajoutée, la jointure):

where parentfeed.id = (
    select coalesce(reply_id,id) 
    from feed 
    where id = ::thisOne 
) 

en théorie, cette recherche devrait être évaluée qu'une seule fois pour la requête, mais si ce n'est pas dans la pratique, vous pouvez précalculer il as :: thisOneThreadID et ajouter

where parentfeed.id = ::thisOneThreadID 

Pour la deuxième solution, en supposant que vous Précalculer à nouveau, essayez

where coalesce(id,reply_id) = ::thisOneThreadID 

D'ailleurs, je soupçonne que mes deux solutions fusionner les discussions qui ont été modifié pour la dernière exactement au même moment ...

+0

bien que je veux les derniers messages principaux (reply_id = 0) pour être sur le dessus puis à droite sous chaque réponse les messages devraient partir. - message principal - message de réponse - message principal - message de réponse essayez le fichier de vidage SQL suivante, voir si votre requête fonctionne, ne pas fonctionne pour moi: http://pastie.org/578558 – Basit

+0

aussi s'il vous plaît regarder la date, ne pas regarder l'id, id ne sera pas entier, il sera filaire id comme youtube (id: CxewVEwed) – Basit

+0

Je devine encore sur ce que vos données signifie. Le vidage n'aide pas beaucoup, sauf si vous fournissez le résultat que vous voulez voir à partir de ces données, ou une description claire de l'ordre que vous voulez voir les résultats. Ce que je peux dire de votre commentaire est que vous aurez besoin d'un joindre. Les lignes de la table ne contiennent pas assez d'informations pour ORDER BY pour résoudre le problème sans jointure, car les messages doivent être classés en fonction de la date du message parent. L'identifiant, pas la date, est stocké dans la ligne. Je vais ajouter à ma réponse originale. –

2

.... order by(certains prédicat qui est vrai pour les "principaux commentaires", mais pas followups)desc, date desc

Puisque vous ne faites pas clairement ce qui distingue un "commentaire principal", c'est tout ce que je peux faire pour vous. Si, comme dans votre exemple, tous les principaux commentaires avaient un reply_id de zéro, cela pourrait être:

order by case reply_id = 0 then 1 else 0 end desc, date desc

Notez que l'utilisation de la déclaration de cas plutôt que de commander simplement par reply_id est nécessaire, parce que vous voulez la première expression pour avoir la même valeur (à savoir, zéro) pour tous les messages non principaux, de sorte qu'ils sont triés exclusivement par la deuxième expression, date.

(Oh, si je comprends votre schéma, reply_id devrait vraiment être nommé in_repky_to_id.)

+0

C'est une technique utile que j'utilise souvent. –

+0

bien je veux que les derniers messages principaux (reply_id = 0) soient sur le dessus alors juste sous chaque réponse les messages devraient aller. - message principal - message de réponse - message principal - message de réponse essayez le fichier de vidage SQL suivante, voir si votre requête fonctionne, ne pas fonctionne pour moi: http://pastie.org/578558 – Basit

+0

aussi s'il vous plaît regarder la date, ne pas regarder l'id, id ne sera pas entier, il sera filaire id comme youtube (id: CxewVEwed) – Basit

0

je ne suis pas sûr de vos besoins, de sorte que ma réponse est une abstraction ... au maximum - peuvent avoir besoin de être un min (encore une fois, je ne suis pas clair sur vos besoins exacts)

select 
    y.column1 
    , y.column2 
    , y.column3 
    , y.datecolumn 
from 
(select 
    column1 
    , max(datecolumn) as rank_date 
from tableA 
group by column1) as x 
inner join tableA y on x.id = y.id 
order by x.rank_date, y...., y.... desc, y... asc, etc... 

si vous utilisez le serveur SQL, il y a une fonction appelée sur row_number que vous pouvez utiliser aussi bien.

0

Voici un lien sur la représentation de données hiérarchiques dans une base de données relationnelle. http://dev.mysql.com/tech-resources/articles/hierarchical-data.html

L'essentiel, vous devez vous joindre à la table pour autant de niveaux que vous voulez. Les données d'exemple fournies avaient seulement deux niveaux de profondeur.

SELECT 
f1.id AS `parent_id`, 
f1.text AS `parent_text`, 
f1.created_date AS `parent_created_date`, 
f2.* 
FROM 
feed AS `f1` 
LEFT JOIN feed `f2` ON (f1.id = f2.reply_id) 
WHERE f1.reply_id = 0 
ORDER BY f1.created_date DESC, f2.created_date DESC 
; 

Les informations de l'article parent sera dans la f1. * Colonnes et les informations des enfants (replys) seront dans les colonnes f2. *.

Questions connexes