Très intéressant.
Merci, encore une fois, fsmrel de nous bercer de philosophie et d'humour au milieu des discussions techniques.
Très intéressant.
Merci, encore une fois, fsmrel de nous bercer de philosophie et d'humour au milieu des discussions techniques.
A noter que NULL n'est pas une valeur mais un marqueur, c'est a dire qu'il représente l'absence de connaissance d'une valeur existante.
En effet quand on traite un NULL on traite bel et bien une valeur sans la connaitre.
C'est d'ailleurs aussi pour cela que la norme SQL impose de retourner chaque NULL, lors d'un distinct par exemple. En effet ces NULL représente une valeur que l'on ne connait pas, elle n'est donc pas évaluable et sans évaluation on se contente de retourner l'information directement. Suivant donc cette logique je ne suis pas contre les NULL, bien au contraire je pense que c'est idéal pour désigner une information non connue, chose qui arrive tous les jours.
Bien sûr cette théorie n'est pas suivi par tous les SGBD, et puis je peut me tromper ce n'est que ma manière de voir.
Ce que fsmrel veut dire c'est qu'on peut modéliser de manière à ne pas avoir de colonnes NULLables. Là ou le marqueur NULL désigne l'absence de valeur, la non présence d'un enregistrement la désigne aussi bien.
Ainsi en prenant l'exemple absurde suivant :
Entite1 = {Id_Entite}
ValeurAttributEntite1 = {#Id_Entite, Valeur}
Modélise bien un attribut de l'Entité1 nullable sans colonne nullable dans la table. Bon évidemment quand on fait une jointure externe, on retrouve le NULL en cas de non présence de la donnée .
Encore beaucoup de choses intéressantes écrites dans les derniers messages, et trop peu de temps pour les étudier comme elles le mériteraient !
En quelques mots :
N'y allons pas par quatre chemins : je ne connaissais pas la clause WITH. Je me garderai donc bien de la ranger d'emblée dans telle ou telle catégorie. Où la situerais-tu pour ta part ?
Au fait, est-elle largement implémentée dans le petit monde des SGBD ?
Remarque : une chose que j'ai omis de préciser lors de nos précédentes discussions : j'ai pris l'habitude de tutoyer sur le forum, mais si tu préfères que je te vouvoie, n'hésite pas à me le faire savoir, ça ne me dérangerait aucunement.
Le NULL a en effet un statut bien particulier en SQL. Malheureusement, l'exemple est mal choisi, car il se trouve que, dans le cadre d'un GROUP BY (donc d'un DISTINCT), il est en l'occurrence traité comme n'importe quelle valeur :
Source : http://msdn2.microsoft.com/en-us/library/ms187007.aspxIf the grouping column contains a null value, that row becomes a group in the results. If the grouping column contains more than one null value, the null values are put into a single group. This behavior is defined in the SQL-2003 standard.
Pour s'en convaincre, on pourra exécuter les deux requêtes suivantes :
qui renvoient donc chacune une seule ligne :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 SELECT DISTINCT F1 FROM ( SELECT NULL AS F1 UNION ALL SELECT NULL) AS T; SELECT F1 FROM ( SELECT NULL AS F1 UNION ALL SELECT NULL) AS T GROUP BY F1;
Mes découvertes, c'est notamment sur ce topic que je les fais, en lisant les différents témoignages que chacun a pu faire au sujet de la relation réflexive.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 F1 ---- NULL
Et comme vous tous, j'essaie bien sûr d'alimenter moi-même la discussion avec ce que j'ai expérimenté ces derniers jours, que ce soit sur Access ou sur SQL Server.
Je vous souhaite à tous un excellent week-end !
Tout à fait d'accord avec toi J1, et tu a raison de dire qu'un distinct sur des NULL donne un seul NULL dans la plupart des SGBD, mais ça ne veux pas dire que c'est forcément sémantiquement juste.
D'ailleurs dans ta citation, ils parlent de valeurs, hors un NULL n'est pas une valeur, et c'est même totalement le contraire puisqu'il désigne l'absence même de valeur.
Plus d'informations sur le NULL ici
Après tout ceci n'est qu'un point de vue et la théorie est très différente (ici en est la preuve).
Bonjour,
Hum... La structure de WITH est la suivante :Envoyé par J1
Si donc on admet qu’une requête (Query) est déclarative, la clause WITH est du genre déclaratif.
N.B. En réponse à votre remarque, sur le forum, j'ai pris l'habitude du "vous".
Je dois vous avouer que je n'en sais rien. La clause WITH est définie dans le cadre de la norme SQL, à laquelle sont conformes SQL Server et DB2. Concernant Oracle, la jointure récursive est disponible, mais sous une forme différente, avec une performance au demeurant excellente (par exemple, 100 millisecondes pour extraire une nomenclature, dans une table de 500000 lignes, dans un secteur où l’on ne rigole pas avec les nomenclatures, à savoir celui de la grande distribution).Envoyé par J1
Styles utilisés pour effectuer une jointure récursive (requêtes non testées) :
Soit la tableI (Composant, Composé)Pour obtenir les composants du composé "xyz" :
Selon la norme SQL (à faire valider par SQLpro) :
Avec Oracle :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 With V (Composant) As (Select Composant From I Where Composé = "xyz" UNION ALL Select I.Composant From V, I Where I.Composé = V.Composant) Select Composant From V ;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 Select Composant From I ... Start With Composé = "xyz" Connect By Prior Composant = Composé
Hors SQL, en relationnel pur (avec le langage Tutorial D) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part TCLOSE (I {Composé, Composant}) WHERE Composé = "xyz") {Composant}
Intéressant !
J'en ai profité pour parcourir le tutoriel de SQLPro, également très instructif.
Malheureusement, je ne pense pas que les SGBD que j'utilise actuellement implémentent WITH (surtout s'il est apparu avec la norme SQL:1999).
Mais ça reste bon à savoir, merci !
J'interprète votre réponse comme une invitation au vouvoiement. Aucun problème !
Pas forcément...
En préambule, NULL est pour moi le nom d’un petit personnage magique, unique mais multiforme (ou polymorphe, terme à la mode), très difficile à maîtriser, façon savonnette. Il n’est pas une valeur, il n’a pas de valeur, mais il se fait volontiers passer pour une valeur (exemple : Insert Into T Values (..., NULL, ...)). Ainsi, les auteurs de la norme SQL se sont fait piéger, en écrivant que la valeur de vérité UNKNOWN (Cf. le type BOOLEAN) et NULL sont la même chose. Si l’on n’y prend garde, NULL s'empresse de polluer les bases de données, les parasiter, les ravager à la manière des criquets. NULL est un malin, il va jusqu’à chercher à faire faire des erreurs aux optimiseurs (je reviendrai sur ce point).
Par exemple, quand JPhi33 explique à Chtouk qu’une modélisation approximative au niveau conceptuel peut avoir des conséquences funestes au niveau logique relationnel, il attire l’attention de notre jeune camarade sur l’irruption de NULL dans le résultat des requêtes et le met donc en garde. Ainsi, quand Chtouk met en scène des universitaires dont certains seulement sont des étudiants, JPhi33 lui explique la technique de la spécialisation, laquelle est particulièrement satisfaisante d’un point de vue sémantique, et conduit en plus au niveau logique à avoir deux tables tout à fait saines :
Une table UNIVERSITAIRE contenant les attributs communs à tous les universitaires, ainsi qu’une table ETUDIANT contenant les attributs ne caractérisant que les étudiants. Un de ces attributs spécifiques a pour nom EstBoursier et permet de savoir si un étudiant est boursier, oui ou non.
Avec ce système, au niveau tabulaire on peut coder "NOT NULL" pour chaque attribut, ce qui est un but à atteindre. Maintenant, que se passe-t-il si on décide de n’avoir qu’une seule table, à savoir la table UNIVERSITAIRE ? En toute logique, on autorisera NULL à se manifester.
Je reprends le contenu de la table UNIVERSITAIRE, quand celle-ci a phagocyté la table ETUDIANT :
DUBOIS et MARTIN ne sont pas des étudiants : en conséquence, contrairement à ce vous dites, kazou, par sa présence NULL ne signale pas ici la méconnaissance que nous aurions d’une valeur, mais bien le fait qu’être boursier ou non n’a aucun sens pour les universitaires qui ne sont pas des étudiants. Ce qui est fâcheux, c’est que si l’on admet que l’on puisse ignorer qu'un étudiant soit boursier ou non, on peut se retrouver dans la situation inconfortable suivante :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 Table UNIVERSITAIRE Ref NomUniv PrenomUniv EstBoursier --- ------- ---------- ----------- U-1 DUBOIS Aline NULL U-2 DUPONT Bertrand Non U-3 DURAND Charlène Oui U-4 MARTIN Didier NULL
Et les choses commencent à se gâter, du fait de l’ambiguïté apportée par NULL qui, je le rappelle, est multiforme, et l’on ne sait plus quelle signification donner à NULL selon que l’universitaire s’appelle DUBOIS, MARTIN ou MOREAU : Il devient urgent de suivre le conseil de JPhi33, même si ce farceur de NULL cherchera évidemment à revenir par la fenêtre.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 Table UNIVERSITAIRE Ref NomUniv PrenomUniv EstBoursier --- ------- ---------- ----------- U-1 DUBOIS Aline NULL U-2 DUPONT Bertrand Non U-3 DURAND Charlène Oui U-4 MARTIN Didier NULL U-5 MOREAU Exupère NULL
Pour lever le genre d’ambiguïté que je viens d’évoquer, Ted Codd avait mis en œuvre une logique quadrivaluée, selon laquelle les valeurs de vérité ne sont plus seulement TRUE, FALSE et UNKNOWN, mais TRUE, FALSE, APPLICABLE et INAPPLICABLE. Selon cette logique, lorsque vous dites "quand on traite un NULL on traite bel et bien une valeur sans la connaître", vous signifiez que NULL se déguise en APPLICABLE, ce qui dans l’exemple de Chtouk correspond à la situation "On se sait pas si MOREAU est boursier", tandis que dans le cas de DUBOIS, MARTIN, NULL se déguise clairement en INAPPLICABLE.
Pour la petite histoire, la logique quadrivaluée de Codd est "inapplicable" (sic), car, entre autres, des lois fondamentales telles que les lois de De Morgan sont mises en échec :
¬(p ET q)et
¬p OU ¬qne sont plus des formules équivalentes : si p et q prennent respectivement les valeurs de vérité APPLICABLE et INAPPLICABLE, la 1re expression sera évaluée à INAPPLICABLE tandis que la 2e sera évaluée à APPLICABLE. De la même façon, l’équivalence suivante ne vaut plus :
∀x (p) ≡ ¬∃x (¬p)Ou si vous préférez, "Tous les hommes sont mortels" n’est plus équivalent à "Il n’existe pas d’homme non mortel".
NULL et les optimiseurs :
Les optimiseurs sont généralement friands de ce que l’on appelle la fermeture transitive, ne serait-ce que pour rendre les requêtes plus performantes (c’est une de leurs missions...)
Considérez la séquence suivante :
Puis la requête (due à Chris Date) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 Create table Dept ( DeptNo Char (4) not null , Primary key (deptNo)) ; Create table Emp ( EmpNo Char (4) not null , DeptNo Char (4) , Primary key (EmpNo) , Foreign Key (DeptNo) references Dept) ; Insert Into Dept Values ('d2') ; Insert Into Emp Values ('e1', 'd2') ; Insert Into Emp Values ('e2', Null) ;
L’optimiseur devrait normalement appliquer la fermeture transitive en enrichissant ainsi la requête :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 Select EmpNo From Dept d, Emp e Where Not (d.DeptNo = e.DeptNo And e.DeptNo = 'd1') ;
mais la présence possible du camarade NULL l’incitera à n’en rien faire. En exécutant les requêtes, vous noterez la différence dans les résultats.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 Select EmpNo From Dept d, Emp e Where Not (d.DeptNo = e.DeptNo And e.DeptNo = 'd1' And d.DeptNo = 'd1') ;
Accessoirement, je rappelle ce qu’a écrit Codd concernant l’ensemble vide [The Relational Model for Database Management: Version 2 (Reading, Mass.: Addison-Wesley, 1990), page 188] :
"SQL fournit NULL comme résultat de certaines fonctions statistiques (telles qu’AVERAGE) appliquées à l’ensemble vide. Puisque le NULL de SQL a été introduit pour signifier le fait qu’une valeur (db-value) est inconnue, ça n’est pas un choix judicieux de signifier dans ce contexte quelque chose de complètement différent, à savoir qu’un résultat arithmétique est indéfini."
En l’occurrence, NULL se manifeste à nouveau, déguisé encore autrement (combien a-t-il de costumes ce Frégoli des bases de données ?)
Sur le WITH et le récursivité :
SQL Server, IBM DB2, Sybase et Firebird le gère, soit plus de 67% des parts de marché.
Oracle gère cela de manière spécifique (une grosse connerie entre nous) uniquement pour les arbres (les parcours de graphe ne sont pas gérés).
MySQL et PostGreSQL ne savent pas faire...
Bref avec Oracle qui gère cela à moitié cela représente plus de 87 % de parts de marché !
A +
D'un DISTINCT comme d'un ALL (ALL étant par défaut)...
Si tous les SGBDR sont conforme à la norme en matière de NULL à quelques très rares exceptions près...
1) Oracle fait confusion du NULL avec la chaine vide. Un paramètre est à modifier pour contournement
2) Sybase SQL Server permet une unicité de NULL (et MS SQL server en a hérité). Contournement possible avec les index uniques filtrés (WHERE MaColonne IS NOT NULL)
Sinon il y a plein de chose drôles avec les NULL...Extrait de mon livre "SQL la synthèse" dont le chapitre 2 va paraître en ligne sur ce site bientôt.... (le chapitre 1 est ici...)
La présence du NULL provoque parfois des résultats qui peuvent surprendre au premier abord parce que parfois contre intuitive dans certains prédicats. Voici quelques exemples des problématiques dont il faut avoir conscience... Voici quelques exemples.
Exemple 2.45* – influence du NULL…
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 -- Avec la table suivante : CREATE TABLE T_NUL (NUL_X INT, NUL_Y INT); INSERT INTO T_NUL VALUES (1, 1); INSERT INTO T_NUL VALUES (1, 2); INSERT INTO T_NUL VALUES (NULL, 2); INSERT INTO T_NUL VALUES (1, NULL); INSERT INTO T_NUL VALUES (NULL, NULL);À la lecture, les paires de requêtes suivantes semblent donner le même résultat, or il n'en est rien...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 -- dont le contenu est : NUL_X NUL_Y ----------- ----------- 1 1 1 2 NULL 2 1 NULL NULL NULL
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 SELECT * FROM T_NUL WHERE NUL_X = NUL_Y OR NOT (NUL_X = NUL_Y); SELECT * FROM T_NUL; NUL_X NUL_Y ----------- ----------- 1 1 1 2 NUL_X NUL_Y ----------- ----------- 1 1 1 2 NULL 2 1 NULL NULL NULL
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 SELECT SUM(NUL_X) + SUM(NUL_Y) AS N FROM T_NUL; SELECT SUM(NUL_X + NUL_Y) AS N FROM T_NUL; N ----------- 8 N ----------- 5
Il y a aussi le fait que NULL existe !
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 SELECT CASE WHEN NUL_X = NUL_Y THEN 1 ELSE 0 END AS TRUTH FROM T_NUL; SELECT CASE WHEN NOT(NUL_X=NUL_Y) THEN 1 ELSE 0 END AS TRUTH FROM T_NUL; TRUTH ----------- 1 0 0 0 0 TRUTH ----------- 0 1 0 0 0
La requête suivante :
Renverra bien une ligne NULLe !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 SELECT 1 AS N WHERE EXISTS(SELECT * FROM T_NULL WHERE NUL_X IS NULL AND NUL_Y IS NULL)
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager