1
votes

Le moyen le plus efficace de vérifier s'il existe plusieurs relations

Disons que j'ai besoin de trouver tous les articles, qui sont étiquetés avec les trois balises: nourriture , lifestyle et santé . Quelle est la manière la plus efficace de faire cela dans MySQL? Je suis sorti avec cette solution:

select * from articles
where exists (
    select * from tags
    join article_tag on article_tag.tag_id = tags.id
    where article_tag.article_id = articles.id
    and tags.tag = 'food'
) and exists (
    select * from tags
    join article_tag on article_tag.tag_id = tags.id
    where article_tag.article_id = articles.id
    and tags.tag = 'lifestyle'
) and exists (
    select * from tags
    join article_tag on article_tag.tag_id = tags.id
    where article_tag.article_id = articles.id
    and tags.tag = 'health'
)

Cela fonctionne bien, mais cela ressemble à beaucoup de répétition. Quelle est la requête la plus efficace pour résoudre ce problème?


2 commentaires

Étonnant! Vous vous attendez à ce que les gens vous aident avec une requête sans nous dire quel est votre schéma. De plus, vous voulez une "requête efficace" sans rien dire sur les clés.


C'est une question théorique ouverte. Vous pouvez voir le schéma de la requête, pourquoi auriez-vous besoin de moi pour le répéter séparément? Et en ce qui concerne les clés, supposez simplement qu'elles sont là où elles devraient être (dans les colonnes que vous correspondez). Vous faites partie de ces moutons de Stack Overflow, qui s'attendent à des questions qui ne vous font pas réfléchir.


3 Réponses :


0
votes

Vous pouvez utiliser l'agrégation conditionnelle à la place:

select a.*
from articles a join
     article_tag at
     on at.article_id = a.id join
     tags t
     on at.tag_id = t.id
where t.tag in ('food', 'lifestyle', 'health')
group by a.id
having count(*) = 3;

Ceci fait deux hypothèses raisonnables:

  • id est la clé primaire dans article (ou au moins unique)
  • tag_id n'a pas de doublons


1 commentaires

Vous avez une faute de frappe ici, c'est dans , pas i . Oui, je connais cette approche, mais pour une raison quelconque, je la trouve instable en cas de doublons dans la colonne tags.tag ou la paire article_tag . Je sais qu'il existe des index uniques, mais parfois ils ne conviennent pas.



1
votes
select a.*
from articles a 
join (
select articles.id
from articles
join article_tag on article_tag.article_id = articles.id
join tags on article_tag.tag_id = tags.id
where tags.tag in ('food','lifestyle','health')
group by articles.id
having SUM(CASE WHEN tags.tag = 'food' THEN 1 ELSE 0 END) >= 1
AND SUM(CASE WHEN tags.tag = 'lifestyle' THEN 1 ELSE 0 END) >= 1
AND SUM(CASE WHEN tags.tag = 'health' THEN 1 ELSE 0 END) >= 1) b on a.id = b.id

2 commentaires

Désolé, vous devriez lister les colonnes que vous souhaitez sélectionner dans la clause group by, je modifie la réponse pour résoudre ce problème


Mais je veux toutes les colonnes.



0
votes

Voici la solution:

select a.*
from
  articles a
    inner join(
      select at.article_id
      from
        article_tag at
          inner join tags t
          on t.id = at.tag_id
      where t.tag in ('food', 'lifestyle', 'health')
      group by at.article_id
      having count(distinct t.tag) = 3
    ) at
    on at.article_id = a.id


0 commentaires