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

L'utilisation de DISTINCT dans JOIN crée des problèmes

Une approche consiste à utiliser une vue en ligne, comme la requête que vous avez déjà. Mais au lieu d'utiliser DISTINCT, vous utiliseriez un GROUP BY pour éliminer les doublons. La vue en ligne la plus simple pour répondre à vos besoins serait :

( SELECT n.item_number, n.name, n.type_code
    FROM itpitnam n
   GROUP BY n.item_number
) itpitnam

Bien qu'il ne soit pas déterministe quant à la ligne d'itpitnam à partir de laquelle les valeurs de name et type_code sont récupérées. Une vue en ligne plus élaborée peut rendre cela plus spécifique.

Une autre approche courante de ce type de problème consiste à utiliser une sous-requête corrélée dans la liste SELECT. Pour renvoyer un petit ensemble de lignes, cela peut fonctionner raisonnablement bien. Mais pour renvoyer de grands ensembles, il existe des approches plus efficaces.

SELECT i.identifier
     , i.name
     , i.subtitle
     , i.description
     , i.itemimg 
     , i.mainprice
     , i.upc
     , i.isbn
     , i.weight
     , i.pages
     , i.publisher
     , i.medium_abbr
     , i.medium_desc
     , i.series_abbr
     , i.series_desc
     , i.voicing_desc
     , i.pianolevel_desc
     , i.bandgrade_desc
     , i.category_code
     , r.overall_ranking
     , ( SELECT n1.name
           FROM itpitnam n1
          WHERE n1.item_number = r.item_number
          ORDER BY n1.type_code, n1.name
          LIMIT 1
       ) AS artist
     , ( SELECT n2.type_code
           FROM itpitnam n2
          WHERE n2.item_number = r.item_number
          ORDER BY n2.type_code, n2.name
          LIMIT 1
       ) AS type_code
  FROM itpitems i
  JOIN itprank r
    ON r.item_number = i.identifier
 WHERE mainprice > 1
 LIMIT 3

Cette requête renverra le jeu de résultats spécifié, avec une différence significative. La requête d'origine montre un INNER JOIN au itpitnam table. Cela signifie qu'une ligne sera renvoyée UNIQUEMENT s'il existe une ligne correspondante dans le itpitnam table. La requête ci-dessus, cependant, émule une OUTER JOIN, la requête renverra une ligne lorsqu'il n'y a pas de ligne correspondante trouvée dans itpitnam .

MISE À JOUR

Pour de meilleures performances de ces sous-requêtes corrélées, vous aurez besoin d'un index approprié disponible,

... ON itpitnam (item_number, type_code, name)

Cet index est le plus approprié car il s'agit d'un "index de couverture", la requête peut être entièrement satisfaite à partir de l'index sans référencer les pages de données dans la table sous-jacente, et il y a un prédicat d'égalité sur la colonne principale et un ORDER BY sur les deux prochaines colonnes, cela évitera une opération de "tri".

--

Si vous avez la garantie que soit le type_code ou name colonne dans la table itpitnam est NOT NULL, vous pouvez ajouter un prédicat pour éliminer les lignes qui "manquent" une ligne correspondante, par exemple

HAVING artist IS NOT NULL

(L'ajout de cela aura probablement un impact sur les performances.) En l'absence de ce type de garantie, vous devez ajouter un INNER JOIN ou un prédicat qui teste l'existence d'une ligne correspondante, pour obtenir un comportement INNER JOIN.