0
votes

Trouvez tous les enregistrements qui ont des balises X classées par temps croissant, MAIS, ceux qui correspondent le plus de balises doivent être groupés en premier

Ok, c'est un peu difficile à expliquer, et le titre n'est pas le meilleur: / mais, en gros, j'ai 3 tables et j'essaye d'écrire une requête qui les renvoie avec 2 niveaux de classement. Le premier par le nombre de "balises" de chaque ligne, et le second par la création de cette ligne.

* Item1
* Item4
* Item2
* Item3

Et je voudrais lister tous les éléments qui ont une ou plusieurs balises, dans ordre croissant par date de création. Mais, et voici où je rencontre des problèmes, je veux que la commande soit basée sur le nombre de balises qui correspondent à un article et, dans cette commande, appliquer les critères ascendants.

Alors, disons J'ai:

Item1 -> CreatedAt(0), Tags(A, B)
Item2 -> CreatedAt(0), Tags(A)
Item3 -> CreatedAt(1), Tags(B)
Item4 -> CreatedAt(1), Tags(A, B)

Ensuite, la recherche de tous les articles avec les balises A et B doit retourner d'abord Item1 et Item4 et commander ceux par ordre croissant de CreatedAt . Et puis Item2 et Item3 et commandez-les par CreatedAt par ordre croissant. Donc, le résultat serait:

Table1: Items
  * ID
  * Name
  * CreatedAt

Table2: Tags
  * ID
  * Name

Table3: TaggedItems
  * TagID
  * ItemID

Je suis inexpérimenté avec SQL donc peut-être y a-t-il des solutions très bien connues à cela si je l'explique même correctement?

Nous apprécions toute aide!


0 commentaires

3 Réponses :


0
votes

Vous pouvez effectuer un tri conditionnel:

select i.*, x.no_tags
from items
cross join lateral (
    select count(*) no_tags
    from taggedItems ti
    inner join tags t on t.id = ti.tagID
    where ti.ItemID = i.ID and t.name in ('A', 'B')
) x
order by
    (x.no_tags > 1) desc,
    case when x.no_tags > 1 then i.createdAt end desc,
    createdAt

La requête commence à partir de la table items , puis utilise une jointure latérale pour récupérer le nombre de balises correspondantes qui appartiennent à la liste cible (j'ai utilisé ('A', 'B') comme dans votre exemple). Ensuite, order by place les éléments qui ont plus d'une balise en premier, et utilise une expression conditionnelle pour les trier par date décroissante; les enregistrements avec une seule balise ne sont pas pris en compte par ce critère de tri, et tombent dans le dernier critère de tri, qui trie par date ascendante.


0 commentaires

0
votes

Essayez :

    select i.id,i,name
    from Items i join TaggedItems ti on i.ID=ti.ItemID
    join Tags t on t.ID=ti.TagID
    group by i.id,i,name
    order by count(*),CreatedAt

L'expression order by count (*) fonctionne pour la plupart des serveurs de base de données.


0 commentaires

1
votes

Utilisez une jointure LEFT de Items à TaggedItems (juste au cas où un élément n'aurait pas de balise du tout) et groupez par élément .
Enfin trier par le nombre de balises décroissant puis par la date:

SELECT i.name
FROM Items i 
LEFT JOIN TaggedItems ti ON ti.ItemID = i.ID
LEFT JOIN Tags t ON t.ID = ti.TagID AND t.Name IN ('A', 'B')
GROUP BY i.ID, i.Name
ORDER BY COUNT(t.ID) DESC, i.CreatedAt

Le tableau Tags n'est pas nécessaire.

Mais si vous voulez les résultats pour une liste de balises comme 'A' et 'B' alors:

SELECT i.name
FROM Items i LEFT JOIN TaggedItems t 
ON t.ItemID = i.ID
GROUP BY i.ID, i.Name
ORDER BY COUNT(t.TagID) DESC, i.CreatedAt


0 commentaires