Skip to main content

Requête SQL principale

La requête centrale du fichier index.php alimente le tableau de consultation. Elle est conçue pour éliminer les doublons issus des jointures multiples (prix, concurrents, contrats).


Principe anti-doublons

Le problème classique avec plusieurs jointures 1-N est la multiplication des lignes. La solution mise en place est de pré-sélectionner un seul enregistrement pour chaque relation N via des sous-requêtes de sélection de premier/dernier ID.


Sous-requêtes clés

(A) Dernier prix actif

LEFT JOIN (
SELECT rf2.ID_REFERENCE, MAX(pa2.ID_PRIX) AS ID_PRIX_DERNIER
FROM REFERENCES_FOURNISSEURS rf2
JOIN PRIX_ACHAT pa2 ON pa2.ID_REF_FOURNISSEUR = rf2.ID_REF_FOURNISSEUR
AND (pa2.DATE_FIN IS NULL OR pa2.DATE_FIN >= CURDATE())
WHERE rf2.ACTIF = 1
GROUP BY rf2.ID_REFERENCE
) last_ref ON last_ref.ID_REFERENCE = r.ID_REFERENCE

→ Pour chaque référence, on ne garde que le prix le plus récent (ID_PRIX le plus élevé).

(C) Premier fournisseur actif

LEFT JOIN (
SELECT rf2.ID_REFERENCE, MIN(rf2.ID_REF_FOURNISSEUR) as ID_REF_FOURNISSEUR_PREMIER
FROM REFERENCES_FOURNISSEURS rf2
WHERE rf2.ACTIF = 1
GROUP BY rf2.ID_REFERENCE
) first_fourn ON first_fourn.ID_REFERENCE = r.ID_REFERENCE

→ Le fournisseur est récupéré indépendamment du prix, sur le premier enregistrement actif.

(D/E) Premier concurrent actif

LEFT JOIN (
SELECT rc2.ID_REFERENCE, MIN(rc2.ID_REF_CONCURRENT) AS ID_REF_CONCURRENT_PREMIER
FROM REFERENCES_CONCURRENTS rc2
WHERE rc2.ACTIF = 1
GROUP BY rc2.ID_REFERENCE
) first_concurrent ON first_concurrent.ID_REFERENCE = r.ID_REFERENCE

(F/G) Premier contrat actif

LEFT JOIN (
SELECT cp2.ID_REFERENCE, MIN(cp2.ID_CONTRAT_PRIX) AS ID_CONTRAT_PRIX_PREMIER
FROM CONTRATS_PRIX cp2
JOIN CONTRATS co2 ON cp2.ID_CONTRAT = co2.ID_CONTRAT AND co2.STATUT = 1
GROUP BY cp2.ID_REFERENCE
) first_contract ON first_contract.ID_REFERENCE = r.ID_REFERENCE

Indicateur HAS_CONTRAT

Le champ HAS_CONTRAT est calculé en ligne via un CASE :

CASE
WHEN cp.ID_CONTRAT IS NOT NULL THEN 'O'
ELSE 'N'
END as HAS_CONTRAT

Pagination

La pagination est gérée en PHP avec trois paramètres :

$items_per_page = isset($_GET['limit']) ? intval($_GET['limit']) : 10;
$current_page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
$offset = ($current_page - 1) * $items_per_page;

Le total est calculé via une requête COUNT(*) enveloppant la requête principale :

$count_sql = "SELECT COUNT(*) FROM (" . $sql . ") as c";

Puis la requête principale est complétée :

ORDER BY r.CODE_MACHINE, f.TRIGRAMME
LIMIT $items_per_page OFFSET $offset

Recherche globale

La fonction applyGlobalSearchOptimized() ajoute une condition AND (...) avec 16 paramètres de recherche LIKE couvrant :

  • Champs directs : CODE_MACHINE, DESIGNATION, NOM_ACTEUR, CATEGORIE, SOUS_CATEGORIE, QUALITE, RAISON_SOCIALE, TRIGRAMME, REF_EXTERNE, PLATEFORME, NOM_CONTRAT, CLIENT
  • Sous-requêtes EXISTS sur REFERENCES_CONCURRENTS pour REF_EQUIVALENTE, REF_REMPLACEMENT, et les acteurs concurrents

Filtres multi-valeurs

La fonction applyNewFilters() génère dynamiquement des clauses IN (?, ?, ...) avec autant de placeholders que de valeurs sélectionnées :

$placeholders = str_repeat('?,', count($filter_categorie) - 1) . '?';
$sql .= " AND c.CATEGORIE IN ($placeholders)";
$params = array_merge($params, $filter_categorie);

Ordre d'application

1. applyGlobalSearchOptimized() → Recherche globale
2. applyNewFilters() → Filtres dropdown
3. COUNT(*) sur la requête → Pagination
4. ORDER BY + LIMIT + OFFSET → Résultat final