📄 manual_problems.html
字号:
<p>如果你想要一个列总是被当作大小写敏感的方式,声明它为<code>BINARY</code>。见<a HREF="manual_Reference.html#CREATE_TABLE">7.7<code> CREATE TABLE</code>句法</a>。</p>
<p>如果你使用以所谓的big5编码的中文数据,你要使所有的字符列是<code>BINARY</code>,它可行,是因为big5编码字符的排序顺序基于
ASCII代码的顺序。</p>
<p><a NAME="IDX697"></a></p>
<h2><a NAME="Problems_with_NULL" HREF="manual_toc.html#Problems_with_NULL">18.15 <code>NULL</code>值问题</a></h2>
<p><code>NULL</code>值的概念是造成SQL的新手的混淆的普遍原因,他们经常认为<code>NULL</code>是和一个空字符串<code>''</code>的一样的东西。不是这样的!例如,下列语句是完全不同的:</p>
<pre>mysql> INSERT INTO my_table (phone) VALUES (NULL);
mysql> INSERT INTO my_table (phone) VALUES ("");
</pre>
<p>两个语句把值插入到<code>phone</code>列,但是第一个插入一个<code>NULL</code>值而第二个插入一个空字符串。第一个的含义可以认为是“电话号码不知道”,而第二个则可意味着“她没有电话”。
</p>
<p>在SQL中,<code>NULL</code>值在于任何其他值甚至<code>NULL</code>值比较时总是假的(FALSE)。包含<code>NULL</code>的一个表达式总是产生一个<code>NULL</code>值,除非在包含在表达式中的运算符和函数的文档中指出。在下列例子,所有的列返回<code>NULL</code>:</p>
<pre>mysql> SELECT NULL,1+NULL,CONCAT('Invisible',NULL);
</pre>
<p>如果你想要寻找值是<code>NULL</code>的列,你不能使用<code>=NULL</code>测试。下列语句不返回任何行,因为对任何表达式,<code>expr
= NULL</code>是假的:</p>
<pre>mysql> SELECT * FROM my_table WHERE phone = NULL;
</pre>
<p>要想寻找<code>NULL</code>值,你必须使用<code>IS NULL</code>测试。下例显示如何找出<code>NULL</code>电话号码和空的电话号码:</p>
<pre>mysql> SELECT * FROM my_table WHERE phone IS NULL;
mysql> SELECT * FROM my_table WHERE phone = "";
</pre>
<p>在<strong>MySQL</strong>中,就像很多其他的SQL服务器一样,你不能索引可以有<code>NULL</code>值的列。你必须声明这样的列为<code>NOT
NULL</code>,而且,你不能插入<code>NULL</code>到索引的列中。</p>
<p><a NAME="IDX699"></a>当用<code>LOAD DATA INFILE</code>读取数据时,空列用<code>''</code>更新。如果你想要在一个列中有<code>NULL</code>值,你应该在文本文件中使用<code>\N</code>。字面上的词<code>'NULL'</code>也可以在某些情形下使用。见<a HREF="manual_Reference.html#LOAD_DATA">7.16<code> LOAD DATA INFILE</code>句法</a>。</p>
<p>当使用<code>ORDER BY</code>时,首先呈现<code>NULL</code>值。如果你用<code>DESC</code>以降序排序,<code>NULL</code>值最后显示。当使用<code>GROUP
BY</code>时,所有的<code>NULL</code>值被认为是相等的。</p>
<p>为了有助于<code>NULL</code>的处理,你能使用<code>IS NULL</code>和<code>IS
NOT NULL</code>运算符和<code>IFNULL()</code>函数。</p>
<p><a NAME="IDX700"></a>对某些列类型,<code>NULL</code>值被特殊地处理。如果你将<code>NULL</code>插入表的第一个<code>TIMESTAMP</code>列,则插入当前的日期和时间。如果你将<code>NULL</code>插入一个<code>AUTO_INCREMENT</code>列,则插入顺序中的下一个数字。</p>
<p> </p>
<h2><a NAME="Problems_with_alias" HREF="manual_toc.html#Problems_with_alias">18.16 <code>alias</code>问题</a></h2>
<p>你可以在<code>GROUP BY</code>、<code>ORDER BY</code>或在<code>HAVING</code>部分中使用别名引用列。别名也可以用来为列取一个更好点的名字:</p>
<pre>SELECT SQRT(a*b) as rt FROM table_name GROUP BY rt HAVING rt > 0;
SELECT id,COUNT(*) AS cnt FROM table_name GROUP BY id HAVING cnt > 0;
SELECT id AS "Customer identity" FROM table_name;
</pre>
<p>注意,你的 ANSI SQL 不允许你在一个<code>WHERE</code>子句中引用一个别名。这是因为在<code>WHERE</code>代码被执行时,列值还可能没有终结。例如下列查询是<strong>不合法</strong>:</p>
<pre>SELECT id,COUNT(*) AS cnt FROM table_name WHERE cnt > 0 GROUP BY id;
</pre>
<p><code>WHERE</code>语句被执行以确定哪些行应该包括<code>GROUP BY</code>部分中,而<code>HAVING</code>用来决定应该只用结果集合中的哪些行。
</p>
<h2><a NAME="Deleting_from_related_tables" HREF="manual_toc.html#Deleting_from_related_tables">18.17 从关联的表中删除行</a></h2>
<p>因为<strong>MySQL</strong>不支持子选择或在<code>DELETE</code>语句中使用多个表,你应该使用下列方法从2个关联的表中删除行:
<ol>
<li>在主表中基于某个<code>WHERE</code>条件<code>SELECT</code>行。</li>
<li>在主表中基于相同的条件<code>DELETE</code>行。</li>
<li><code>DELETE FROM related_table WHERE related_column IN (selected_rows)</code> </li>
</ol>
<p>如果在<code>related_column</code>查询中的字符的全部数量超过1,048,576(缺省值<code>max_allowed_packet</code>),你应该分成更小的部分并且执行多个<code>DELETE</code>语句。如果<code>related_column</code>是一个索引,你每次只删除100-1000个<code>related_column</code>
id将可能使得<code>DELETE</code>最快。如果<code>related_column</code>不是一个索引,速度与<code>IN</code>子句中参数的数量无关。</p>
<h2><a NAME="No_matching_rows" HREF="manual_toc.html#No_matching_rows">18.18
解决没有匹配行的问题</a></h2>
<p>如果你有一个复杂的查询,涉及多个表,但没有返回任何行,你应该使用下列过程查找你的询问有什么不对:
<ol>
<li><code>EXPLAIN</code>测试查询并且检查你是否能找出显然是错误的一些东西。见<a HREF="manual_Reference.html#EXPLAIN">7.22<code> EXPLAIN</code>句法(得到关于一个<code>SELECT</code>的信息)</a>。</li>
<li>仅选择那些在<code>WHERE</code>子句中使用的字段。 </li>
<li>一次从查询中删除一个表,直到它返回一些行。如果表很大,对查询使用<code>LIMIT
10</code>是一个好主意。 </li>
<li>对应该已经匹配一行的列做一个<code>SELECT</code>,针对从询问中做后被删除的表。</li>
<li>如果你将<code>FLOAT</code>或<code>DOUBLE</code>列与有小数的数字进行比较,你不能使用<code>=</code>!。这个问题在大多数计算机语言是常见的,因为浮点值不是准确的值。<pre>mysql> SELECT * FROM table_name WHERE float_column=3.5;
->
mysql> SELECT * FROM table_name WHERE float_column between 3.45 and 3.55;
</pre>
<p>在大多数情况下,将<code>FLOAT</code>改成一个<code>DOUBLE</code>将修正它!</p>
</li>
<li>如果你仍然不能发现错误是什么,创建一个最小的可运行<code>mysql
test < query.sql</code>的测试来显示你的问题。你可以用<code>mysqldump
--quick database tables > query.sql</code>创建一个测试文件,在一个编辑器编辑文件,删除一些插入行(如果有太多这些语句)并且在文件末尾加入你的选择语句。测试你仍然有问题,可以这样做:<pre>shell> mysqladmin create test2
shell> mysql test2 < query.sql
</pre>
<p>使用<code>mysqlbug</code>的邮寄测试文件到<a HREF="mailto:mysql@lists.mysql.com">mysql@lists.mysql.com</a>。</p>
</li>
</ol>
<h2><a NAME="ALTER_TABLE_problems" HREF="manual_toc.html#ALTER_TABLE_problems">18.19 与<code>ALTER
TABLE</code>有关的问题</a></h2>
<p>如果<code>ALTER TABLE</code>死于这样一个错误:</p>
<pre>Error on rename of './database/name.frm' to './database/B-a.frm' (Errcode: 17)
</pre>
<p>问题可能是<strong>MySQL</strong>在前一个<code>ALTER TABLE</code>中已经崩溃并且留下了一个名为<tt>“A-xxx”</tt>或<tt>“B-xxx”</tt>的老的数据库表。在这种情况下,到<strong>MySQL</strong>数据目录中并删除所有名字以<code>A-</code>或<code>B-</code>开始的文件。(你可以把他们移到别的地方而不是删除他们)。</p>
<p><code>ALTER TABLE</code>工作方式是:
<ul>
<li>以要求的改变创建一个名为<tt>“A-xxx”</tt>的新表。 </li>
<li>从老表把所有行拷贝到<tt>“A-xxx”</tt>。</li>
<li>老表被改名为<tt>“B-xxx”</tt>。 </li>
<li><tt>“A-xxx”</tt>被改名为你的老表的名字。</li>
<li><tt>“B-xxx”</tt>被删除。 </li>
</ul>
<p>如果某些改名操作出错,<strong>MySQL</strong>试图还原改变。如果出错严重(当然,这不应该发生。),<strong>MySQL</strong>可能留下了老表为<tt>“B-xxx”</tt>但是一个简单改名就应该恢复你的数据。</p>
<h2><a NAME="Change_column_order" HREF="manual_toc.html#Change_column_order">18.20
怎样改变一张表中列的顺序</a></h2>
<p>SQL的要点是中抽象应用程序以避免数据存储格式。你应该总是以你想要检索数据的意愿指定顺序。例如:</p>
<pre>SELECT col_name1, col_name2, col_name3 FROM tbl_name;
</pre>
<p>将以<code>col_name1</code>、<code>col_name2</code>、<code>col_name3</code>的顺序返回列,而:</p>
<pre>SELECT col_name1, col_name3, col_name2 FROM tbl_name;
</pre>
<p>将以<code>col_name1</code>、<code>col_name3</code>、<code>col_name2</code>的顺序返回列。</p>
<p>在一个应用程序中,你应该<strong>决不</strong>基于他们的位置使用<code>SELECT
*</code> 检索列,因为被返回的列的顺序永远<strong>不能</strong>保证;对你的数据库的一个简单改变可能导致你的应用程序相当有戏剧性地失败。</p>
<p>不管怎样,如果你想要改变列的顺序,你可以这样做:
<ol>
<li>以正确的列顺序创建一张新表。</li>
<li>执行<code>INSERT INTO new_table SELECT fields-in-new_table-order FROM old_table</code>.
</li>
<li>删除或改名<code>old_table</code>。</li>
<li><code>ALTER TABLE new_table RENAME old_table</code>。</li>
</ol>
<hr>
<p>去<a HREF="manual_Introduction.html">首先</a>, <a HREF="manual_Common_programs.html">先前</a>,
<a HREF="manual_Common_problems.html">下一个</a>, <a HREF="manual_Concept_Index.html">最终</a>部分,<a HREF="manual_toc.html">目录</a>. </p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -