Dans le cadre du développement d'applications de gestion, il est fréquent de devoir trier des données selon des règles métier complexes qui ne se limitent pas à une simple colonne. L'utilisation de l'expression CASE WHEN en MySQL permet de définir des priorités personnalisées et d'appliquer des stratégies de tri différentes pour chaque groupe de données.
1. Attribution d'un rang de priorité dynamique
L'approche consiste d'abord à calculer un champ temporaire (souvent nommé priority ou sort_index) dans une sous-requête. Ce champ servira de base pour le regroupement logique des résultats.
SELECT * FROM (
SELECT
id_commande,
statut,
date_maj,
date_debut_prevue,
date_fin_reelle,
CASE
WHEN (id_ligne IS NOT NULL) AND statut = 3 THEN 1
WHEN (id_ligne IS NULL) AND statut = 3 THEN 2
WHEN (id_ligne IS NOT NULL) AND statut = 4 THEN 3
WHEN (id_ligne IS NULL) AND statut = 4 THEN 4
WHEN (id_ligne IS NOT NULL) AND statut = 2 THEN 5
WHEN (id_ligne IS NULL) AND statut = 2 THEN 6
WHEN statut = 5 AND date_fin_reelle >= DATE_SUB(NOW(), INTERVAL 7 DAY) THEN 7
ELSE 99
END AS rang_tri
FROM t_ordres_travail
WHERE statut IN (2, 3, 4, 5)
) AS calcul_tri
WHERE rang_tri < 99
ORDER BY
rang_tri ASC,
CASE WHEN rang_tri IN (1, 2, 4, 5) THEN date_maj END DESC,
CASE WHEN rang_tri IN (3, 6) THEN date_debut_prevue END ASC,
CASE WHEN rang_tri = 7 THEN date_fin_reelle END DESC;
2. Implémentation avec MyBatis pour la persistance
L'intégration de cette logique dans un mappeur MyBatis nécessite une attention particulière sur la gestion des caractères spéciaux (comme les signes inférieurs) et la structuration des jointurse si les données principales doivent être récupérées intégralement.
<select id="rechercherCommandesTriees" resultType="com.exemple.entity.Commande">
SELECT base.*
FROM t_ordres_travail base
INNER JOIN (
SELECT id_commande, rang_tri, date_maj, date_debut_prevue, date_fin_reelle
FROM (
SELECT
id_commande, date_maj, date_debut_prevue, date_fin_reelle,
CASE
WHEN (id_ligne IS NOT NULL) AND statut = 3 THEN 1
WHEN (id_ligne IS NOT NULL) AND statut = 4 THEN 2
WHEN (id_ligne IS NOT NULL) AND statut = 2 THEN 3
WHEN (id_ligne IS NULL) AND statut = 3 THEN 4
WHEN (id_ligne IS NULL) AND statut = 4 THEN 5
WHEN (id_ligne IS NULL) AND statut = 2 THEN 6
WHEN statut = 5 AND date_fin_reelle BETWEEN DATE_SUB(NOW(), INTERVAL 6 DAY) AND NOW() THEN 7
ELSE 8
END AS rang_tri
FROM t_ordres_travail
WHERE (statut IN (2,3,4,5) AND (id_ligne = #{idLigne} OR id_ligne IS NULL))
<if test="codeMateriel != null">
AND code_materiel LIKE CONCAT('%', #{codeMateriel}, '%')
</if>
<if test="statutFiltre != null">
AND statut = #{statutFiltre}
</if>
) sub_calcul
WHERE rang_tri < 8
) table_tri ON base.id_commande = table_tri.id_commande
ORDER BY
table_tri.rang_tri ASC,
CASE table_tri.rang_tri WHEN 1 THEN table_tri.date_maj END DESC,
CASE table_tri.rang_tri WHEN 2 THEN table_tri.date_maj END DESC,
CASE table_tri.rang_tri WHEN 3 THEN table_tri.date_debut_prevue END ASC,
CASE table_tri.rang_tri WHEN 4 THEN table_tri.date_maj END DESC,
CASE table_tri.rang_tri WHEN 5 THEN table_tri.date_maj END DESC,
CASE table_tri.rang_tri WHEN 6 THEN table_tri.date_debut_prevue END ASC,
CASE table_tri.rang_tri WHEN 7 THEN table_tri.date_fin_reelle END DESC
</select>
Analyse de la structure de tri
Cette méthode repose sur deux étapes clés :
- La catégorisation : Le premier
CASE WHENtransforme des conditions métier hétérogènes en une suite numérique ordonnée. Cela permet de grouper visuellement les résultats (ex: traiter les urgences avec une ligne assignée avant les tâches sans ligne). - Le tri granulaire : Dans la clause
ORDER BY, chaque blocCASEest indépendant. Si la condition duCASEn'est pas remplie, il retourneNULL, ce qui permet aux autres clauses de tri de prendre le relais sans conflit pour les rangs correspondants.