Version 15 — Juin 2023 — JLuc
Docs
- [spip.net : Docs
- Les [Les jointures entre tables -> https://www ( spip .net) -> https://www.spip.net/fr_article4254.html]
- https://programmer.spip.net/-Liaisons-entre-tables-jointures-
- [b_b : Divagations [Divagations sur les jointures avec SPIP->https://blog.eliaz.fr/article117.html]
- Wiki Contrib : Jointures.
Tickets
- https://git.spip.net/spip/spip/issues/3894
- https://git.spip.net/spip/spip/issues/2940
- https://git.spip.net/spip/medias/issues/4900
- d’autres
Référence : https://discuter.spip.net/t/a-laide...
Il est très simple avec ?var_mode=debug
de voir comment une boucle est compilée et comment spip crée, ou pas, une jointure.
JLuc : Ce qui est automatique dans les jointures, ainsi que la doc l’indique, c’est le choix du champ sur lequel faire la jointure. Et donc pas forcément le choix des tables, qu’il faut parfois encore expliciter dans la boucle, selon les déclarations php qu’on fait ou qu’on ne fait pas. Par exemple, dans une situation où
- il existe une table t_cccc avec une clé primaire id_cccc
- il existe une table t_dddd qui contient un champ id_cccc
- on ne rien déclare du tout à SPIP en PHP, ni tables, ni champs, ni jointures etc, ce qui a la vertu de la simplicité de permettre de « SPIPer direct clé en main sans prise de tête »
alors, des boucles <BOUCLE_ouafouaf(spip_cccc spip_dddd){id_cccc}>
par exemple sont correctement compilées (avec, donc, les 2 tables explicitement indiquées)
Cerdic : Les jointures ne se font que via des champs qui sont aussi des clés de la table. La déclaration join est un helper pour les cas ou il faut faire la jointure entre des champs pas homonymes par exemple.
Avec un objet CHIEN
et un objet RACE
, et un champ id_race
déclaré sur chien
, pour qu’une jointure entre spip_chiens
et spip_race
puisse se faire, il faut que le champ id_race
de la table spip_chiens
soit déclaré en index de la table, comme le champ id_rubrique
de la table spip_articles
dans le noyau de SPIP.
Thème : alias et type de join - Auteur : John Livingston et JMT19 - Source : https://code.globenet.org/attacfr/campagnodon/-/commit/d2b516b1e3e05fc4598973ae037cf868843b736d - Autre réf : ticket https://git.spip.net/spip/spip/issues/5203#issuecomment-37646 + PR https://git.spip.net/spip/spip/pulls/5205
Les 2 tables campagnodon_transactions
et transactions
ont toutes 2 un champ <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+bW9kZTwvY29kZT4="></span>
.
Dans une jointure <BOUCLE_liste_campagnodon_transactions(CAMPAGNODON_TRANSACTIONS transactions)
on ne peut accéder qu’au #MODE
de la 1re table : campagnodon_transactions
De plus, on souhaite que la jointure soit de type LEFT JOIN
alors que SPIP fait par défaut des INNER JOIN
.
Soluce
On y parvient au moyen du critère suivant, qui déclare la jointure au lieu que ça soit la boucle, la déclare de type LEFT JOIN
et crée un alias sur le champ. La balise qui suit permet ensuite d’y accéder.
function critere_campagnodon_jointure_transactions_dist($idb, &$boucles, $crit) {
$boucle = &$boucles[$idb];
$boucle->from['transactions'] = 'spip_transactions';
$boucle->from_type['transactions'] = 'LEFT';
// le format de join est :
// array(table depart, cle depart [,cle arrivee[,condition optionnelle and ...]])
$boucle->join['transactions'] = array("'campagnodon_transactions'", "'id_transaction'", "'id_transaction'");
$boucle->select[] = 'transactions.mode AS transaction_mode'; // ce champ a un homonyme dans campagnodon_transactions, on contourne.
}
function balise_TRANSACTION_MODE_dist($p) {
return rindex_pile($p, 'transaction_mode', 'campagnodon_jointure_transactions');
}
Usage
<BOUCLE_liste_campagnodon_transactions(CAMPAGNODON_TRANSACTIONS)
{campagnodon_jointure_transactions}
{statut_synchronisation?=#ENV{statut_synchronisation}}
{tri #ENV{par,id_campagnodon_transaction},#GET{defaut_tri}}
{pagination #ENV{nb,10}}
title="<:info_numero_abbreviation|attribut_html:> #ID_TRANSACTION">#ID_TRANSACTION</a>
</td>
<td class="statut">[(#STATUT|match{echec|ok|rembourse}|et{#MESSAGE|trim|strlen}|?{[<abbr title="[(#MESSAGE|attribut_html)[ - (#ERREUR|attribut_html)]]">(#STATUT)</abbr>],#STATUT})]</td>
<td class="transaction_mode">[(#TRANSACTION_MODE|bank_afficher_mode)]</td>
<td class="montant">[(#MONTANT|bank_affiche_montant)]</td>
<td class="mode">#MODE</td>
...
</BOUCLE_liste_campagnodon_transactions>
Alternative
JMT19 : une simple déclaration suffit dans le pipeline table interface :
$interfaces['exceptions_des_tables']['spip_transactions']['transaction_mode'] = array('campagnodon_transaction', 'mode');
#TRANSACTION_MODE
doit alors fonctionner nickel, ainsi que les critères des tris.
À tester et confirmer !
Auteur Stéphane Santon - ref https://discuter.spip.net/t/erreur-sql-sur-boucle/164214
La boucle suivante
<BOUCLE_rubs(ARTICLES){id_mot ?IN #ENV**{sections}}{0,12}>
#SET{etabs, #GET{etabs}|push{#ID_RUBRIQUE}}
</BOUCLE_rubs>
provoque l’erreur suivante quand il y a une valeur de sections
dans l’environnement :
Unknown column 'L1.id_mot' in 'order clause'
SELECT articles.id_rubrique, articles.lang, articles.titre FROM spip_articles AS <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+YXJ0aWNsZXM8L2NvZGU+"></span> WHERE (articles.statut = 'publie') GROUP BY articles.id_article ORDER BY FIELD(L1.id_mot,5) LIMIT 0,12
Solution
L’erreur n’apparaît pas si le corps de la boucle utilise #ID_MOT
car alors SPIP comprend bien qu’il a besoin de cette jointure.
Une soluce est donc d’y insérer [(#ID_MOT|oui)]
pour forcer le compilateur SPIP à inclure la jointure même avec un critère conditionnel.