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

  1. #1
    Membre à l'essai
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    août 2017
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : Belgique

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Bâtiment

    Informations forums :
    Inscription : août 2017
    Messages : 16
    Points : 14
    Points
    14

    Par défaut Jointure externe sur plusieurs champs entre deux sous-requêtes

    Bonjour à tous,

    Pour commencer, sachez que j'utilise le système de gestion de base de Données d'Ensemble, à savoir Caché.
    Ensemble est en quelque sorte un BUS permettant à plusieurs logiciels de communiquer entre eux.
    Celui-ci est construit sur la base de Caché qui permet à la fois la gestion de base de données relationnelles et orientées objet...
    Il y a beaucoup à dire sur ces systèmes complexes. La doc (lien) vous renseignera mieux que moi si nécessaire.
    Sachez juste que Caché embarque SQL incluant tous ces standards : source.
    J'ai pris pour habitude de communiquer avec mes DB en full SQL. C'est la raison qui m'amène sur ce forum.

    J'ai tenté une requête pour isoler et mettre en parallèle les articles à priori communs entre deux "bases articles". Une base articles reprend un ensemble d'articles propres à un type de commerce.
    Je vous préviens à l'avance, la base de données est vieille, très vieille, et les transgressions aux propriétés ACID y sont nombreuses, ainsi que les erreurs pures et simples d'architecture relationnelle. On ne retrouve par exemple aucune clé primaire ou étrangères. Les liens se font généralement sur un ou plusieurs champs arbitraires. Mais dans un soucis de coller à la réalité, je vais montrer des requêtes très proches de ce qui s'y fait.

    Voici la définition de mes deux tables :
    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
    -- Articles reprend les données signalétiques des articles qui sont propres à une base articles (un type de commerce)
    CREATE TABLE IF NOT EXISTS Articles (
    BaseArticles INT,
    CodeArticle VARCHAR(10),
    BarCode VARCHAR(15),
    LibelléArticle VARCHAR(50)
    -- Autres propriétés
    );
     
    -- ArtFou reprend les données signalétiques des articles qui sont propres à un fournisseur et un dépôt (un magasin)
    CREATE TABLE IF NOT EXISTS ArtFou (
    BaseArticles INT,
    CodeArticle VARCHAR(10),
    CodeArtFou VARCHAR(15),
    CodeFournisseur VARCHAR(10),
    CodeDépôt INT
    -- Autres propriétés
    );
    Voici un exemple d'échantillon :
    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
    INSERT INTO Articles (BaseArticles, CodeArticle, BarCode, LibelléArticle)
    VALUES
    	(95, 'A', '1', 'Article n°1'),
    	(95, 'D', NULL, 'Article n°4'),
    	(95, 'E', '5', 'Article n°5'),
    	(95, 'G', NULL, 'Article n°7'),
    	(95, 'I', '8', 'Article n°8'),
    	(95, 'J', '10', 'Article n°10'),
    	(17, 'E', '5', 'Article n°5'),
    	(17, 'G', '7', 'Article n°7'),
    	(17, 'H', '8', 'Article n°8'),
    	(17, 'I', '9', 'Article n°9'),
    	(17, 'J', NULL, 'Article n°10'),
    	(17, 'P', '16', 'Article n°16');
     
     
    INSERT INTO ArtFou (BaseArticles, CodeArticle, CodeArtFou, CodeFournisseur, CodeDépôt)
    VALUES
    	(95, 'A', 'F1-1', 'F1', 0),
    	(95, 'E', 'F1-2', 'F1', 0),
    	(95, 'G', 'F3-1', 'F3', 0),
    	(95, 'I', 'F3-2', 'F3', 0),
    	(95, 'J', 'F3-3', 'F3', 0),
    	(17, 'E', 'F1-2', 'F1', 0),
    	(17, 'G', 'F4-2', 'F4', 0),
    	(17, 'J', NULL, 'F4', 0);
    Voici la requête SELECT :
    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
    SELECT 
    -- Base 95
    Base95.CodeArticle AS CodeArticle95, 
    Base95.Barcode AS BarCode95, 
    Base95.CodeArtFou AS CodeArtFou95, 
    Base95.LibelléArticle AS LibelléArticle95, 
    -- Base 17
    Base17.CodeArticle AS CodeArticle17, 
    Base17.Barcode AS BarCode17, 
    Base17.CodeArtFou AS CodeArtFou17, 
    Base17.LibelléArticle AS LibelléArticle17
     
    FROM (
    	-- Base 95
    	SELECT
    	Articles.CodeArticle, 
    	Articles.Barcode, 
    	ArtFou.CodeArtFou, 
    	Articles.LibelléArticle
     
    	FROM
    	Articles
     
    	LEFT JOIN
    	ArtFou
    	ON (Articles.BaseArticles = ArtFou.BaseArticles 
    		AND Articles.CodeArticle = ArtFou.CodeArticle
    		AND ArtFou.CodeDépôt = '0')
     
    	WHERE
    	Articles.BaseArticles = '95'
    ) AS Base95
     
    FULL JOIN (
    	-- Base 17
    	SELECT
    	Articles.CodeArticle, 
    	Articles.Barcode, 
    	ArtFou.CodeArtFou, 
    	Articles.LibelléArticle
     
    	FROM
    	Articles
     
    	LEFT JOIN
    	ArtFou
    	ON (Articles.BaseArticles = ArtFou.BaseArticles 
    		AND Articles.CodeArticle = ArtFou.CodeArticle
    		AND ArtFou.CodeDépôt = '0')
     
    	WHERE
    	Articles.BaseArticles = '17'
    ) AS Base17
     
    ON (Base95.CodeArtFou = Base17.CodeArtFou
    	OR Base95.CodeArticle = Base17.CodeArticle 
    	/*OR Base95.Barcode = Base17.Barcode*/)
    L'idée derrière cette requête c'est de retrouver tous les articles des bases 17 et 95 avec leur homologues de l'autre base articles, sans oublier les articles pour lesquels on a trouvé aucune correspondance.
    Un article est l'homologue d'un autre lorsque au moins un des éléments suivants est semblable:
    - CodeArticle
    - BarCode
    - CodeArtFou

    Voici une idée du résultat attendu :

    BaseArticles95 CodeArticle95 BarCode95 LibelléArticle95 CodeArtFou95 BaseArticles17 CodeArticle17 BarCode17 LibelléArticle17 CodeArtFou17
    95 A 1 Article n°1 F1-1
    95 D Article n°4
    95 I 8 Article n°8 F3-2 17 I 9 Article n°9
    95 I 8 Article n°8 F3-2 17 H 8 Article n°8
    95 E 5 Article n°5 F1-2 17 E 5 Article n°5 F1-2
    95 G Article n°7 F3-1 17 G 7 Article n°7 F4-2
    95 J 10 Article n°10 F3-3 17 J Article n°10
    17 P 16 Article n°16



    L'exécution de cette requête plante dans mon SGBD.
    La jointure externe n'est pas reconnue.
    J'ai isolé la ligne qui pose problème (la dernière, en commentaire, dans le 'ON').

    En fait, pour être tout à fait précis, l’erreur vient du fait que je fais une jointure externe avec l’opérateur ‘OR’ sur plusieurs champs issus de plus d’une table contenue dans mes sous-requêtes… C'est très pointu...
    Avec l’opérateur ‘AND’ dans le 'ON', pas de problème.
    Avec seulement les champs provenant de la table ‘Articles’ de mes sous-requête, mais l’opérateur ‘OR’, pas de problème
    Avec la même jointure mais en INNER JOIN, pas de problème.

    Ai-je atteint une limite du SQL ?
    Est-ce du à mon SGBD, à son optimiseur ?
    Avez-vous une syntaxe alternative ?

    Je vous remercie d'avance pour le temps que vous prendrez à essayer de résoudre mon problème.

    Bien à vous,

  2. #2
    Rédacteur
    Avatar de SQLpro
    Homme Profil pro
    Expert SGBDR & SQL, spécialiste Microsoft SQL Server
    Inscrit en
    mai 2002
    Messages
    18 334
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert SGBDR & SQL, spécialiste Microsoft SQL Server
    Secteur : Conseil

    Informations forums :
    Inscription : mai 2002
    Messages : 18 334
    Points : 42 847
    Points
    42 847

    Par défaut

    Un OR peut toujours être remplacé par un UNION ou UNION ALL

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence * * * * *

  3. #3
    Modérateur

    Profil pro
    Inscrit en
    janvier 2010
    Messages
    4 990
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : janvier 2010
    Messages : 4 990
    Points : 10 224
    Points
    10 224

    Par défaut

    Bonjour,

    Le OR dans la condition de jointure devrait passer... si ce n'est pas le cas, c'est bien une limitation de votre SGBD. quel est le message d'erreur ?

    D’ailleurs, vous dites que c'est la dernière ligne qui plante, mais juste au dessus il y a déjà un OR... est-ce que celui-ci passe ?

  4. #4
    Rédacteur
    Avatar de SQLpro
    Homme Profil pro
    Expert SGBDR & SQL, spécialiste Microsoft SQL Server
    Inscrit en
    mai 2002
    Messages
    18 334
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert SGBDR & SQL, spécialiste Microsoft SQL Server
    Secteur : Conseil

    Informations forums :
    Inscription : mai 2002
    Messages : 18 334
    Points : 42 847
    Points
    42 847

    Par défaut

    Au passage votre requête peut être récrite :

    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
    SELECT -- Base 95
           A95.CodeArticle AS CodeArticle95, 
           A95.Barcode AS BarCode95, 
           AF95.CodeArtFou AS CodeArtFou95, 
           A95.LibelléArticle AS LibelléArticle95, 
           -- Base 17
           A17.CodeArticle AS CodeArticle17, 
           A17.Barcode AS BarCode17, 
           AF17.CodeArtFou AS CodeArtFou17, 
           A17.LibelléArticle AS LibelléArticle17
    FROM   Articles AS A95
           LEFT OUTER JOIN ArtFou AS AF95
    	        ON A95.BaseArticles = AF95.BaseArticles 
                   AND A95.CodeArticle = AF95.CodeArticle
                   AND AF95.CodeDépôt = '0'
                   AND A95.BaseArticles = '95'
          FULL OUTER JOIN Articles AS A17
    	       LEFT OUTER JOIN ArtFou AS AF17
    	            ON A17.BaseArticles = AF17.BaseArticles 
                       AND A17.CodeArticle = AF17.CodeArticle
                       AND AF17.CodeDépôt = '0'
                       AND A17.BaseArticles = '17'
             ON (AF95.CodeArtFou = AF17.CodeArtFou
    	         OR A95.CodeArticle = A17.CodeArticle) 
    	/*OR Base95.Barcode = Base17.Barcode*/
    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence * * * * *

  5. #5
    Membre à l'essai
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    août 2017
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : Belgique

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Bâtiment

    Informations forums :
    Inscription : août 2017
    Messages : 16
    Points : 14
    Points
    14

    Par défaut

    Bonjour SQL Pro et aieeeuuuu,

    SQL Pro, merci pour ces remarques pertinentes !

    En effet, la requête fonctionne grâce à à des UNION. Merci pour le truc !

    Et je me doutais bien qu'il y avait un moyen d'éviter les sous-requêtes par des JOIN mais j'ignorais comment. Ou plutôt j'avais plus de facilité de conceptualiser la requête grâce aux sous-requêtes.
    Cependant, cela ne fonctionne pas avec cette requête pour la même raison que celle présentée dans mon 1er message.

    aieeeuuuu, le OR dans la jointure fonctionne bien. C'est la combinaison de l'utilisation d'un OUTER JOIN, d'un OR et de champs provenant de plusieurs tables (ici Articles et ArtFou) qui fait planter ma requête. Séparément, ils fonctionnent tous.
    D'ailleurs je remarque une coquille dans mon 1er msg, je n'ai pas mis la bonne ligne en commentaire... c'est la ligne 55 : "ON (Base95.CodeArtFou = Base17.CodeArtFou" qui cloche, car elle utilise des champs d'une autre table que les autres conditions dans le ON.
    Voici le message d'erreur.
    ERREUR : source lines(3) : SQLCODE=-94 : Utilisation de OUTER JOIN non prise en charge. ERREUR : source lines(3) : SQLCODE=-94 : Utilisation de OUTER JOIN non prise en charge.
    Quoi qu'il en soit, le problème est résolu. Ou presque... J'ai des lignes bizarres qui apparaissent, je cherche encore la raison... je reviendrai vers vous si c'est dû à la requête.

    Merci !

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

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