diff --git a/ecrire/public/boucles.php b/ecrire/public/boucles.php
index 1a8cbf04e226839edf21bb17528e346a86dcaaa3..0f7f8d2fb3d1c45a98524ca407368654e93cb812 100644
--- a/ecrire/public/boucles.php
+++ b/ecrire/public/boucles.php
@@ -168,11 +168,9 @@ function boucle_DOCUMENTS_dist($id_boucle, &$boucles) {
 	// sauf s'ils sont distants (taille inconnue)
 	$boucle->where[]= "($id_table.taille > 0 OR $id_table.distant='oui')";
 
-	$jointure = array_search("spip_types_documents", $boucle->from);
-	if ($jointure) {
-	  $j = $id_table . ".id_type=$jointure" . ".id_type";
-	  if (!in_array($j, $boucle->join)) $boucle->join[]= $j;
-	}
+	$joint = substr(array_search("spip_types_documents", $boucle->from),1);
+	if ($joint AND !isset($boucle->join[$joint]))
+	    $boucle->join[$joint]= array($id_table, 'id_type');
 
 	return calculer_boucle($id_boucle, $boucles);
 }
diff --git a/ecrire/public/calcul-outils.php b/ecrire/public/calcul-outils.php
index 175bd9aea1898da1da0f20c092e36194cbd663d3..f4e87a67f4e7efbc39f186ee8d4b71852c804c28 100644
--- a/ecrire/public/calcul-outils.php
+++ b/ecrire/public/calcul-outils.php
@@ -551,9 +551,25 @@ function spip_optim_select ($select = array(), $from = array(),
 			    $sousrequete = '', $cpt = '',
 			    $table = '', $id = '', $serveur='') {
 
-	foreach($where as $k => $v) { if (!$v) unset($where[$k]);}
-	$where = array_merge($where, $join);
-
+// retirer les criteres vides:
+// {X ?} avec X absent de l'URL
+// {par #ENV{X}} avec X absent de l'URL
+// IN sur collection vide
+
+	foreach($where as $k => $v) { 
+		if ((!$v) OR ($v==1) OR ($v=='0=0')) {
+			unset($where[$k]);
+		}
+	}
+// Construire les clauses determinant les jointures.
+// Il faudrait retirer celles seulement utiles aux criteres finalement absents
+// (et nettoyer $from en consequence)
+// mais la condition necessaire et suffisante n'est pas triviale
+
+	foreach($join as $k => $v) {
+		list($t,$c) = $v;
+		$where[]= "$t.$c=L$k.$c";
+	}
 	return spip_abstract_select($select, $from, $where,
 		  $groupby, array_filter($orderby), $limit,
 		  $sousrequete, $cpt,
diff --git a/ecrire/public/compilo.php b/ecrire/public/compilo.php
index 990c78f0cd4beb834800304e97cea31c464ff809..40fc9426790bcab9f3a790253b5ddf8285cfae83 100644
--- a/ecrire/public/compilo.php
+++ b/ecrire/public/compilo.php
@@ -268,9 +268,8 @@ function calculer_requete_sql(&$boucle)
 		array(' .
 		($boucle->where  ? ('"'. join('", "', $boucle->where) . '"') : '') .
 		'), # WHERE
-		array(' .
-		($boucle->join  ? ('"'. join('", "', $boucle->join) . '"') : '') .
-		'), # WHERE pour jointure
+		' . calculer_dump_array($boucle->join)
+		. ', # WHERE pour jointure
 		' . (!$boucle->group ? "''" : 
 		     ('"' . join(", ", $boucle->group)) . '"') .
 		', # GROUP
@@ -288,6 +287,13 @@ function calculer_requete_sql(&$boucle)
 }
 
 
+function calculer_dump_array($a)
+{
+  $res = "";
+  foreach($a as $k => $v) $res .= ", $k => array('$v[0]', '$v[1]')";
+  return 'array(' . substr($res,2) . ')';
+}
+
 function calculer_from(&$boucle)
 {
   $res = "";
diff --git a/ecrire/public/criteres.php b/ecrire/public/criteres.php
index 17a73b59738b186f93cd26b65b92b5106bd34bca..d6d4bb1c0288c443cc408f81087e1a63d3ee9a26 100644
--- a/ecrire/public/criteres.php
+++ b/ecrire/public/criteres.php
@@ -591,7 +591,7 @@ function calculer_critere_externe_init(&$boucle, $col, $desc, $crit)
 			_T('zbug_boucle') .
 			" $idb " .
 			_T('zbug_critere_inconnu', 
-			    array('critere' => $crit->op)));
+			    array('critere' => $col)));
 }
 
 // deduction automatique des jointures 
@@ -611,7 +611,7 @@ function calculer_jointure(&$boucle, $depart, $arrivee, $col='')
   foreach($res as $r) {
     list($d, $a, $j) = $r;
     $num++;
-    $boucle->join[]= ($id_table ? $id_table : $d) . ".$j=L$num." . $j;
+    $boucle->join[$num]= array(($id_table ? $id_table : $d), $j);
     $boucle->from[$id_table = "L$num"] = $a[0];    
   }
 
@@ -646,10 +646,9 @@ function calculer_chaine_jointures(&$boucle, $depart, $arrivee, $vu=array())
 
   $keys = $ddesc['key'];
 
-  if ($v = $keys['PRIMARY KEY']) {
-    unset($keys['PRIMARY KEY']);
-    $keys = array_merge(split(', *', $v), $keys);
-  }
+  // priorite a la primaire, qui peut etre multiple
+  if ($v = (split(', *', $keys['PRIMARY KEY'])))
+    $keys = $v;
   $v = array_intersect($keys, $adesc['key']); 
   if ($v)
     return array(array($dnom, $arrivee, array_shift($v)));
@@ -659,7 +658,7 @@ function calculer_chaine_jointures(&$boucle, $depart, $arrivee, $vu=array())
 	if ($v && (!in_array($v,$vu)) && 
 	    ($def = trouver_def_table($v, $boucle))) {
 	  list($table,$join) = $def;
-	  $milieu = array_intersect($keys, trouver_cles_table($join['key']));
+	  $milieu = array_intersect($ddesc['key'], trouver_cles_table($join['key']));
 	  foreach ($milieu as $k)
 	    {
 	      $new[] = $v;