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 :

Simplifier une requête de recherche d'un champ non compris dans un group by


Sujet :

Langage SQL

  1. #1
    Candidat au Club
    Femme Profil pro
    Inscrit en
    Décembre 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4
    Points : 4
    Points
    4
    Par défaut Simplifier une requête de recherche d'un champ non compris dans un group by
    Bonjour,

    Je cherche a récupérer tous les unique_id (clé primaire de ma table) correspondant à cette sélection :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT unid, num_1
    FROM un_hi
    WHERE dgroup not like 'CANTO' and tycod='TRANSFERTS'
    and cterm not like 'saeedge'
    GROUP BY num_1, unid
    HAVING count(cdts)=2;
    donc normalement deux unique_id par groupe
    la seule solution que j'imagine est de faire un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT unique_id FROM un_hi WHERE num_1 in (SELECT num_1 FROM ma_première_requête) and unid in (SELECT unid FROM ma_première_requête)
    mais je en suis même pas sûre d'obtenir réellement ce que je veux. Quid des cas ou j'aurais un couple num_1 / unid dans cette requête, existant dans un_hi mais qui n'avais pas un count(cdts)=2.

    Je précise que je suis sur une BDD Ms SQL server si jamais il existe des particularités.

    Merci pour vos éclaircissements (je ne suis pas développeur, pas même informaticienne à la base mais j'essaye de m'en sortir et d'apprendre!)

  2. #2
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 134
    Points : 38 557
    Points
    38 557
    Billets dans le blog
    9
    Par défaut
    Bonjour,

    Pour la 1ère requête
    L'opérateur LIKE requiert l'utilisation du caractère % en début et/ou fin de chaine de caractères :
    ==> where COL1 LIKE '%ABC%' tout ce qui contient "ABC"
    ==> where COL1 LIKE 'ABC%' tout ce qui commence par "ABC"
    Cela étant, attention aux majuscules/minuscules, peut être devriez vous utiliser les fonctions UPPER ou LOWER pour convertir tout en MàJ ou Min
    ==> where upper(COL1) LIKE 'ABC%'

    Pour la 2ème requête
    Pour des raisons de performances, un test d'existence ne doit jamais utiliser IN / NOT IN*, préférez l'utilisation de EXISTS / NOT EXISTS ou bien faites une jointure OUTER et testez la nullité d'une colonne "NOT NUL"
    * seul cas d'exception : in / not in avec une liste de valeurs "en dur", exemple WHERE COL1 NOT IN (1, 5, 22)
    Dans votre cas, c'est encore plus simple, une jointure "INNER" suffit

    S'il peut y avoir plus de deux ident, il faut remplacer le test de la clause HAVING, par HAVING count(cdts)>1

    Pour "assembler" les deux requêtes, vous pouvez utiliser une CTE, ce qui donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    with TAB0 as (
        SELECT unid, num_1
        FROM un_hi
        WHERE upper(dgroup) not like '%CANTO%' 
          and upper(tycod)='TRANSFERTS'
          and lower(cterm) not like '%saeedge%'
        GROUP BY unid, num_1
        HAVING count(cdts)>1 )
     
    SELECT unique_id 
    FROM un_hi  HI
    INNER JOIN TAB0 T0
       on T0.unid = HI.unid
    ;

  3. #3
    Candidat au Club
    Femme Profil pro
    Inscrit en
    Décembre 2013
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4
    Points : 4
    Points
    4
    Par défaut
    Mon not like n'était pas approprié, j'avais simplement besoin d'un "différent de" mais comme je passe de logiciel en logiciel et donc de langage en langage je ne retrouve jamais la syntaxe <> ou != appropriée. Bref ce n'était pas le sujet.

    Je me suis mal exprimée. Je ne veux absolument QUE les couples num_1 / unid pour lesquels j'ai exactement 2 cdts. Si j'en ai plus ou moins je ne veux surtoutpas récupérer les unique_id correspondants. Je n'ai pas besoin des upper ou lower, il s'agit d'une BDD opérationnelle (non remplie à la main) il n'y a pas possibilité que les valeurs des champs soient sous un autres format et si elles l'étaient alors ce serait un bug ou une entrée manuelle forcée et je ne veux pas la traiter dans cette recherche automatique.

    Le join me semble une bonne solution mais ne faudrait-il pas que la jointure se fasse sur mes deux champs unid et num_1 plutôt? Je vais faire les tests.

    (Pour info et pour plus de compréhension num_1 est un numéro d'événement et unid un numéro d'unité engagée sur l'événement. Les unités peuvent avoir travaillées sur de nombreux événements différents et pour un événement je peux avoir une ou plusieurs unités engagées. Enfin ma table comprend une ligne par statut de l'unité pour un événement donné : engagé, départ, sur place... libre)

    Merci pour cette réponse rapide!

    Je ne connaissais pas les CTE ! Encore un nouvel apprentissage je suis contente!

  4. #4
    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
    Bonjour,

    Vous pouvez aussi faire comme ceci (pas testé) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    WITH CTE AS (
    	SELECT unique_id, COUNT(cdts) OVER(PARTITION BY unid, num_1) as nb_cdts
    	FROM un_hi
    	WHERE dgroup <> 'CANTO' and tycod='TRANSFERTS'
    	and cterm <> 'saeedge'
    )
    SELECT unique_id
    FROM CTE
    WHERE nb_cdts = 2
    ;

  5. #5
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Salut.

    Question un peu hors sujet à escartefigue : sur quoi te bases-tu pour dre que le IN / NOT IN n'est pas performant et qu'il faut lui préférer EXISTS / NOT EXISTS ?

    En effet, pendant longtemps, ceci a été vrai que ce soit avec SQL Server ou Oracle, mais maintenant, sur ces deux là, généralement le IN / NOT IN est au contraire plus rapide que le EXISTS / NOT EXISTS.

    Dans tous les cas, un IN peut être remplacé par INNER JOIN sur une CTE, qui sera bien plus rapide.
    Quant au NOT IN, il peut être remplacé par un LEFT OUTER JOIN where xxx IS NULL mais c'est généralement plus lent.

    Après, toutes les exceptions sont possibles.

    En tout cas, je ne serais pas aussi catégorique quant aux problèmes de performances inhérentes au IN/EXISTS/jointure : en règle générale, ils se valent à pas grand chose près, et d'un cas à l'autre, sur un même SGBD on peut avoir de grands écarts dans un sens ou dans un autre (et je parle pas de changement de version).

    A mon sens, il vaut mieux dans un premier temps privilégier la sémantique, et uniquement en cas de problèmes de performances, se pencher sur les autres solutions.
    On ne jouit bien que de ce qu’on partage.

  6. #6
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 134
    Points : 38 557
    Points
    38 557
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    Question un peu hors sujet à escartefigue : sur quoi te bases-tu pour dre que le IN / NOT IN n'est pas performant et qu'il faut lui préférer EXISTS / NOT EXISTS ?
    Sur des mesures et des plans d'exécution, tout simplement.
    Mais j'ai bien précisé
    - que cette remarque ne vaut que pour un test d'existence
    - que dans le cas précis de ce fil, une jointure inner est la solution, c'est d'ailleurs ce que j'ai appliqué dans ma proposition de solution

    Citation Envoyé par StringBuilder Voir le message
    En effet, pendant longtemps, ceci a été vrai que ce soit avec SQL Server ou Oracle, mais maintenant, sur ces deux là, généralement le IN / NOT IN est au contraire plus rapide que le EXISTS / NOT EXISTS.
    Le problème est que la requête corrélée construit l'ensemble de toutes les réponses, alors que le not exists ou la requête outer avec test de nullité, ne vérifie qu'une seule fois l'existence
    En fonction des cardinalités, la différence peut être minime ... ou énorme

    Citation Envoyé par StringBuilder Voir le message
    Quant au NOT IN, il peut être remplacé par un LEFT OUTER JOIN where xxx IS NULL mais c'est généralement plus lent.
    Je l'ai mentionné plus haut

    Citation Envoyé par StringBuilder Voir le message
    A mon sens, il vaut mieux dans un premier temps privilégier la sémantique, et uniquement en cas de problèmes de performances, se pencher sur les autres solutions.
    Tout à fait d'accord, mais comme le demandeur à précisé "je ne suis pas informaticien", j'ai essayé de profiter de ce sujet pour être un peu didactique, et préconiser les solutions les plus efficientes

  7. #7
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Ok, merci pour ces précisions
    On ne jouit bien que de ce qu’on partage.

Discussions similaires

  1. [AC-2007] Problème de critère pour le champ d'une requête de recherche
    Par robin148 dans le forum Access
    Réponses: 1
    Dernier message: 23/05/2014, 12h18
  2. champs non accessibles dans une requête sélection
    Par Claire31 dans le forum Requêtes et SQL.
    Réponses: 8
    Dernier message: 03/08/2006, 13h22
  3. Optimisation d'une requête de recherche
    Par Bobtop dans le forum Requêtes
    Réponses: 16
    Dernier message: 14/06/2006, 16h27
  4. [SQL] Simplifier une requête SQL ?
    Par renaud26 dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 29/04/2006, 13h50

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