Mysql
 sql >> Base de données >  >> RDS >> Mysql

ordre sql complexe par

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

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

AJOUT : Merci pour le complément d'information dans votre commentaire. Mettre les résultats dans l'ordre que vous souhaitez n'est pas si facile, car la première clé de commande est la date de création du message de démarrage du fil. 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 (qui ne sont toujours pas assez complètes pour m'empêcher 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 ajuster la syntaxe pour postgre. J'ai testé cela dans SQL Server.

Si cela ne fait toujours pas ce que vous voulez, veuillez être précis sur la façon dont vous voulez 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 le fondement de cette ordonnance. Voici ce que j'ai fait :

  1. Tous les messages d'un fil (fil =un message et ses commentaires) doivent être regroupés.

  2. Dans un fil de discussion, placez le message en haut, suivi de ses commentaires dans l'ordre chronologique inverse. Le thread avec la date/création la plus récente doit être le premier, puis le thread avec la deuxième date/date de création la plus récente, et ainsi de suite. (Vos exemples de données comportaient de nombreux commentaires avec la même date de création, j'ai donc utilisé "id" comme clé d'ordre secondaire pour les commentaires dans un fil.)

Remarque : Votre vidage indique que created_date est mis à jour en CURRENT_TIMESTAMP si un message est modifié. S'il s'agit d'un babillard électronique en direct, sachez que cela peut entraîner la date des commentaires avant le message parent, et cela signifie qu'un fil de discussion restera au premier plan s'il est fréquemment modifié (même sans modification réelle de son texte). (Ce n'est pas pertinent pour ma solution, mais j'ai pensé que cela valait la peine d'être noté.)

Comme une jointure est requise, cette requête sera désormais beaucoup plus lente. Ma suggestion :conservez deux colonnes de date, "thread_last_modified" et "item_last_modified". Vous devrez cascader les mises à jour des démarreurs de thread aux commentaires, mais je pense que cela en vaut la peine s'il n'y a pas beaucoup de mises à jour, car la requête peut être beaucoup plus simple. Je n'ai pas testé cela car cela nécessite plusieurs modifications de 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 #2 :Si vous ne voulez que le fil contenant le commentaire avec id ::thisOne, je pense que vous pouvez ajouter cette ligne entre les clauses ON et 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 ne devrait être évaluée qu'une seule fois pour la requête, mais si ce n'est pas le cas en pratique, vous pouvez la précalculer comme ::thisOneThreadID et ajouter

where parentfeed.id = ::thisOneThreadID

Pour la deuxième solution, en supposant que vous précalculiez à nouveau, essayez

where coalesce(id,reply_id) = ::thisOneThreadID

Au fait, je soupçonne que mes deux solutions fusionneront les threads qui ont été modifiés pour la dernière fois exactement au même moment...