Jointures et sélections de champs identiques

Bonjour,
j’ai une boucle sur Articles qui fait une jointure avec rubriques et mots.

<BOUCLE_art(ARTICLES){id_mot=#GET{listemc}}{par date}{inverse}{id_groupe IN 2,3,9}{0,8}{doublons}{rubriques.titre}>

Bon le {rubriques.titre} à la fin c’est juste pour forcer la jointure sur rubrique car je ne sais pas faire autrement. Mais surtout, j’aimerais récupérer le titre de MOTS et le titre de RUBRIQUES.

Il y a dans ce cas là 3 #TITRE possibles, c’est celui de la table principale qui est pris.

La syntaxe de la requête est (presque) OK:

SELECT articles.date, articles.id_article, articles.id_rubrique, articles.titre, articles.id_rubrique, articles.id_article, articles.lang
FROM spip_articles AS `articles`  
INNER JOIN spip_rubriques AS L4 ON ( L4.id_rubrique = articles.id_rubrique ) 
INNER JOIN spip_mots_liens AS L2 ON ( L2.id_objet = articles.id_article AND L2.objet='article') 
INNER JOIN spip_mots AS L3 ON ( L3.id_mot = L2.id_mot ) 
INNER JOIN spip_mots_liens AS L1 ON ( L1.id_objet = articles.id_article AND L1.objet='article')
WHERE (articles.statut = 'publie')
	AND articles.date<'2024-02-22 00:00:00'
	AND (L1.objet = 'article')
	AND (L1.id_mot = 49)
	AND (L2.objet = 'article')
	AND (L3.id_groupe  IN (2,3,9))
	AND (articles.id_article NOT IN (30744))
	AND (articles.id_rubrique NOT IN (41,42,43))
GROUP BY articles.id_article
ORDER BY articles.date DESC
LIMIT 0,8

il me manque juste de pouvoir récupérer L4.titre et L3.titre dans mon SELECT

J’ai essayé plusieurs choses mais sans succès. Est ce qu’il y a un mécanisme du genre #mots.TITRE ou #rubriques.TITRE pour récupérer des champs d’une autre table qui ont des noms identiques ?

Merci!

Bonsoir,

Une première piste : Forcer des jointures - Programmer avec SPIP 4 :

Cependant, une différence de taille existe : actuellement, seule l’écriture déclarant l’ensemble des tables permet de faire afficher une balise #CHAMP d’une autre table.

Mais aussi #CHAMP_SQL - SPIP où tu devrais pouvoir faire #CHAMP_SQL{table.titre}

Coucou RealET, merci pour ta réponse.

C’est vrai que je ne l’avais pas précisé mais j’avais un peu cherché avant de poster ici et j’avais lu la doc que tu m’indiques :wink:
Du coup, au début j’avais forcé la jointure comme indiqué avec un (ARTICLES spip_rubriques) (pas besoin pour mots car spip a trouvé la jointure tout seul) mais ça ne suffit pas, il faut forcément forcer {rubriques.xxx} dans les critères pour que la jointure fonctionne.

Et CHAMP_SQL, béh je ne comprends pas. Je l’avais bien vu, et j’en déduisais qu’il fallait que je mette #CHAMP_SQL{mots.titre} et #CHAMP_SQL{rubriques.titre} mais ça ne fonctionne pas. Du coup soit j’ai la mauvaise syntaxe, soit j’ai pas compris, soit il y a une limitation quelque part…

Alors, c’est peut-être bien une limitation de cette balise :frowning:

Mince :confused:
Dans ces cas là, qu’est ce qui est recommandé comme solution de contournement? Est ce que je peux déporter ma requête SQL (écrite en PHP) dans mes_fonctions.php par exemple?
L’idée serait de toujours bénéficier du cache. Je vais voir si ça fonctionne, mais je suis preneur de toute solution propre et élégante!

Encore merci!

@cpol0
As-tu essayé avec simplement un critère id_rubrique ?

#On est d’accord que CHAMP ici sera remplacé par le champ sql, exemple par NOM ou TITRE
Tu as bien #INFO_CHAMP{objet,id_objet} mais je pense que cela créé une nouvelle requête, à voir …
et c’est intéressant d’indiquer ensuite ici si cela fonctionne :slight_smile:

Ou encore #_n:BALISE qui va chercher dans l’imbrication des boucles

Merci touti.

As-tu essayé avec simplement un critère id_rubrique ?

Je suis désolé je ne saisis pas ce que tu veux dire. Là mon problème ce n’est pas la jointure mais la manière de récupérer les valeurs depuis la jointure. Si j’ai bien compris, le critère ne sert que dans la boucle, pas une fois dedans?

Pour la _n:Balise, le problème c’est que c’est 2 boucles imbriquées (ce que j’ai déjà en fait). Et c’est justement ce que je veux enlever, car ça explose mon nombre de requêtes SQL alors qu’en PHP je sais le faire en une seule fois…

Mmm, tu indiques pourtant dans ta demande initiale

Bon le {rubriques.titre} à la fin c’est juste pour forcer la jointure sur rubrique car je ne sais pas faire autrement.

si tu mets juste {id_rubrique} en critère (avec un environnement adequat?)


Tu peux aussi tenter encore ta chance avec le critère where et/ou les boucles DATA (itérateurs)

Les gourmandises emballées sont là

Il y a 12 ans déjà j’écrivais que ça n’était pas possible, et je crois bien que c’est encore le cas actuellement cf :

On remarque que les jointure générées par SPIP sont correctes, mais il reste un problème. Il ne sera pas possible d’afficher le titre et le descriptif du point GIS car des champs homonymes sont présents dans la table spip_articles (première table de la boucle). Et comme SPIP ne permet pas de notation du type #gis.TITRE comme on pourrait le voir en SQL, cette solution ne convient pas.

@touti ah OK compris! Oui en effet, mais comme j’ai réussi à faire ma jointure (même pas très propre) j’étais passé à « comment récupérer mes données ». Merci à toi! Bon, pas sûr que j’essaierai vu la réponse qui suit…

@b_b j’avais lu la phrase que tu cites, mais en 12 ans j’imagine que spip a évolué donc j’avais l’espoir que ça soit devenu possible…
Par contre grand merci pour le lien qui suit car celui là je l’avais pas trouvé. Donc en gros il faut que je crée un critère perso (solution 3 du doc) pour faire mes jointures aux petits oignons.
Ma foi ça se tente!

Merci à tous pour votre aide! :pray:

Re bonjour @cpol0,
et @b_b
Vite fait, cette boucle

<BOUCLE_art(ARTICLES){id_mot IN 34,7}{0,8}{id_parent IN 27}{'<hr>'}>

<code>#<!-- -->TITRE = </code>#TITRE<br>

<code>#<!-- -->INFO_TITRE{mot,#ID_MOT} = </code>#INFO_TITRE{mot,#ID_MOT}<br>

<code>#<!-- -->INFO_TITRE{article,#ID_ARTICLE} = </code>#INFO_TITRE{article,#ID_ARTICLE}<br>

<code>#<!-- -->INFO_TITRE{rubrique,#ID_RUBRIQUE} = </code>#INFO_TITRE{rubrique,#ID_RUBRIQUE}<br>

</BOUCLE_art>

me retourne

#TITRE = Bouillon blanc
#INFO_TITRE{mot,34} = Mellifère
#INFO_TITRE{article,584} = Bouillon blanc
#INFO_TITRE{rubrique,1} = Fleurs

PS merci d’utiliser l’écriture inclusive comme spécifié dans la charte SPIP

Ya des pistes dans cette discussion : #4703 - Critère {select ...} - spip - SPIP on GIT notamment le recours à une boucle DATA.
L’exemple donné est BOUCLE_ma_requete(DATA){source sql, "SELECT id_article as mon_id, SUBSTRING(titre,3,10) as letitre FROM spip_articles"}
alors peux tu mettre à la place la grosse requête JOIN de ta boucle, que tu sembles connaître, avec un alias ze_graal qui va bien pour la valeur que tu veux récupérer,
et tu la récupères avec #VALEUR{ze_graal} ?

:thinking:
Alors j’avais exclu INFO_XXX car la doc précise bien que:

est une balise qui permet de récupérer la valeur d’un champ en base de données sans nécessairement faire une boucle

Donc une requête en plus alors que j’en veux en moins, et de toute façon j’ai quand même besoin d’une boucle.

Mais en essayant la requête passe de
SELECT articles.date, articles.id_article, articles.titre, articles.id_rubrique, articles.id_article, articles.lang
à
SELECT articles.date, articles.id_article, articles.id_rubrique, L1.id_mot, articles.titre, articles.id_rubrique, articles.id_article, articles.lang.
Et sans me faire de requête supplémentaire.
Donc c’est pas vraiment ce que j’aurais écrit car je voulais le titre et pas l’id, mais la balise semble faire un peu de post processing (où, quoi comment, aucune idée) mais ouais on dirait bien que ça marche impec car ça m’affiche bien les bons noms de titres!
En plus la syntaxe de la boucle reste la même, pas besoin de critère abscons et j’ai juste besoin de rajouter dans ma boucle:

 #INFO_TITRE{rubrique, #ID_RUBRIQUE}
 #INFO_TITRE{mot, #ID_MOT}

Bref, je vérifierai demain matin car là je dois filer mais super bonne nouvelle pour finir la soirée!

@JLuc je check demain ta réponse merci.

Merci à toutes et tous :wink:

@cpol0 tu vas avoir droit à ton RTFM :slight_smile:
Et cher aïeul @b_b :stuck_out_tongue: SPIP a quand même évolué uuhuhu

Et donc, c’est bien marqué dans la doc de #INFO_XXX

Cette fonctionnalité est optimisée pour ne pas faire plusieurs requêtes SQL sur la même table. Vous pouvez donc utiliser plusieurs fois la balise sur le même objet sans inquiétude.

Et y’en a qui sont pas d’accord pour que je republie !

Il semblerait que votre lien vers (la doc de #INFO_) a déjà été publié dans le sujet par (me) dans une réponse de 20 févr. '24. Voulez-vous vraiment le publier à nouveau ?

1 « J'aime »

Désolée chère amie, mais SPIP ne permet toujours pas à ce jour de passer outre le problème que je pointais. Aïeul peut-être, mais pas encore sénile (j’espère) ^^

Sur un même objet/id_objet, oui.

#INFO_TITRE{rubrique,123} génère une requête, #INFO_ID_PARENT{rubrique,123} n’en re-génère pas.
Mais #INFO_TITRE{rubrique,456} en génère une à nouveau.

Oui, @b_b et @nicod_ vous avez raison. Je reconnais platement mon erreur, me fiant à la doc, je n’ai pas testé avant ce que ça générait en terme de requêtes.

Pour info et documentation, je confirme que la soluce que j’évoque plus haut marche bien.

  1. Pour simplifier l’écriture du squelette HTML, créer une filtre get_query_jointure dans le fichiers de _fonctions.php : cette fonction reçoit $id_mot et renvoie la query, écrite sur une seule ligne (sans retour à la ligne). Dans la query il y a 2 alias : SELECT L3.titre as l3_titre, L4.titre as l4_titre.
  2. Ensuite la boucle DATA spécifie le retour de cette fonction comme valeur de la source sql et peut utiliser les alias avec #VALEUR

Donc dans le _fonctions.php :

function get_query_jointure($id_mot) {
	$id_mot = ($id_mot ?: 3);
	return "SELECT articles.date, articles.id_article, articles.id_rubrique, articles.titre, articles.id_rubrique, articles.id_article, articles.lang, L3.titre as l3_titre, L4.titre as l4_titre   FROM spip_articles AS `articles` INNER JOIN spip_rubriques AS L4 ON ( L4.id_rubrique = articles.id_rubrique )  INNER JOIN spip_mots_liens AS L2 ON ( L2.id_objet = articles.id_article AND L2.objet='article') INNER JOIN spip_mots AS L3 ON ( L3.id_mot = L2.id_mot )  INNER JOIN spip_mots_liens AS L1 ON ( L1.id_objet = articles.id_article AND L1.objet='article') WHERE (articles.statut = 'publie') 	AND (L1.objet = 'article') 	AND (L1.id_mot = $id_mot) 	AND (L2.objet = 'article') GROUP BY articles.id_article ORDER BY articles.date DESC LIMIT 0,8";
}

Et ensuite la boucle

#SET{q,#GET{listemc}|get_query_jointure}
<B_ma_requete><ul>
<BOUCLE_ma_requete(DATA){source sql,#GET{q}}>
<li>CLE:#CLE l3_titre:#VALEUR{l3_titre} l4_titre:#VALEUR{l4_titre}</li>
</BOUCLE_ma_requete>
</ul></B_ma_requete>
Pas de résultats
<//B_ma_requete>

Il y a 2 autres solutions que je n’ai pas testé sur la page Difficultés avec jointures et solutions :

  • Déclarer les alias dans un critère maison
  • Déclarer les alias dans $interfaces['exceptions_des_tables']
2 « J'aime »