IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage SQL Discussion :

Sélection avec gestion de niveau de priorité


Sujet :

Langage SQL

  1. #1
    Membre régulier
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2019
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2019
    Messages : 15
    Points : 77
    Points
    77
    Par défaut Sélection avec gestion de niveau de priorité
    Bonjour à tous, je bute sur une requête SQL un peu complexe.

    Pour l'instant, j'ai une requête très simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT `Contenu`, `Type`, `Signature`
    FROM `ressources`
    WHERE `date`<= NOW()
    AND `dateValidite` > NOW()
    Il s'avère que ma table possède un champ intitulé "Priorité" qui contient un niveau de priorité de 1 à 4.

    Ce que je voudrais via SQL c'est, dans les lignes sélectionnées par ma requête :
    • Si il y a des lignes contenant la priorité à 1 -> ne sélectionner que les éléments contenant la priorité à 1.
    • Si il y a des lignes contenant la priorité à 2 et/ou 3 (mais pas de 1) -> Sélectionner tous les éléments contenant la priorité 2 et 3 (exclusion du niveau de priorité 4).
    • Si il n'y a que des lignes contenant la priorité à 4 -> Sélectionner tout le monde.


    Je me doute qu'il faut que j'utilise du CASE ou/et du EXISTS mais je n'arrive pas à formuler correctement ma requête.
    Si une âme charitable pouvait me donner un coup de pouce...

    PS : Je peux faire le tri via PHP mais je pense que ce serait bien plus rapide à l’exécution et instructif via SQL.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 239
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 239
    Points : 12 870
    Points
    12 870
    Par défaut
    Bonjour,
    Si tu reformules ton besoin, tu t'approche de la solution.
    Tu veux:
    1. Toutes les lignes de priorité 1
    2. Toutes les lignes de priorité 2/3, pour lesquelles il n'en existe pas avec la priorité 1
    3. Toutes les lignes de priorité 4, pour lesquelles il n'en existe pas avec une priorité inférieure à 4

    Tu peux donc faire une union des 3 requêtes, et pour le test de non existence tu as plusieurs solution (not exists, jointure externe).

    Tatayo.

  3. #3
    Membre régulier
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2019
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2019
    Messages : 15
    Points : 77
    Points
    77
    Par défaut
    @tatayo

    Merci, mais c'est plutot :
    Si 1 existe, je ne sélectionne que 1.
    Si 2 ou 3 existe, je sélectionne que 2 et 3.
    Sinon je sélectionne 4.

    En attendant, j'ai réussi à formuler ce code qui fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    SELECT `Contenu`, `Type`, `Signature`, `Priorité`
    FROM `ressources`
    WHERE `date`<= NOW()
    AND `dateValidite` > NOW()
    AND (CASE
       WHEN EXISTS(SELECT * FROM `ressources` WHERE `date`<= NOW() AND `dateValidite` > NOW() AND `Priorité`=1) THEN `Priorité`=1
       WHEN EXISTS(SELECT * FROM `ressources` WHERE `date`<= NOW() AND `dateValidite` > NOW() AND `Priorité`=2 OR `Priorité`=3) THEN `Priorité`=2 OR `Priorité`=3
       ELSE True
    END)
    Il y a peut-être moyen d'optimiser.

  4. #4
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2002
    Messages
    264
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2002
    Messages : 264
    Points : 175
    Points
    175
    Par défaut
    Pourquoi ne pas faire un petit select pour recup PrioriteMin = MIN(Priorité)
    puis ta requête qui filtre sur priorité avec un case PrioriteMin

  5. #5
    Membre régulier
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2019
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2019
    Messages : 15
    Points : 77
    Points
    77
    Par défaut
    Citation Envoyé par bib34690 Voir le message
    Pourquoi ne pas faire un petit select pour recup PrioriteMin = MIN(Priorité)
    puis ta requête qui filtre sur priorité avec un case PrioriteMin
    J'ai fait comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    SELECT @PrioriteMin := MIN(`Priorité`) FROM `ressources`
    WHERE `date`<= NOW()
    AND `dateValidite` > NOW() OR `dateValidite`=Null;
     
    SELECT `Contenu`, `Type`, `Signature`, `Priorité`
    FROM `ressources`
    WHERE `date`<= NOW()
    AND `dateValidite` > NOW() OR `dateValidite`=Null
    AND (CASE
        WHEN @PrioriteMin = 1 THEN `Priorité`=1
        WHEN @PrioriteMin <= 3 THEN `Priorité`=2 OR `Priorité`=3
        ELSE True
    END)
    Mais du coup, je récupère aussi la valeur de @PrioriteMin dans mon résultat.. ce qui ne m'est pas très utile.
    Le code est plus court et il y a moins de répétition, c'est déjà ça.

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 239
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 239
    Points : 12 870
    Points
    12 870
    Par défaut
    Et pourtant ma requête répond bien au besoin.
    La première renvois toutes les lignes avec pour priorité 1, donc elle ignore les autres lignes => Toutes les lignes de priorité 1.
    La requête 2 renvoie les lignes de priorité 2 ou 3, s'il n'existe pas de ligne avec la priorité 1. Elle ignore donc les lignes avec la priorité 4, et ne renvoie rien s'il existe des lignes de priorité 1 => Toutes les lignes de priorité 2/3, pour lesquelles il n'en existe pas avec la priorité 1
    La dernière renvoie les lignes de priorité 4, s'il n'en existe pas de priorité inférieur => Toutes les lignes de priorité 4, pour lesquelles il n'en existe pas avec une priorité inférieure à 4

    Il faut faire 3 requêtes distincts, et faire une union des 3.

    Je ne vois pas ce qui coince avec ma proposition.

    Tatayo.

  7. #7
    Membre chevronné
    Homme Profil pro
    Développeur Oracle
    Inscrit en
    Décembre 2019
    Messages
    1 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Oracle

    Informations forums :
    Inscription : Décembre 2019
    Messages : 1 150
    Points : 1 935
    Points
    1 935
    Par défaut
    Bonjour,

    Pas possible d'utiliser des fonctions analytiques?

  8. #8
    Membre régulier
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2019
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2019
    Messages : 15
    Points : 77
    Points
    77
    Par défaut
    Citation Envoyé par tatayo Voir le message
    Et pourtant ma requête répond bien au besoin.
    La première renvois toutes les lignes avec pour priorité 1, donc elle ignore les autres lignes => Toutes les lignes de priorité 1.
    La requête 2 renvoie les lignes de priorité 2 ou 3, s'il n'existe pas de ligne avec la priorité 1. Elle ignore donc les lignes avec la priorité 4, et ne renvoie rien s'il existe des lignes de priorité 1 => Toutes les lignes de priorité 2/3, pour lesquelles il n'en existe pas avec la priorité 1
    La dernière renvoie les lignes de priorité 4, s'il n'en existe pas de priorité inférieur => Toutes les lignes de priorité 4, pour lesquelles il n'en existe pas avec une priorité inférieure à 4

    Il faut faire 3 requêtes distincts, et faire une union des 3.

    Je ne vois pas ce qui coince avec ma proposition.

    Tatayo.
    D'abord, merci de tenter de m'aider.

    Ce que je souhaite c'est n'avoir qu'une seule requête, pour des question de lisibilité et de facilité de maintenir mon code.
    Ensuite, si la priorité 1 existe, je souhaite m'arrêter là et ne sélectionner que les lignes possédant cette priorité.

    Si il n'y a pas de priorité 1 alors, si la priorité 2 ou 3 existe, je sélectionne les lignes de cette priorité et je m'arrête.

    Enfin, si il n'y a ni priorité 1, 2 ou 3, je sélectionne la priorité 4.

    Mon code fonctionne très bien.
    Mais il y a des répétitions et ça ne me plait pas. Rapport au DRY.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    SELECT `Contenu`, `Type`, `Signature`, `Priorite`
    FROM `ressources`
    WHERE `date`<= NOW()
    AND `dateValidite` > NOW() OR `dateValidite`=Null
    AND (CASE
        WHEN EXISTS(SELECT * FROM `ressources` WHERE `date`<= NOW() AND `dateValidite` > NOW() OR `dateValidite`=Null AND `Priorite`=1) THEN `Priorite`=1
        WHEN EXISTS(SELECT * FROM `ressources` WHERE `date`<= NOW() AND `dateValidite` > NOW() OR `dateValidite`=Null AND `Priorite`=2 OR `Priorite`=3) THEN `Priorite`=2 OR `Priorite`=3
        ELSE True
    END)
    @vanagreg
    Quelle fonction analytique te paraitrait intéressante ?

    @tous
    Si ce n'est pas possible de condenser ce code en évitant les répétitions, je le générerais en PHP pour éviter d'avoir à le modifier en plusieurs endroits...

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 239
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 239
    Points : 12 870
    Points
    12 870
    Par défaut
    Mais il s'agit d'une union de 3 requêtes, ce qui fait bien une seule requête au final.
    Pour la priorité 1, c'est exactement ce que fait ma requête:
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    select LaTable.id,1
    	from LaTable
    	where priorite = 1
    union
    select LaTable.id,23
    	from LaTable 
    	left outer join LaTable as t2 
    		on t2.id = LaTable.id and t2.priorite = 1
    	where LaTable.priorite in (2,3) and  t2.id = null
    union
    select LaTable.id,4 
    	from LaTable
    	left outer join LaTable as t2 
    		on t2.id = LaTable.id and t2.priorite < 4
    	where LaTable.priorite = 4 and t2.id = null
    Tu obtiens bien le bon résultat.
    Tu peux ajouter les colonnes qui te manques dans chaque SELECT.

    Bref pourquoi vouloir partir sur une requête compliquée si tu peux avoir le bon résultat avec une requête plus simple ?

    Tatayo.

  10. #10
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Citation Envoyé par vanagreg Voir le message
    Bonjour,

    Pas possible d'utiliser des fonctions analytiques?
    Si !

    Un truc dans ce genre là
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    WITH CTE AS (
    	SELECT 
    			`Contenu`
    		,	`Type`
    		,	`Signature`
    		,	RANK() OVER(ORDER BY CASE priorite
    						WHEN 1 THEN 1
    						WHEN 2 THEN 2
    						WHEN 3 THEN 2
    						WHEN 4 THEN 4
    					END ) AS RK
    	FROM `ressources`
    	WHERE `date`<= NOW()
    	AND `dateValidite` > NOW()
    )
    SELECT 
    			`Contenu`
    		,	`Type`
    		,	`Signature`
    FROM CTE
    WHERE RK = 1

  11. #11
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Juin 2002
    Messages
    264
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Juin 2002
    Messages : 264
    Points : 175
    Points
    175
    Par défaut
    Citation Envoyé par Aklain52 Voir le message
    J'ai fait comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    SELECT @PrioriteMin := MIN(`Priorité`) FROM `ressources`
    WHERE `date`<= NOW()
    AND `dateValidite` > NOW() OR `dateValidite`=Null;
     
    SELECT `Contenu`, `Type`, `Signature`, `Priorité`
    FROM `ressources`
    WHERE `date`<= NOW()
    AND `dateValidite` > NOW() OR `dateValidite`=Null
    AND (CASE
        WHEN @PrioriteMin = 1 THEN `Priorité`=1
        WHEN @PrioriteMin <= 3 THEN `Priorité`=2 OR `Priorité`=3
        ELSE True
    END)
    Mais du coup, je récupère aussi la valeur de @PrioriteMin dans mon résultat.. ce qui ne m'est pas très utile.
    Le code est plus court et il y a moins de répétition, c'est déjà ça.
    Le 1er select doit être fait ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    DECLARE @PrioriteMin TinyInt;
            SET @PrioriteMin = 
            (
               SELECT MIN(`Priorité`) 
               FROM `ressources`
               WHERE `date`<= NOW()
                       AND `dateValidite` > NOW() OR `dateValidite`=Null;
            )

  12. #12
    Membre régulier
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2019
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2019
    Messages : 15
    Points : 77
    Points
    77
    Par défaut
    Merci à tous,
    Quand je vois ce que vous m'envoyez, je me dit que je suis encore un gros débutant en SQL...

    C'est le défaut de gérer de multiples code, on ne devient jamais vraiment bon dans l'un d'eux.

    En tout cas, encore merci.

    Je vais tester un peu les performances des solutions de @aieeeuuuuu et @tatayo pour garder le plus rapide et je passe ce sujet en résolu.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Gestion des sélections avec QListWidget
    Par garuda1 dans le forum Débuter
    Réponses: 6
    Dernier message: 20/08/2012, 12h04
  2. [C#] Configuration du niveau de priorite des processus
    Par stephdiplo150 dans le forum Windows Forms
    Réponses: 6
    Dernier message: 22/04/2007, 23h29
  3. Pb sélection avec Champ vide
    Par Luffy Duck dans le forum Langage SQL
    Réponses: 2
    Dernier message: 20/10/2005, 12h11
  4. Création requête avec gestion de date
    Par MELINE dans le forum Access
    Réponses: 1
    Dernier message: 30/09/2005, 11h12
  5. Creer une vue avec gestion de date
    Par jf-nigou dans le forum Décisions SGBD
    Réponses: 2
    Dernier message: 01/06/2005, 16h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo