SQL中三值逻辑和NULL的具体使用
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">NULL的特性</a></li><li><a href="#_label1">NULL在SQL逻辑运算中的影响</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_0">1. 逻辑运算 (AND, OR, NOT)</a></li><li><a href="#_lab2_1_1">2. NULL参与比较 (=, !=, >, <, etc.)</a></li><li><a href="#_lab2_1_2">3. NULL在IN 和 NOT IN中的影响</a></li><li><a href="#_lab2_1_3">4. NULL在DISTINCT、GROUP BY 和 ORDER BY 中</a></li><li><a href="#_lab2_1_4">5. NULL在 COALESCE 和 IFNULL 处理</a></li></ul><li><a href="#_label2">NULL 在 JOIN 中的影响</a></li><ul class="second_class_ul"></ul><li><a href="#_label3">如何正确处理 NULL</a></li><ul class="second_class_ul"></ul><li><a href="#_label4">总结(重点)</a></li><ul class="second_class_ul"></ul></ul></div><p> 在SQL中,三值逻辑是一个重要概念,它的存在主要是由于 <code>NULL</code> 值的引入。<code>NULL</code> 代表未知值,它既不是空字符串,也不是数字 0,而是一个特殊的标记,表示数据缺失或不可用。</p><p>在SQL中,由于<code>NULL</code>值的存在,导致它使用了一种特殊的逻辑作用法:<strong>三值逻辑 (Three-Valued Logic, 3VL)</strong></p>
<p>其包括三个任何逻辑计算的可能结果:</p>
<ul><li><p><strong>TRUE (真)</strong></p></li><li><p><strong>FALSE (假)</strong></p></li><li><p><strong>UNKNOWN (未知)</strong></p></li></ul>
<p><code>NULL</code>在SQL中表示“未知”或“缺失的值”,它与普通的值有很大区别。由于<code>NULL</code>表示未知值,所以任何与<code>NULL</code>进行运算的结果都应该是<code>UNKNOWN</code>,而不是TRUE或FALSE。</p>
<p class="maodian"><a name="_label0"></a></p><h2>NULL的特性</h2>
<p><code>NULL</code>并不是一个具体值,而是一个特殊状态,其具有如下特性:</p>
<ul><li><p><code>NULL</code>不能相互比较:<code>NULL = NULL</code>结果不是TRUE,而是UNKNOWN。</p></li><li><p><code>NULL</code>参与数值运算,结果为<code>NULL</code>:<code>NULL + 10</code>的结果仍然是<code>NULL</code>。</p></li><li><p><code>NULL</code>参与逻辑运算,会影响逻辑结果:</p>
<ul><li><p><code>TRUE AND NULL</code>,结果是<code>UNKNOWN</code></p></li><li><p><code>FALSE OR NULL</code>,结果是<code>UNKNOWN</code></p></li></ul></li></ul>
<p>如果WHERE条件结果为<code>UNKNOWN</code>,那么该记录将不会被查询结果包含。</p>
<p class="maodian"><a name="_label1"></a></p><h2>NULL在SQL逻辑运算中的影响</h2>
<p class="maodian"><a name="_lab2_1_0"></a></p><h3>1. 逻辑运算 (AND, OR, NOT)</h3>
<p>AND运算</p>
<table><tbody><tr><th>表达式</th><th>结果</th></tr><tr><td>TRUE AND TRUE</td><td>TRUE</td></tr><tr><td>TRUE AND FALSE</td><td>FALSE</td></tr><tr><td>TRUE AND UNKNOWN</td><td>UNKNOWN</td></tr><tr><td>FALSE AND UNKNOWN</td><td>FALSE</td></tr><tr><td>UNKNOWN AND UNKNOWN</td><td>UNKNOWN</td></tr></tbody></table>
<p> OR运算</p>
<table><tbody><tr><th>表达式</th><th>结果</th></tr><tr><td>TRUE OR UNKNOWN</td><td>TRUE</td></tr><tr><td>FALSE OR UNKNOWN</td><td>UNKNOWN</td></tr><tr><td>UNKNOWN OR UNKNOWN</td><td>UNKNOWN</td></tr></tbody></table>
<p>NOT运算 </p>
<table><tbody><tr><th>表达式</th><th>结果</th></tr><tr><td>NOT TRUE</td><td>FALSE</td></tr><tr><td>NOT FALSE</td><td>TRUE</td></tr><tr><td>NOT UNKNOWN</td><td>UNKNOWN</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_1_1"></a></p><h3>2. NULL参与比较 (=, !=, >, <, etc.)</h3>
<table><tbody><tr><th>表达式</th><th>结果</th></tr><tr><td>NULL = NULL</td><td>UNKNOWN</td></tr><tr><td>NULL != NULL</td><td>UNKNOWN</td></tr><tr><td>NULL > 10</td><td>UNKNOWN</td></tr><tr><td>NULL < 10</td><td>UNKNOWN</td></tr><tr><td>NULL IS NULL</td><td>TRUE</td></tr><tr><td>NULL IS NOT NULL</td><td>FALSE</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_1_2"></a></p><h3>3. NULL在IN 和 NOT IN中的影响</h3>
<p>如果 <code>NULL</code> 出现在 <code>IN</code> 或 <code>NOT IN</code> 语句中,会导致不可预期的结果:</p>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM users WHERE age IN (20, 30, NULL);</pre></div>
<p>由于 <code>NULL</code> 是未知值,SQL 不知道 <code>NULL</code> 是否属于 <code>age</code>,导致 <code>UNKNOWN</code>,最终查询只会匹配 <code>age=20</code> 和 <code>age=30</code>,但不会匹配 <code>NULL</code>。</p>
<p>更严重的问题出现在 <code>NOT IN</code> 中:</p>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM users WHERE age NOT IN (20, 30, NULL);</pre></div>
<p>由于 <code>NULL</code> 在 <code>IN</code> 语句中会返回 <code>UNKNOWN</code>,整个 <code>NOT IN</code> 变成 <code>UNKNOWN</code>,最终不会返回任何数据。</p>
<p>解决方法:</p>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM users WHERE age NOT IN (20, 30) OR age IS NULL;</pre></div>
<p class="maodian"><a name="_lab2_1_3"></a></p><h3>4. NULL在DISTINCT、GROUP BY 和 ORDER BY 中</h3>
<ul><li><p><strong>DISTINCT</strong> 视 <code>NULL</code> 为相同值:</p>
<div class="jb51code"><pre class="brush:sql;">SELECT DISTINCT category FROM products;</pre></div>
<p>如果 <code>category</code> 列中有多个 <code>NULL</code>,<code>DISTINCT</code> 只会保留一个 <code>NULL</code>。</p></li><li><p><strong>GROUP BY</strong> 视 <code>NULL</code> 为一个分组:</p>
<div class="jb51code"><pre class="brush:sql;">SELECT category, COUNT(*) FROM products GROUP BY category;</pre></div>
<p>所有 <code>NULL</code> 值会被归为同一组。</p></li><li><p><strong>ORDER BY</strong> 处理 <code>NULL</code>:</p>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM employees ORDER BY salary ASC;</pre></div>
<p><code>NULL</code> 默认排在最前或最后,具体行为取决于数据库:</p>
<ul><li><p>PostgreSQL: <code>NULLS FIRST</code> 或 <code>NULLS LAST</code></p></li><li><p>MySQL: <code>NULL</code> 默认排在最前</p></li><li><p>SQL Server: <code>NULL</code> 默认排在最前</p></li></ul></li></ul>
<p class="maodian"><a name="_lab2_1_4"></a></p><h3>5. NULL在 COALESCE 和 IFNULL 处理</h3>
<p>要避免 <code>NULL</code> 影响查询,可以使用 <code>COALESCE</code> 或 <code>IFNULL</code> 进行处理:</p>
<ul><li><p><code>COALESCE(expr1, expr2, ..., exprN)</code>:返回第一个非NULL值</p>
<div class="jb51code"><pre class="brush:sql;">SELECT name, COALESCE(email, '未知') AS email FROM users;</pre></div></li><li><p><code>IFNULL(expr, default_value)</code>(MySQL 专用)</p>
<div class="jb51code"><pre class="brush:sql;">SELECT name, IFNULL(email, '未知') AS email FROM users;</pre></div></li></ul>
<p class="maodian"><a name="_label2"></a></p><h2>NULL 在 JOIN 中的影响</h2>
<p>如果 <code>NULL</code> 存在于 <code>JOIN</code> 的关联列中,则该行不会被匹配:</p>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM orders
LEFT JOIN customers ON orders.customer_id = customers.id;</pre></div>
<p>如果 <code>orders.customer_id</code> 是 <code>NULL</code>,<code>= NULL</code> 结果是 <code>UNKNOWN</code>,导致 <code>INNER JOIN</code> 失败。</p>
<p><code>LEFT JOIN</code> 可以保留 <code>orders</code> 但 <code>customers</code> 数据为 <code>NULL</code>。</p>
<p class="maodian"><a name="_label3"></a></p><h2>如何正确处理 NULL</h2>
<ul><li><p>查询时使用 IS NULL 和 IS NOT NULL</p>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM users WHERE email IS NULL;</pre></div></li><li><p>避免 NULL 影响逻辑运算</p>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM orders WHERE discount IS NULL OR discount > 10;</pre></div></li><li><p>在 JOIN 中考虑 NULL 可能带来的问题</p>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM orders
LEFT JOIN customers ON orders.customer_id = customers.id
WHERE customers.id IS NOT NULL;</pre></div></li><li><p>使用 COALESCE() 处理 NULL</p>
<div class="jb51code"><pre class="brush:sql;">SELECT name, COALESCE(email, '未知') AS email FROM users;</pre></div></li><li><p>正确使用 NOT IN</p>
<div class="jb51code"><pre class="brush:sql;">SELECT * FROM users WHERE age NOT IN (20, 30) OR age IS NULL;</pre></div></li></ul>
<p class="maodian"><a name="_label4"></a></p><h2>总结(重点)</h2>
<ul><li>NULL 代表未知,不是空字符串或 0。</li><li>SQL 采用三值逻辑(TRUE, FALSE, UNKNOWN),导致 NULL 参与运算时可能返回 UNKNOWN。</li><li>NULL 不能用 = 直接比较,而要使用 IS NULL 和 IS NOT NULL。</li><li>NULL 可能影响 JOIN、GROUP BY、ORDER BY、IN/NOT IN 等查询,必须小心处理。</li><li>使用 COALESCE()、IFNULL() 等函数可以避免 NULL 带来的问题。</li></ul>
頁:
[1]