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

Requêtes MySQL Discussion :

Problème JOINTURE et CONDITION


Sujet :

Requêtes MySQL

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2015
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Septembre 2015
    Messages : 3
    Points : 9
    Points
    9
    Par défaut Problème JOINTURE et CONDITION
    Bonjour,

    J'espère que les explications seront claires :-)

    Une table ta.id ta.champ1 ta.champ2
    Une table tb.idta tb.champ1 tb.champ2

    Je voudrais faire une requête de type :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT ta.champ1 
    FROM ta 
    JOIN tb ON ( ta.id = tb.idta ) 
    WHERE ta.champ2 = 'truc' 
      OR (tb.champ1 = 'recto'  AND tb.champ2= 'noir' )
    Cela fonctionne presque sauf que je voudrais que le AND s'applique pour chaque ligne trouvée dans ma table jointe.

    Exemple de contenu tb2 :

    idta | champ1 | champ2
    1 | recto | blanc
    1 | verso | noir

    La requête me renverra un résultat (alors que je ne veux pas) parce qu'il existe bien un enregistrement avec tb.champ1 = 'recto' et un autre enregistrement avec tb.champ2= 'noir' ... sauf que je veux que tb.champ1 = 'recto' AND tb.champ2= 'noir' pour une même ligne de ma tb.

    Merci de votre aide ... sachant malheureusement que je ne peux pas modifier la structure des tables.

    Anthony

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    WHERE ta.champ2 = 'truc' 
      OR (tb.champ1 = 'recto'  AND tb.champ2= 'noir' )
    Exemple de contenu tb2 :

    idta | champ1 | champ2
    1 | recto | blanc
    1 | verso | noir

    La requête me renverra un résultat (alors que je ne veux pas) parce qu'il existe bien un enregistrement avec tb.champ1 = 'recto' et un autre enregistrement avec tb.champ2= 'noir' ... sauf que je veux que tb.champ1 = 'recto' AND tb.champ2= 'noir' pour une même ligne de ma tb.
    Normalement, c'est bien ce que fait la requête et, d'après votre exemple de données, la condition après le OR n'est pas satisfaite.
    La condition avant le OR porte sur "ta" et votre exemple de données ne permet pas de savoir si la ligne de ta portant l'id 1 a la colonne (et pas champ ! ) à "truc" ou pas.

    Vérifiez bien vos données réelles et le cas qui vous pose problème.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2015
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Septembre 2015
    Messages : 3
    Points : 9
    Points
    9
    Par défaut
    Citation Envoyé par CinePhil Voir le message
    Normalement, c'est bien ce que fait la requête et, d'après votre exemple de données, la condition après le OR n'est pas satisfaite.
    La condition avant le OR porte sur "ta" et votre exemple de données ne permet pas de savoir si la ligne de ta portant l'id 1 a la colonne (et pas champ ! ) à "truc" ou pas.

    Vérifiez bien vos données réelles et le cas qui vous pose problème.
    Merci bien pour votre réponse ... et à la modération pour avoir remis mon message en forme :-)

    Pour être plus précis j'ai reproduis en gros la structure d'une requête que je fais sur une table wordpress (avec w_posts comme table ta et w_postmeta pour la table tb).

    La condition concernant est "sans intérêt ici" puisque dans mon cas elle ne s'applique pas. J'aurai même plus omettre cette condition.

    J'ai plusieurs fois vérifié les données et je vous assure que cette requête me sort le résultat parce que les deux conditions sont remplis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (tb.champ1 = 'recto'  AND tb.champ2= 'noir' )
    mais pour deux enregistrements distincts de ma table jointe ... alors que j'aurai souhaité qu'elle soit valide seulement lorsqu'elle s'applique sur une ligne.

    Ma requête d'origine est un peu plus complexe aussi je vais faire des tests pour vérifier que mon exemple est pertinent.

    Anthony

  4. #4
    Futur Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Septembre 2015
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Septembre 2015
    Messages : 3
    Points : 9
    Points
    9
    Par défaut
    Merci pour votre aide.
    Effectivement après des tests simplifiés j'ai constaté que la requête originale était bonne. Effet fin de semaine donc ... le problème venait du fait que ma requête (plus complexe) peinait sur un autre point.

    Merci et bon week-end,

    Anthony

  5. #5
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Alors donnez votre requête réelle et vos données réelles, éventuellement anonymisées ou transformées mais en respectant leur cohérence. Là c'est difficile d'en dire plus mais ce qu'il y a dans le WHERE est bien vérifié pour chaque ligne rapportée par la partie FROM (éventuellement JOIN) de la requête.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  6. #6
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut nunux34.

    avant de faire quoi que ce soit, tu dois te poser les questions suivantes :

    1) de quel type de jointure ai-je besoin ?
    --> Inner : une intersection.
    --> left outer, la table de gauche + l'intersection
    --> Full : left + right.

    2) tes deux tables, est-ce une relation père - fils ?
    Si c'est OUI, il faut déclarer une clef étrangère entre les deux tables.

    A titre indicatif, je te communique la base de données :
    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
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    --------------
    SET AUTOCOMMIT = 0
    --------------
     
    --------------
    START TRANSACTION
    --------------
     
    --------------
    DROP DATABASE IF EXISTS `base`
    --------------
     
    --------------
    CREATE DATABASE `base`
            DEFAULT CHARACTER SET `latin1`
            DEFAULT COLLATE       `latin1_general_ci`
    --------------
     
    --------------
    DROP TABLE IF EXISTS `test1`
    --------------
     
    --------------
    CREATE TABLE `test1`
    (
      `id1`   integer unsigned NOT NULL AUTO_INCREMENT,
      `col1`  char(20)         NOT NULL,
      `col2`  char(20)         NOT NULL,
      PRIMARY KEY         (`id1`),
      UNIQUE  INDEX `idx` (`col1`,`col2`,`id1`)
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `test1` (`col1`, `col2`) VALUES
    ('un',    'one'),
    ('deux',  'two'),
    ('trois', 'three')
    --------------
     
    --------------
    select * from test1
    --------------
     
    +-----+-------+-------+
    | id1 | col1  | col2  |
    +-----+-------+-------+
    |   2 | deux  | two   |
    |   3 | trois | three |
    |   1 | un    | one   |
    +-----+-------+-------+
    --------------
    DROP TABLE IF EXISTS `test2`
    --------------
     
    --------------
    CREATE TABLE `test2`
    (
      `id2`   integer unsigned NOT NULL AUTO_INCREMENT,
      `clef`  integer unsigned,
      `ch1`   char(20)         NOT NULL,
      `ch2`   char(20)         NOT NULL,
      PRIMARY KEY         (`id2`),
      UNIQUE  INDEX `idx` (`ch1`,`ch2`,`id2`),
      CONSTRAINT `FOREIGN` FOREIGN KEY (`clef`) REFERENCES `test1` (`id1`) ON DELETE RESTRICT ON UPDATE RESTRICT
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `test2` (`clef`,`ch1`, `ch2`) VALUES
    (1, 'do', 'bleu'),
    (1, 'do', 'rouge'),
    (2, 're', 'rose'),
    (2, 'mi', 'noir'),
    (2, 're', 'vert'),
    (3, 'fa', 'bleu'),
    (3, 'do', 'noir')
    --------------
     
    --------------
    select * from test2
    --------------
     
    +-----+------+-----+-------+
    | id2 | clef | ch1 | ch2   |
    +-----+------+-----+-------+
    |   1 |    1 | do  | bleu  |
    |   2 |    1 | do  | rouge |
    |   3 |    2 | re  | rose  |
    |   4 |    2 | mi  | noir  |
    |   5 |    2 | re  | vert  |
    |   6 |    3 | fa  | bleu  |
    |   7 |    3 | do  | noir  |
    +-----+------+-----+-------+
    --------------
    COMMIT
    --------------
     
    --------------
    SET AUTOCOMMIT = 1
    --------------
     
     
    Appuyez sur une touche pour continuer...
    Et voici le jeu d'essai :
    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
    --------------
    SELECT *
    FROM            test1 AS t1
    left OUTER JOIN test2 AS t2
    ON (t2.clef = t1.id1)
    order by t1.id1
    --------------
     
    +-----+-------+-------+------+------+------+-------+
    | id1 | col1  | col2  | id2  | clef | ch1  | ch2   |
    +-----+-------+-------+------+------+------+-------+
    |   1 | un    | one   |    1 |    1 | do   | bleu  |
    |   1 | un    | one   |    2 |    1 | do   | rouge |
    |   2 | deux  | two   |    3 |    2 | re   | rose  |
    |   2 | deux  | two   |    4 |    2 | mi   | noir  |
    |   2 | deux  | two   |    5 |    2 | re   | vert  |
    |   3 | trois | three |    6 |    3 | fa   | bleu  |
    |   3 | trois | three |    7 |    3 | do   | noir  |
    +-----+-------+-------+------+------+------+-------+
    Ceci correspond à une jointure de type gauche.
    Je désire obtenir toutes les lignes de ma première tables 'test1' et toutes les lignes de ma seconde table 'test2' si elles existent.
    Ici, j'ai fait en sorte d'avoir pour chaque fils un père, et un père pour chaque fils.
    A moins de me tromper, cette relation se nomme une surjection en mathématique (tout fils à un père).

    En ce point, nous avons notre jeu d'essai sur lequel nous allons appliquer une restriction.
    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
    --------------
    SELECT *
    FROM            test1 AS t1
    LEFT OUTER JOIN test2 AS t2
    ON (t2.clef = t1.id1)
    WHERE                     t1.col2 = 'one'
       OR  (t2.ch1 = 'mi' AND t2.ch2  = 'noir')
    order by t1.id1
    --------------
     
    +-----+------+------+------+------+------+-------+
    | id1 | col1 | col2 | id2  | clef | ch1  | ch2   |
    +-----+------+------+------+------+------+-------+
    |   1 | un   | one  |    1 |    1 | do   | bleu  |
    |   1 | un   | one  |    2 |    1 | do   | rouge |
    |   2 | deux | two  |    4 |    2 | mi   | noir  |
    +-----+------+------+------+------+------+-------+
    A l'identique de ton exemple, je recherche deux ensembles de données :
    --> toutes les lignes de la table test1 ayant col2 = 'one'.
    --> toutes les lignes de la table test2 ayant ch1 = 'mi' et ch2 = 'noir'.

    A l'affichage, on obtiens ces deux ensembles, qui, je l'ai fait exprès, sont disjoincts.
    Cela ne sera pas toujours le cas, comme dans l'exemple ci-après :
    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
    --------------
    SELECT *
    FROM            test1 AS t1
    LEFT OUTER JOIN test2 AS t2
    ON (t2.clef = t1.id1)
    WHERE                     t1.col2 = 'two'
       OR  (t2.ch1 = 'mi' AND t2.ch2  = 'noir')
    order by t1.id1
    --------------
     
    +-----+------+------+------+------+------+------+
    | id1 | col1 | col2 | id2  | clef | ch1  | ch2  |
    +-----+------+------+------+------+------+------+
    |   2 | deux | two  |    3 |    2 | re   | rose |
    |   2 | deux | two  |    4 |    2 | mi   | noir |
    |   2 | deux | two  |    5 |    2 | re   | vert |
    +-----+------+------+------+------+------+------+
    Ici, je recherche :
    --> toutes les lignes de la table test1 ayant col2 = 'two'.
    --> toutes les lignes de la table test2 ayant ch1 = 'mi' et ch2 = 'noir'.

    Il se trouve que la seconde recherche est déjà incluse dans la première.
    Et de ce fait, la seconde recherche est inutile.
    Mais ça, tu ne peux pas le savoir avant d'avoir produit un résultat.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  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
    J'ai pas très bien compris pourquoi le topic était marqué comme "résolu" vu que je n'ai pas vu de réponse à la question initiale.

    Voici deux requêtes qui répondent au problème.
    Il y en a certainement bien d'autres.
    Je vous laisse choisir celle qui est la plus performante dans votre cas.

    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    select ta.champ1
    from ta
    where ta.champ2 = 'truc'
    or (
       exists (select null from tb where tb.idta = ta.id and tb.champ1 = 'verso')
       and
       exists (select null from tb where tb.idta = ta.id and tb.champ2 = 'noir')
    )

    Ou :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    select ta.champ1
    from ta
    inner join tb on tb.idta = ta.id
    where ta.champ2 = 'truc'
    union
    select ta.champ1
    from ta
    inner join tb on tb.idta = ta.id
    group by ta.champ1
    having sum(when tb.champ1 = 'recto' then 1 else 0 end) > 0 and sum(when tb.champ2 = 'noir' then 1 else 0 end) > 0

    Allez, parce que je suis en forme, une troisième :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    select ta.champ1
    from ta
    left outer join tb t1 on t1.idta = ta.id
    left outer join tb t2 on t2.idta = ta.id
    where ta.champ2 = 'truc'
    or (t1.champ1 = 'recto' and t2.champ2 = 'noir')
    On ne jouit bien que de ce qu’on partage.

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

Discussions similaires

  1. Problème de jointure et condition
    Par flagodzki dans le forum Requêtes
    Réponses: 4
    Dernier message: 14/11/2011, 22h34
  2. Problème jointure
    Par RiPSO dans le forum Requêtes
    Réponses: 3
    Dernier message: 30/04/2006, 23h55
  3. Problème jointure de tables
    Par Carter dans le forum Requêtes
    Réponses: 1
    Dernier message: 07/02/2006, 12h41
  4. Problème avec une condition
    Par ghan77 dans le forum Débuter
    Réponses: 2
    Dernier message: 16/12/2005, 16h18
  5. Jointure avec conditions sur plusieurs colonnes
    Par ben53 dans le forum Langage SQL
    Réponses: 9
    Dernier message: 28/11/2005, 09h27

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