Les jointures entre tables

Exemples de boucles produisant une jointure multiple entre 3 tables

  • Apparu en : SPIP 2.0

Nous voulons, en une boucle, récupérer les informations des articles d’une (ou plusieurs) rubrique à laquelle est affecté un mot clef (que nous connaissons).

<BOUCLE_a(ARTICLES spip_mots_rubriques spip_mots){titre_mot=truc}>

produira la requête sql suivante :

  SELECT articles.id_rubrique,
         articles.id_article,
         ...
         articles.lang
    FROM spip_articles AS `articles`
         INNER JOIN spip_mots_rubriques AS L1
                 ON L1.id_rubrique = articles.id_rubrique
         INNER JOIN spip_mots AS L2
                 ON L2.id_mot = L1.id_mot
   WHERE articles.statut = 'publie'
     AND L2.titre = 'truc'
GROUP BY articles.id_article

nous voulons en une boucle sélectionner aléatoirement un document dans un secteur. À savoir que ce secteur ne contient pas d’articles, seulement des rubriques avec des documents liés (photothèque).

<BOUCLE_d(spip_documents_liens rubriques)
          {objet = rubrique}
          {rubriques.id_secteur = 13}
          {par hasard}
          {0, 1}>
  #LOGO_DOCUMENT
</BOUCLE_d>

-  la table spip_documents_liens est une table qui recense les liens (jointures) entre un document et un objet (article, rubrique, mot, site...).

des entrées type de cette table pourraient ressembler à :

id_document id_objet objet vu
14 36 article non
363 66 rubrique non
... ... ... ...

nous allons donc chercher dans cette table les documents rattachés à une rubrique {objet = rubrique}

Mais nous voulons aussi que cette rubrique soit descendante de la rubrique secteur d’id 13

nous devons donc établir dans notre requête une jointure entre la table spip_documents_liens et spip_rubriques

cette jointure sera faite sur d’un côté :
l’id_objet de spip_documents_liens, de l’autre
l’id_rubrique de spip_rubriques

pour cela nous indiquons à spip que nous voulons cette jointure spécifique en donnant les 2 tables à la boucle

<BOUCLE_d(spip_documents_liens rubriques)...

enfin, pour spécifier notre restriction concernant le secteur 13, nous précisons le critère {rubriques.id_secteur = 13} en spécifiant explicitement le nom complet du champ (nom de la table inclu) pour que la requête n’aille pas chercher un champ spip_documents_liens.id_secteur qui n’existe pas.

-  à partir de cette boucle, donc, nous avons alors accès à tous les champs de spip_documents_liens et tous ceux de spip_rubriques :

#ID_DOCUMENT
#ID_OBJET
#OBJET
#VU

#ID_RUBRIQUE
#ID_PARENT
#TITRE
#DESCRIPTIF
#TEXTE
#ID_SECTEUR
...

-  la requête sql produite par notre boucle :

  SELECT rand() AS alea,
         spip_documents_liens.id_document
    FROM spip_documents_liens AS `spip_documents_liens`
         INNER JOIN spip_rubriques AS L1
                 ON L1.id_rubrique = spip_documents_liens.id_objet
                AND spip_documents_liens.objet = 'rubrique'
   WHERE spip_documents_liens.objet = 'rubrique'
     AND L1.id_secteur = 13
GROUP BY spip_documents_liens.id_document,
         spip_documents_liens.id_objet,
         spip_documents_liens.objet
ORDER BY alea
   LIMIT 0,1

-  enfin, la balise #LOGO_DOCUMENT nous retournera le source html :

<img src='local/cache-vignettes/L135xH150/Image_10-d84e2.png'
width='135' height='150' style='height:150px;width:135px;' alt=''
class='spip_logos' />

et si nous voulions le nom du fichier document, que nous ne pouvons avoir directement avec cette requête car le champ spip_documents.fichier n’est pas relevé (pas de jointure avec la table spip_documents), alors il faut déclarer une jointure supplémentaire sur la table spip_documents :

<BOUCLE_d(spip_documents_liens documents rubriques)
          {objet = rubrique}
          {rubriques.id_secteur = 13}
          {par hasard}
          {0, 1}>
#LOGO_DOCUMENT / #FICHIER
</BOUCLE_d>

requête produite :

  SELECT rand() AS alea,
         spip_documents_liens.id_document,
         L2.fichier
    FROM spip_documents_liens AS `spip_documents_liens`
         INNER JOIN spip_documents AS L2
                 ON L2.id_document = spip_documents_liens.id_document
         INNER JOIN spip_rubriques AS L1
                 ON L1.id_rubrique = spip_documents_liens.id_objet
                AND spip_documents_liens.objet='rubrique'
   WHERE spip_documents_liens.objet = 'rubrique'
     AND L1.id_secteur = 13
GROUP BY spip_documents_liens.id_document,
         spip_documents_liens.id_objet,
         spip_documents_liens.objet
ORDER BY alea
   LIMIT 0,1

attention n° 1 :
-  ici, nous avons presque accès à tous les champs des 3 tables
« presque » car attention aux champs homonymes :
les #TITRE, #DESCRIPTIF, #MAJ, #STATUT et #DATE affichés, qui sont des champs homonymes dans spip_documents et spip_rubriques, seront ceux de spip_documents (table première de la requête) !

attention n° 2 :
-  les écritures de nom de table

si :

  <BOUCLE_d(DOCUMENTS_LIENS)>
  <BOUCLE_d(documents_liens
  <BOUCLE_d(SPIP_DOCUMENTS_LIENS
  <BOUCLE_d(spip_documents_liens 

sont équivalentes ;

tout comme :

  <BOUCLE_d(documents_liens documents rubriques
  <BOUCLE_d(documents_liens documents spip_rubriques
  <BOUCLE_d(documents_liens documents RUBRIQUES

sont équivalentes ;

et encore :

  <BOUCLE_d(documents_liens documents
  <BOUCLE_d(documents_liens spip_documents
  <BOUCLE_d(spip_documents_liens spip_documents
  <BOUCLE_d(spip_documents_liens documents 

sont aussi équivalentes ;

il n’en va pas de même avec :

  <BOUCLE_d(DOCUMENTS_LIENS DOCUMENTS)>
  <BOUCLE_d(documents_liens DOCUMENTS)>
  <BOUCLE_d(SPIP_DOCUMENTS_LIENS DOCUMENTS)>
  <BOUCLE_d(spip_documents_liens DOCUMENTS)>

où la mise en capitales de documents occasionne une perte de jointure
entre spip_documents_liens et spip_documents

Tables déclarées et tables non déclarées

La documentation ci dessus porte sur des tables du noyau de SPIP, et elle est valable pour toutes tables déclarées au moyen de l’API de déclaration des tables.

Lorsqu’une table n’est pas déclarée, il faut utiliser son nom complet, avec le préfixe, en minuscules.

Voir aussi sur programmer.spip.net : Automatisme des jointures.

Auteur denisb Publié le : Mis à jour : 07/07/23

Traductions : català, English, français, Nederlands, українська