{"id":392,"date":"2012-05-08T00:00:03","date_gmt":"2012-05-08T00:00:03","guid":{"rendered":"http:\/\/www.sqlserver.fr\/blog\/?p=392"},"modified":"2026-05-02T14:31:15","modified_gmt":"2026-05-02T12:31:15","slug":"null-nest-pas-une-valeur","status":"publish","type":"post","link":"https:\/\/www.sqlserver.fr\/blog\/null-nest-pas-une-valeur\/","title":{"rendered":"Null n&rsquo;est pas une valeur"},"content":{"rendered":"<p>Cet article s&rsquo;adresse \u00e0 tous ceux et celles qui consid\u00e8rent Null comme une valeur particuli\u00e8re. Je pense notamment aux d\u00e9veloppeurs C#, pour qui null est une valeur sp\u00e9cifique.<\/p>\n<p>Du point de vue SQL Server, <strong>Null n&rsquo;est pas une valeur<\/strong>, mais refl\u00e8te la non connaissance d&rsquo;une information.<!--more--><\/p>\n<p>Sous SQL Server, Null indique une absence d&rsquo;information. Prenons par exemple cette liste de Produits.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">use tempdb\r\ngo\r\ncreate table Produits (IdProduit int identity,\r\n\t\t\t\t\t\tNom varchar(100),\r\n\t\t\t\t\t\tPrix money)\r\ninsert into Produits (Nom,Prix)\r\n\tvalues ('Clavier',10),\r\n\t\t\t('Ecran', 100),\r\n\t\t\t('Souris', 15),\r\n\t\t\t('CPU', Null),\r\n\t\t\t('Webcam',40)<\/pre>\n<p>Si l&rsquo;on cherche \u00e0 avoir tous les produits de 50 Euros ou moins, on obtient le clavier, la souris et la webcam.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">select *\r\nfrom Produits\r\nwhere Prix&lt;=50<\/pre>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/Inf50.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-419\" title=\"Inf50\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/Inf50.png\" alt=\"\" width=\"208\" height=\"106\" \/><\/a><\/p>\n<p>Et si l&rsquo;on cherche \u00e0 avoir tous les produits de plus de 50 Euros, il n&rsquo;y a que l&rsquo;Ecran.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">select *\r\nfrom Produits\r\nwhere Prix&gt;50<\/pre>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/Sup50.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-420\" title=\"Sup50\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/Sup50.png\" alt=\"\" width=\"199\" height=\"77\" \/><\/a><\/p>\n<p>Et o\u00f9 est le CPU dans l&rsquo;histoire ? Et bien l&rsquo;assertion \u00ab\u00a0Le prix est inf\u00e9rieur ou \u00e9gal \u00e0 50 Euros\u00a0\u00bb ne peut pas \u00eatre consid\u00e9r\u00e9e comme vraie, puisqu&rsquo;on ne connait pas le prix du CPU. Mais en m\u00eame temps, l&rsquo;assertion \u00ab\u00a0Le prix du CPU est sup\u00e9rieur \u00e0 50 Euros\u00a0\u00bb ne peut pas non plus \u00eatre consid\u00e9r\u00e9e comme vraie. En fait, Null signifie qu&rsquo;on ne connait pas le prix du CPU, et donc qu&rsquo;on ne peut comparer quelque chose qu&rsquo;on ne connait pas \u00e0 50 Euros. Est-ce plus cher ? Est-ce moins cher ? On ne sait pas.<\/p>\n<p>Mais ce qu&rsquo;il est vraiment primordial de comprendre, c&rsquo;est que, par exemple, l&rsquo;assertion \u00ab\u00a0Le prix est inf\u00e9rieur ou \u00e9gal \u00e0 50 Euros\u00a0\u00bb n&rsquo;est pas vraie, mais elle n&rsquo;en est pas n\u00e9anmoins fausse pour autant !<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">select *\r\nfrom Produits\r\nwhere NOT (Prix&lt;=50)<\/pre>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/Sup50.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" title=\"Sup50\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/Sup50.png\" alt=\"\" width=\"199\" height=\"77\" \/><\/a><\/p>\n<p>En fait, on ne peut pas dire que le prix du CPU est inf\u00e9rieur \u00e0 50 Euros, mais on ne peut pas dire non plus qu&rsquo;il ne l&rsquo;est pas ! L&rsquo;\u00e9tat de cette assertion est \u00ab\u00a0Inconnu\u00a0\u00bb.<\/p>\n<p>Et sous SQL Server, les clauses \u00ab\u00a0Where\u00a0\u00bb, de m\u00eame que les jointures, filtrent les enregistrements pour lesquels le pr\u00e9dicat est vrai. Et par vrai, il est entendu que le pr\u00e9dicat est confirm\u00e9 comme v\u00e9rifi\u00e9.<\/p>\n<p>Attention, toute la subtilit\u00e9 est l\u00e0 : <strong>un pr\u00e9dicat vrai, ce n&rsquo;est pas un pr\u00e9dicat qui n&rsquo;est pas faux<\/strong>.<\/p>\n<p>Dans notre cas, le fait de dire que l&rsquo;assertion NOT (Prix&lt;=50) est vraie revient \u00e0 dire que l&rsquo;assertion Prix&lt;=50 est fausse. Or nous avons vu que, pour le cas de notre produit CPU, nous ne pouvons pas affirmer que l&rsquo;assertion Prix&lt;=50 est fausse, car nous ne connaissons pas le prix. Nous ne pouvons rien dire, tout simplement.<\/p>\n<p>Voici au final une requ\u00eate qui r\u00e9sume la probl\u00e9matique :<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">select *\r\nfrom Produits\r\nwhere\t(Prix&lt;=50)\r\n\tOR\r\n\t\t(NOT (Prix&lt;=50))<\/pre>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/InfOrNotInf1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-425\" title=\"InfOrNotInf\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/InfOrNotInf1.png\" alt=\"\" width=\"208\" height=\"128\" \/><\/a><\/p>\n<p>Il nous manque bien notre produit CPU.<\/p>\n<p>Il n&rsquo;est pas vrai de dire que son prix est inf\u00e9rieur \u00e0 50 Euros, mais il n&rsquo;est pas vrai de dire qu&rsquo;il est faux de dire que son prix est inf\u00e9rieur \u00e0 50 Euros. (\u00e7a commence \u00e0 devenir un peu compliqu\u00e9, l\u00e0&#8230; :-) \u00a0)<\/p>\n<p>Quand on ne sait pas, on n&rsquo;affirme rien, mais on ne nie rien non plus&#8230;<\/p>\n<p>Pour finir, rajoutons quelques produits dans la liste.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">insert into Produits (Nom,Prix)\r\n\tvalues ('Tapis souris',10),\r\n\t\t\t('Carte graphique', 100),\r\n\t\t\t('Carte m\u00e8re', Null)<\/pre>\n<p>Et regardons les paires de produits ayant le m\u00eame prix :<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">select p1.Nom, p2.Nom\r\nfrom Produits p1\r\n\tjoin Produits p2 on p1.IdProduit &lt; p2.IdProduit\r\n\t\t\t\t\tand p1.Prix=p2.Prix<\/pre>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/PrixIdentiques.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-424\" title=\"PrixIdentiques\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/PrixIdentiques.png\" alt=\"\" width=\"183\" height=\"92\" \/><\/a><\/p>\n<p>Les produits Carte M\u00e8re et CPU n&rsquo;ont pas n\u00e9cessairement le m\u00eame prix donc, logiquement, on ne les voit pas dans la liste.<\/p>\n<p>Mais si on cherche les prix diff\u00e9rents :<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">select p1.Nom, p2.Nom\r\nfrom Produits p1\r\n\tjoin Produits p2 on p1.IdProduit &lt; p2.IdProduit\r\n\t\t\t\t\tand p1.Prix&lt;&gt;p2.Prix<\/pre>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/PrixDifferents.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-426\" title=\"PrixDifferents\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/05\/PrixDifferents.png\" alt=\"\" width=\"213\" height=\"296\" \/><\/a><\/p>\n<p>Il est tr\u00e8s int\u00e9ressant de voir que ni le CPU, ni la Carte m\u00e8re ne sont pr\u00e9sents dans la liste. Et pour cause, \u00e9tant donn\u00e9 qu&rsquo;on ne connait pas leur prix, on ne peut pas affirmer qu&rsquo;il est diff\u00e9rent du prix de tel ou tel autre produit. Et m\u00eame, tout comme on ne pouvait pas affirmer que ces deux produits avaient le m\u00eame prix, on ne peut pas affirmer qu&rsquo;ils sont de prix diff\u00e9rents.<\/p>\n<p><strong>Null n&rsquo;est pas \u00e9gal \u00e0 Null, mais Null n&rsquo;est pas diff\u00e9rent de Null.<\/strong><\/p>\n<p>Au final, Null n&rsquo;est pas un pointeur vers l&rsquo;adresse m\u00e9moire 0, c&rsquo;est la marque d&rsquo;une non-connaissance, et donc la fin de toute assertion.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cet article s&rsquo;adresse \u00e0 tous ceux et celles qui consid\u00e8rent Null comme une valeur particuli\u00e8re. Je pense notamment aux d\u00e9veloppeurs C#, pour qui null est une valeur sp\u00e9cifique. Du point de vue SQL Server, Null n&rsquo;est pas une valeur, mais &hellip; <a href=\"https:\/\/www.sqlserver.fr\/blog\/null-nest-pas-une-valeur\/\">Continuer la lecture <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-392","post","type-post","status-publish","format-standard","hentry","category-article_sql"],"_links":{"self":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/392","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/comments?post=392"}],"version-history":[{"count":22,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/392\/revisions"}],"predecessor-version":[{"id":1956,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/392\/revisions\/1956"}],"wp:attachment":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/media?parent=392"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/categories?post=392"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/tags?post=392"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}