Précédent   Forum des professionnels en informatique > Bases de données > Firebird > SQL
SQL Forum d'entraide sur le SQL pour Firebird
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 19/01/2005, 10h17   #1
Membre à l'essai
 
Inscription : janvier 2004
Messages : 44
Détails du profil
Informations personnelles :
Localisation : Belgique

Informations forums :
Inscription : janvier 2004
Messages : 44
Points : 23
Points : 23
Par défaut Pb Jointure reflexive et champ NULL

Bonjour,

J'ai un pb sur la requete suivante qui me permet de construire une vue:

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
     SELECT L1.NO_LIGNE_BUDGET,
     L1.VALEUR,
     L1.NO_LIGNE_BUDGET_HISTO,
     L1.NO_BUDGET,
     L1.DATE_ECHEANCE,
     L1.TITRE_LIGNE_BUDGET,
     L1.DATE_CREATION,
     L1.COMMENTAIRE_HISTO,
     L1.LIB_COLLAB_CREA,
     L1.TYPE_LIGNE,
     'F'
     FROM LIGNES_BUDGET L1
     INNER JOIN LIGNES_BUDGET L2
     ON (L1.no_ligne_budget) NOT IN (L2.no_ligne_budget_histo)
La table lignes_budget possede une clé secondaire reflexive sur le champs NO_LIGNE_BUDGET_HISTO qui permet de stocker l'historique de modification des lignes de budget. Le but de la vue est de faire apparaitre pour chaque ligne si elle a été utilisée dans le cadre d'une historisation en marquant un champ à la valeur V ou F.

Le code ci-dessus devrait donc retourner les lignes de budgets qui ne sont pas liées à une historisation.

Le probleme est le suivant, si le champ ligne_budget_histo est à NULL pour tout les enregistrements, la requete ne retourne rien, a partir d'une moment ou une des lignes a une valeur pour ce champ, la vue est créée correctement.

Je n'arrive pas à comprendre cette erreur au niveau de ma syntaxe SQL. Est ce que c'est un bug de Firebird (1.5.1) ou bien une mauvaise utilisation des champs à NULL???
VincentR est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/01/2005, 10h42   #2
Membre Expert
 
Avatar de Barbibulle
 
Frédéric
Inscription : octobre 2002
Messages : 1 722
Détails du profil
Informations personnelles :
Nom : Frédéric
Âge : 42

Informations forums :
Inscription : octobre 2002
Messages : 1 722
Points : 2 025
Points : 2 025
C'est plutot étrange votre jointure.

Utiliser un Not IN alors qu'il n'y a qu'une valeur à droite n'est pas très judicieux. Un <> serait plus juste d'un point de vue syntaxe.

Maintenant d'un point de vue raisonnement il y a il me semble bien plus simple. Plutot que de faire un UNION de deux requetes (une qui selectionne les enregistrements ayant un historique et une seconde ceux sans historique) faire une seule requete avec une jointure gauche.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SELECT L1.NO_LIGNE_BUDGET, 
     L1.VALEUR, 
     L1.NO_LIGNE_BUDGET_HISTO, 
     L1.NO_BUDGET, 
     L1.DATE_ECHEANCE, 
     L1.TITRE_LIGNE_BUDGET, 
     L1.DATE_CREATION, 
     L1.COMMENTAIRE_HISTO, 
     L1.LIB_COLLAB_CREA, 
     L1.TYPE_LIGNE, 
     'F' AS HISTORISATION 
     case when L2.no_ligne_budget_histo IS NULL then 'F' else 'V' end AS HISTORISATION
     FROM LIGNES_BUDGET L1 
     LEFT JOIN LIGNES_BUDGET L2 
     ON (L1.no_ligne_budget = L2.no_ligne_budget_histo)
Je ne suis pas certain d'avoir bien utilisé les bonnes colonnes pour la jointure, vu que je ne connais pas votre contrainte d'intégrité.
Mais bon dans l'esprit c'est plutot ce genre de requete qu'il faut faire d'un point de vue performance c'est bien mieux.
Barbibulle est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/01/2005, 11h08   #3
Membre à l'essai
 
Inscription : janvier 2004
Messages : 44
Détails du profil
Informations personnelles :
Localisation : Belgique

Informations forums :
Inscription : janvier 2004
Messages : 44
Points : 23
Points : 23
Ta requete ne me semble pas convenir. En fait lorsqu'une ligne a été "historisée" cela signifie qu'une nouvelle ligne la remplace est donc que l'ancienne est devenue obsolete. Ce n'est pas parce que le champ no_ligne_budget_histo de la ligne n°36 est à NULL que la ligne n'est pas obsolete!!! Ainsi une autre ligne de budget avoir le champ no_ligne_budget_histo=36 est ainsi rendre la ligne 36 obsolete.

Ensuite, oui effectivement pour le NOT IN, j'avais mis <> au départ mais vu que la requete ne retournait pas qqch de juste j'ai essayait avec autre chose et j'ai pas remi ma requete telle qu'elle etait au départ

En tout cas le principe que tu me donnes à l'air bon je teste et je vous dis ce que ca donne
VincentR est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/01/2005, 11h32   #4
Membre Expert
 
Avatar de Barbibulle
 
Frédéric
Inscription : octobre 2002
Messages : 1 722
Détails du profil
Informations personnelles :
Nom : Frédéric
Âge : 42

Informations forums :
Inscription : octobre 2002
Messages : 1 722
Points : 2 025
Points : 2 025
Citation:
Envoyé par VincentR
Ta requete ne me semble pas convenir. En fait lorsqu'une ligne a été "historisée" cela signifie qu'une nouvelle ligne la remplace est donc que l'ancienne est devenue obsolete. Ce n'est pas parce que le champ no_ligne_budget_histo de la ligne n°36 est à NULL que la ligne n'est pas obsolete!!!
Ce n'est pas ce que j'ai écrit
Soit vous ne connaissez pas les jointures gauches soit vous n'avez pas vu que j'en avait faite une.

