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

Problème SQL :relation un à plusieurs et modèle EAV

La réponse courte à votre question est non, il n'y a pas de construction simple dans MySQL pour obtenir l'ensemble de résultats que vous recherchez.

Mais il est possible d'élaborer soigneusement (méticuleusement) une telle requête. Voici un exemple, j'espère que vous saurez le déchiffrer. Fondamentalement, j'utilise des sous-requêtes corrélées dans la liste de sélection, pour chaque attribut que je veux renvoyer.

SELECT t.id
     , t.name
     , t.nickname

     , ( SELECT v1.attribute_value 
           FROM team_information v1 
           JOIN attributes a1
             ON a1.id = v1.attribute_id AND a1.attribute_name = 'city'
          WHERE v1.team_id = t.id ORDER BY 1 LIMIT 1
       ) AS city

     , ( SELECT v2.attribute_value
           FROM team_information v2 JOIN attributes a2
             ON a2.id = v2.attribute_id AND a2.attribute_name = 'captain'
          WHERE v2.team_id = t.id ORDER BY 1 LIMIT 1
       ) AS captain

     , ( SELECT v3.attribute_value
           FROM team_information v3 JOIN attributes a3
             ON a3.id = v3.attribute_id AND a3.attribute_name = 'f_number'
          WHERE v3.team_id = t.id ORDER BY 1 LIMIT 1
       ) AS f_number

  FROM teams t
 ORDER BY t.id

Pour les attributs "à valeurs multiples", vous devez extraire chaque instance de l'attribut séparément. (Utilisez la LIMITE pour préciser si vous récupérez le premier, le second, etc.)

     , ( SELECT v4.attribute_value
           FROM team_information v4 JOIN attributes a4
             ON a4.id = v4.attribute_id AND a4.attribute_name = 'nickname'
          WHERE v4.team_id = t.id ORDER BY 1 LIMIT 0,1
       ) AS nickname_1st

     , ( SELECT v5.attribute_value
           FROM team_information v5 JOIN attributes a5
             ON a5.id = v5.attribute_id AND a5.attribute_name = 'nickname'
          WHERE v5.team_id = t.id ORDER BY 1 LIMIT 1,1
       ) AS nickname_2nd

     , ( SELECT v6.attribute_value
           FROM team_information v6 JOIN attributes a6
             ON a6.id = v6.attribute_id AND a6.attribute_name = 'nickname'
          WHERE v6.team_id = t.id ORDER BY 1 LIMIT 2,1
       ) AS nickname_3rd

J'utilise le surnom comme exemple ici, car les clubs de football américains ont souvent plus d'un surnom, par ex. Chicago Fire Soccer Club a des surnoms :'The Fire', 'La Máquina Roja', 'Men in Red', 'CF97', et al.)

PAS UNE RÉPONSE À VOTRE QUESTION, MAIS ...

Ai-je déjà mentionné à plusieurs reprises à quel point je n'aime pas travailler avec les implémentations de bases de données EAV ? Qu'est-ce que l'OMI devrait être une requête très simple se transforme en une bête trop compliquée d'une requête potentiellement atténuée.

Ne serait-il pas beaucoup plus simple de créer un tableau où chaque "attribut" est une colonne distincte ? Ensuite, les requêtes pour renvoyer des ensembles de résultats raisonnables sembleraient plus raisonnables...

SELECT id, name, nickname, city, captain, f_number, ... FROM team

Mais ce qui me fait vraiment frissonner, c'est la perspective qu'un développeur décide que le LDQ devrait être "caché" dans la base de données en tant que vue, pour permettre la requête "plus simple".

Si vous suivez cette voie, veuillez résister à toute envie de stocker cette requête dans la base de données en tant que vue.