Ma requete liste toutes les lignes de votre table. Puis regarde s'il y a une ligne de cette table qui aurait la colonne histo égale à son numéro de ligne.

S'il trouve une tel correspondance toutes les valeurs des colonnes de L2 et notamment la valeur histo ne sera pas null (puisqu'il aura trouvé une valeur de jointure) s'il ne trouve pas de correspondance toutes les valeurs de L2 (et donc L2...histo) sont à null.

Ce qui veux bien dire que quand L2.histo est à null (j'insiste sur L2) c'est qu'il n'y a pas d'historisation.
Barbibulle est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/01/2005, 11h49   #5
Membre à l'essai
 
Inscription : janvier 2004
Messages : 44
Détails du profil
Informations personnelles :
Localisation : Belgique

Informations forums :
Inscription : janvier 2004
Messages : 44
Points : 23
Points : 23
Ca y est :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT L1.NO_LIGNE_BUDGET,
     L1.VALEUR,
     L1.NO_LIGNE_BUDGET_HISTO,
     L1.NO_BUDGET,
     L1.DATE_ECHEANCE,
     L1.TITRE_LIGNE_BUDGET,
     L1.DATE_CREATION,
     L1.COMMENTAIRE_HISTO,
     L1.LIB_COLLAB_CREA,
     L1.TYPE_LIGNE,
     case when L1.no_ligne_budget NOT IN (SELECT NO_LIGNE_BUDGET_HISTO
                                         FROM LIGNES_BUDGET
                                         WHERE NO_LIGNE_BUDGET_HISTO IS NOT NULL) then 'F' else 'V' end AS OBSOLETE
     FROM LIGNES_BUDGET L1;
Si y a une autre solution qui est préférable dites moi
VincentR est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/01/2005, 11h56   #6
Membre Expert
 
Avatar de Barbibulle
 
Frédéric
Inscription : octobre 2002
Messages : 1 722
Détails du profil
Informations personnelles :
Nom : Frédéric
Âge : 42

Informations forums :
Inscription : octobre 2002
Messages : 1 722
Points : 2 025
Points : 2 025
Votre solution marchera, mais sera bien moins performante que la mienne. Plus vous aurez d'enregistrement dans votre table plus votre requete sera lente et lourde à exécuter.

Une jointure gauche sera plus performante.
Barbibulle est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/01/2005, 11h59   #7
Membre à l'essai
 
Inscription : janvier 2004
Messages : 44
Détails du profil
Informations personnelles :
Localisation : Belgique

Informations forums :
Inscription : janvier 2004
Messages : 44
Points : 23
Points : 23
Ok pardon j'avais pas vu le post précedant, donc oui j'ai compris, désolé ca me paraissait pas évident à voir votre démarche, mais c'est vrai que c'est efficasse

Merci, j'opte pour votre solution alors
VincentR est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/01/2005, 12h52   #8
Membre Expert
 
Avatar de Barbibulle
 
Frédéric
Inscription : octobre 2002
Messages : 1 722
Détails du profil
Informations personnelles :
Nom : Frédéric
Âge : 42

Informations forums :
Inscription : octobre 2002
Messages : 1 722
Points : 2 025
Points : 2 025
Citation:
Envoyé par VincentR
Ok pardon j'avais pas vu le post précedant, donc oui j'ai compris, désolé ca me paraissait pas évident à voir votre démarche, mais c'est vrai que c'est efficasse

Merci, j'opte pour votre solution alors
Vous n'avez pas à vous excuser il n'y pas de mal.
D'autant plus que je vous ai raconté des bétises.
A cause de (ou plutot grace à ) la mise en cache du résultat de la sous requete il se pourait que votre solution soit plus performante.
Donc c'est a vous de regarder laquel est la plus performante des deux.

De plus vous avez trouvé une solution ce qui est bien (C'est toujours mieux quand on trouve par soit même).
Donc félicitation.

Il y a aussi une autre solution (qui aura les même performances que celle que vous avez proposé) :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT L1.NO_LIGNE_BUDGET, 
     L1.VALEUR, 
     L1.NO_LIGNE_BUDGET_HISTO, 
     L1.NO_BUDGET, 
     L1.DATE_ECHEANCE, 
     L1.TITRE_LIGNE_BUDGET, 
     L1.DATE_CREATION, 
     L1.COMMENTAIRE_HISTO, 
     L1.LIB_COLLAB_CREA, 
     L1.TYPE_LIGNE, 
     case when EXISTS (SELECT NO_LIGNE_BUDGET_HISTO 
                                         FROM LIGNES_BUDGET 
                                         WHERE NO_LIGNE_BUDGET_HISTO = L1.no_ligne_budget) then 'V' else 'F' end AS OBSOLETE 
     FROM LIGNES_BUDGET L1;
Bonne continuation.
Barbibulle est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 19/01/2005, 14h14   #9
Membre à l'essai
 
Inscription : janvier 2004
Messages : 44
Détails du profil
Informations personnelles :
Localisation : Belgique

Informations forums :
Inscription : janvier 2004
Messages : 44
Points : 23
Points : 23
Juste pour l'info, avec l'analyseur de performance de requetes de IBManager, j'obtient bien les meme performances avec les requetes utilisants le IN et le EXIST et celles ci sont plus efficasses que la requete utilisant la jointure :p

Voili
VincentR est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 18h51.


 
 
 
 
Partenaires

Hébergement Web