程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> 關於MYSQL數據庫 >> MySQL數據庫常見錯誤問題解答

MySQL數據庫常見錯誤問題解答

編輯:關於MYSQL數據庫

18.2.1 MySQL server has gone away錯誤 
本小節也涉及有關Lost connection to server during query的錯誤。 
對MySQL server has gone away錯誤最常見的原因是服務器超時了並且關閉了連接。缺省地,如果沒有事情發生,服務器在 8個小時後關閉連接。你可在啟動MySQLd時通過設置wait_timeout變量改變時間限制。 
你可以通過執行mysqladmin version並且檢驗正常運行的時間來檢查MySQL還沒死掉。 
如果你有一個腳本,你只須再發出查詢讓客護進行一次自動的重新連接。 
在這種請下,你通常能獲得下列錯誤代碼(你得到的是OS相關的): 
CR_SERVER_GONE_ERROR 客戶不能發送一個問題給服務器。  
CR_SERVER_LOST 當寫服務器時,客戶沒有出錯,但是它沒有得到對問題的一個完整的答案(或任何答案)。  

如果你向服務器發送不正確的或太大的查詢,你也可能得到這些錯誤。如果mysqld得到一個太大或不正常的包,它認為客戶出錯了並關閉連接。如果你需要較大的查詢(例如,如果你正在處理較大的BLOB列),你可以使用-O max_allowed_packet=#選項(缺省1M)啟動mysqld以增加查詢限制。多余的內存按需分配,這樣mysqld只有在你發出較大差詢時或MySQLd必須返回較大的結果行時,才使用更多的內存! 


18.2.2 Can’t connect to [local] MySQL server錯誤 
一個MySQL客戶可以兩種不同的方式連接mysqld服務器:Unix套接字,它通過在文件系統中的一個文件(缺省“/tmp/MySQLd.sock”)進行連接;或TCP/IP,它通過一個端口號連接。Unix套接字比TCP/IP更快,但是只有用在連接同一台計算機上的服務器。如果你不指定主機名或如果你指定特殊的主機名localhost,使用Unix套接字。 
錯誤(2002)Can’t connect to ...通常意味著沒有一個MySQL服務器運行在系統上或當試圖連接MySQLd服務器時,你正在使用一個錯誤的套接字文件或TCP/IP端口。  
由檢查(使用ps)在你的服務器上有一個名為mysqld的進程啟動!如果沒有任何mysqld過程,你應該啟動一個。見4.15.2 啟動MySQL服務器的問題。 
如果一個MySQLd過程正在運行,你可以通過嘗試這些不同的連接來檢查服務器(當然,端口號和套接字路徑名可能在你的安裝中是不同的): 
shell> MySQLadmin version 
shell> MySQLadmin variables 
shell> MySQLadmin -h `hostname` version variables 
shell> MySQLadmin -h `hostname` --port=3306 version 
shell> MySQLadmin -h ’ip for your host’ version 
shell> mysqladmin --socket=/tmp/MySQL.sock version 

注意hostname命令使用反引號“`”而非正引號“’”;這些導致hostname輸出(即,當前主機名)被代替進MySQLadmin命令中。 
這是可能造成Can’t connect to local MySQL server錯誤的一些原因:  
MySQLd不在運行。  
你正在使用MIT-pthreads的一個系統上運行。如果正在運行在一個沒有原生線程的系統上,mysqld使用 MIT-pthreads 軟件包。見4.2 由MySQL支持的操作系統。然而,MIT-pthreads不支持Unix套接字,因此當與服務器連接時,在這樣一個系統上,你總是必須明確地指定主機名。試試使用這個命令檢查到服務器的連接: 
shell> MySQLadmin -h `hostname` version 

某人刪除了mysqld使用的Unix套接字(缺省“/tmp/mysqld.sock”)。你可能有一個cron任務刪除了MySQL套接字(例如,一個把舊文件從“/tmp”目錄中刪除的任務)。你總是可以運行mysqladmin version並且檢查mysqladmin正在試圖使用的套接字確實存在。在這種情況下,修復方法是刪除cron任務而不刪除“mysqld.sock 或將套接字放在其他地方。你能用這個命令在MySQL配置時指定一個不同的套接字地點: 
shell> ./configure --with-unix-socket-path=/path/to/socket 

你也可以使用--socket=/path/to/socket選項啟動safe_mysqld和在啟動你的MySQL客戶前設置環境變量MYSQL_UNIX_PORT為套接字路徑名。你可用--socket=/path/to/socket選項啟動mysqld服務器。如果你改變了服務器的套接字路徑名,你也必須通知MySQL客戶關於新路徑的情況。你可以通過設置環境變量MySQL_UNIX_PORT為套接字路徑名或由提供套接字路徑名作為客戶的參數做到。你可用這個命令測試套接字: 
shell> MySQLadmin --socket=/path/to/socket version 

你正在使用 Linux和線程已經死了(核心傾倒了)。在這種情況中,你必須殺死其它mysqld線程(例如在啟動一個新的MySQL服務器之前,可以用mysql_zap腳本)。見18.1 如果MySQL總是崩潰怎麼辦。  
如果你得到錯誤Can’t connect to MySQL server on some_hostname,你可以嘗試下列步驟找出問題是什麼:  
通過執行telnet your-host-name tcp-ip-port-number並且按幾次回車來檢查服務器是否正常運行。如果有一個MySQL運行在這個端口上,你應該得到一個包含正在運行的MySQL服務器的版本號的應答。如果你得到類似於telnet: Unable to connect to remote host: Connection refused的一個錯誤,那麼沒有服務器在使用的端口上運行。  
嘗試連接本地機器上的mysqld守護進程,並用mysqladmin variables檢查MySQLd被配置使用的TCP/IP端口(變量port)。  
檢查你的MySQLd服務器沒有用--skip-networking選項啟動。  


18.2.3 Host ’...’ is blocked錯誤 
如果你得到象這樣的一個錯誤: 
Host ’hostname’ is blocked because of many connection errors. 
Unblock with ’MySQLadmin flush-hosts’ 

這意味著,mysqld已經得到了大量(max_connect_errors)的主機’hostname’的在中途被中斷了的連接請求。在max_connect_errors次失敗請求後,mysqld認定出錯了(象來字一個黑客的攻擊),並且阻止該站點進一步的連接,直到某人執行命令MySQLadmin flush-hosts。 
缺省地,MySQLd在10個連接錯誤後阻塞一台主機。你可以通過象這樣啟動服務器很容易地調整它: 
shell> safe_MySQLd -O max_connect_errors=10000 & 

注意,對給定的主機,如果得到這條錯誤消息,你應該首先檢查該主機的TCP/IP連接有沒有問題。如果你的TCP/IP連接不在運行,增加max_connect_errors變量的值對你也不會有幫助! 


18.2.4 Too many connections錯誤 
如果在你試土連接MySQL時,你得到錯誤Too many connections,這意味著已經有max_connections個客戶連接了MySQLd服務器。 
如果你需要比缺省(100)更多的連接,那麼你應該重啟MySQLd,用更大的 max_connections 變量值。 
注意,MySQLd實際上允許(max_connections+1)個客戶連接。最後一個連接是為一個用Process權限的用戶保留的。通過不把這個權限給一般用戶(他們不應該需要它),有這個權限一個管理員可以登錄並且使用SHOW PROCESSLIST找出什麼可能出錯。見7.21 SHOW句法(得到表,列的信息)。 
18.2.5 Out of memory錯誤 
如果你發出查詢並且得到類似於下面的錯誤:  
MySQL: Out of memory at line 42, ’malloc.c’ 
MySQL: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k) 
ERROR 2008: MySQL clIEnt ran out of memory 

注意,錯誤指向了MySQL客戶MySQL。這個錯誤的原因很簡單,客戶沒有足夠的內存存儲全部結果。 
為了修正這個問題,首先檢查你的查詢是否正確。它應該返回這麼多的行,這合理嗎?如果是這樣,你可以使用mysql --quick,它使用MySQL_use_result()檢索結果集合。這將較少的負擔放在了客戶端(只是服務器更多)。 


18.2.6 Packet too large錯誤 
當一個MySQL客戶或MySQLd服務器得到一個比max_allowed_packet個字節長的包,它發出一個Packet too large錯誤並終止連接。 
如果你正在使用mysql客戶,你可以通過用MySQL --set-variable=max_allowed_packet=8M指定一個更大的緩沖區來啟動客戶程序。 
如果你正在使用不允許你指定最大包大小的其他客戶(例如 DBI),你需要在你啟動服務器時設置包大小。你可以使用MySQLd的命令行選項設置max_allowed_packet為一個更大的尺寸。例如,如果你正期望將一個全長的BLOB存入一張表中,你將需要用--set-variable=max_allowed_packet=24M選項來啟動服務器。 
  


18.2.7 The table is full錯誤 
這個錯誤發生在內存臨時表變得比tmp_table_size字節大時。為了避免這個問題,你可以使用MySQLd的-O tmp_table_size=#選項來增加臨時表的大小,或在你發出有疑問的查詢之前使用SQL選項SQL_BIG_TABLES。見7.25 SET OPTION句法。 
你也可以使用--big-tables選項啟動MySQLd。這與為所有查詢使用SQL_BIG_TABLES完全相同。
18.2.8 Commands out of sync in clIEnt錯誤 
如果你在你的客戶代碼中得到Commands out of sync; You can’t run this command now,你正在以錯誤的次序調用客戶函數! 
這可能發生,例如,如果你正在使用mysql_use_result()並且在你已經調用了mysql_free_result()之前試圖執行新查詢。如果你在mysql_use_result()或MySQL_store_result()之間試圖執行返回數據的2個查詢,它也可能發生。 


18.2.9 Ignoring user錯誤 
如果你得到下列錯誤:  
Found wrong passWord for user: ’some_user@some_host’; Ignoring user  
這意味著在MySQLd啟動時或在它再次裝載權限表時,它在user表中找到了一個有一個無效口令的條目。結果,條目簡單地被權限系統忽略。 
可能導致這個問題的原因和修正:  
你可能正在運行一個有一個老的user表的新版本mysqld。你可以通過執行mysqlshow MySQL user看看口令字段是否少於 16個字符來檢查它。如果是這樣,你可以通過運行scripts/add_long_passWord腳本改正這種情況。  
用戶有一個老式的口令(8個字符長)並且你沒使用--old-protocol選項啟動mysqld。用一個新口令更新在user表中的用戶或用--old-protocol重啟MySQLd。  
你沒有使用PASSWord()函數在在user表中指定了一個口令。使用MySQL以一個新口令更新在user表中的用戶。確保使用PASSWord()函數: 
MySQL> update user set password=PASSWORD(’your passWord’) 
           where user=’XXX’; 


18.2.10 Table ’xxx’ doesn’t exist錯誤 
如果你得到錯誤Table ’xxx’ doesn’t exist或Can’t find file: ’xxx’ (errno: 2),這意味著在當前數據庫中沒有名為xxx的表存在。 
注意,因為MySQL使用目錄和文件存儲數據庫和表,數據庫和表名件是區分大小寫的!(在Win32上,數據庫和表名不是區分大小寫的,但是在查詢中對所有表的引用必須使用相同的大小寫!) 
你可以用SHOW TABLES檢查你在當前數據庫中有哪個表。見7.21 SHOW句法(得到表、列的信息)。  
18.3 MySQL怎樣處理一個溢出的磁盤 
當出現一個磁盤溢出的情況時,MySQL做下列事情:  
它每分鐘檢查一次看是否有足夠空間寫入當前行。如果有足夠的空間,它繼續好像發生什麼事情。  
每6分鐘它將有關磁盤溢出的警告寫入日志文件。  
為了緩和這個問題,你可以采取下列行動:  
繼續,你只需釋放足夠的空閒磁盤空間以便插入所有記錄。  
放棄線程,你必須發一個MySQLadmin kill到線程。在下一次檢查磁盤時,線程將被放棄(在1分鐘內)。  
注意,其他線程可能正在等待引起“磁盤溢出”條件的表。如果你有幾個“鎖定的”的線程,殺死正在等待磁盤溢出條件的那個線程將允許其他線程繼續。  


18.4 如何從一個文本文件運行SQL命令 
一般地,MySQL客戶被交互性地使用,象這樣: 
shell> MySQL database 
然而,也可以把你的SQL命令放在一個文件中並且告訴mysql從該文件讀取其輸入。要想這樣做,創造一個文本文件“text_file”,它包含你想要執行的命令。然後如下那樣調用MySQL: 
shell> MySQL database < text_file 

你也能啟動有一個USE db_name語句的文本文件。在這種情況下,在命令行上指定數據庫名是不必要的: 
shell> MySQL < text_file 

見12.1 不同的MySQL程序概述。  


18.5 MySQL在哪兒存儲臨時文件 
MySQL使用TMPDIR環境變量的值作為存儲臨時文件的目錄的路徑名。如果你沒有設置TMPDIR,MySQL使用系統缺省值,它通常是“/tmp”或“/usr/tmp”。如果包含你的臨時文件目錄的文件系統太小,你應該編輯safe_mysqld設定TMPDIR指向你有足夠空間的一個文件系統!你也可以使用MySQLd的--tmpdir選項目設置臨時目錄。 
MySQL以“隱含文件”創建所有臨時文件。這保證了如果MySQLd被終止,臨時文件也將被刪除。使用隱含文件的缺點是你將看不到一個大的臨時文件填滿了臨時文件目錄所在的文件系統。 
當排序(ORDER BY或GROUP BY)時,MySQL通常使用一個或兩個臨時文件。最大磁盤空間需求是: 
(存儲東西的長度 + sizeof (數據庫指針)) 
* 匹配的行數 
* 2 

sizeof(數據庫指針)通常是4,但是在未來對確實很大的表可能增加。 
對一些SELECT查詢,MySQL也創建臨時SQL表。這些沒被隱含且有“SQL_*”格式的名字。 
ALTER TABLE和OPTIMIZE TABLE在原數據庫表的同一個目錄中創建一張臨時表。 


18.6 怎樣保護“/tmp/MySQL.sock ”不被刪除 
如果你有這個問題,事實上任何人可以刪除MySQL通訊套接字“/tmp/MySQL.sock”,在Unix的大多數版本上,你能通過為其設置sticky(t)位來保護你的“/tmp”文件系統。作為root登錄並且做下列事情: 
shell> chmod +t /tmp 

這將保護你的“/tmp”文件系統使得文件僅能由他們的所有者或超級用戶(root)刪除。
你能執行ls -ld /tmp檢查sticky位是否被設置,如果最後一位許可位是t,該位被設置了。 


18.7 Access denIEd錯誤 
見6.6 權限系統如何工作。並且特別要看6.13 引起Access denIEd錯誤的原因。  


18.8 怎樣作為一個一般用戶運行MySQL 
MySQL服務器mysqld能被任何用戶啟動並運行。為了將MySQLd改由Unix用戶user_name來運行,你必須做下列事情:  
如果它正在運行,停止服務器(使用MySQLadmin shutdown)。  
改變數據庫目錄和文件以便user_name有權限讀和寫文件(你可能需要作為Unix的root用戶才能做到): 
shell> chown -R user_name /path/to/MySQL/datadir 

如果在MySQL數據目錄中的目錄或文件是符號鏈接,你也將需要順著那些鏈接並改變他們指向的目錄和文件。chown -R不能跟隨符號鏈接。 
以user_name用戶啟動服務器,或如果你正在使用MySQL 3.22或以後版本,以Unix root用戶啟動mysqld並使用--user=user_name選項,MySQLd將在接受任何連接之前切換到以Unix user_name用戶運行。  
如果在系統被重新啟動時,你使用mysql.server腳本啟動mysqld,你應該編輯mysql.server用su以用戶user_name運行mysqld,或使用--user選項調用mysqld。(不改變safe_MySQLd是必要的。)  
現在,你的mysqld進程應該正在作為Unix用戶user_name運行,並運行完好。盡管有一件事情沒有變化:權限表的內容。缺省 地(就在運行了腳本mysql_install_db安裝的權限表後),MySQL用戶root是唯一有存取MySQL數據庫或創建或拋棄數據庫權限的用戶。除非你改變了那些權限,否則他們仍然保持。當你作為一個Unix用戶而不是root登錄時,這不應該阻止你作為MySQL root用戶來存取MySQL;只要為客戶程序指定-u root的選項。 
注意通過在命令行上提供-u root,作為root存取MySQL,與作為Unix root用戶或其他Unix用戶運行MySQL沒有關系。MySQL的存取權限和用戶名與Unix用戶名字是完全分開的。唯一與Unix用戶名有關的是,如果當你調用一個客戶程序時,你不提供一個-u選項,客戶將試圖使用你的Unix登錄名作為你的MySQL用戶名進行連接。 
如果你的Unix機器本身不安全,你可能應該至少在存取表中為MySQL root用戶放上一個口令。否則,在那台機器上有一個帳號的任何用戶能運行MySQL -u root db_name並且做他喜歡做的任何事情。
18.9 怎樣重新設置一個忘記的口令 
如果你忘記了MySQL的root用戶的口令,你可以用下列過程恢復它。  
通過發送一個kill(不是kill -9)到mysqld服務器來關閉mysqld服務器。pid 被保存在一個.pid文件中,通常在MySQL數據庫目錄中: 
kill `cat /MySQL-data-directory/hostname.pid` 

你必須是一個UNIX root用戶或運行服務器的相同用戶做這個。 
使用--skip-grant-tables選項重啟MySQLd。  
用mysql -h hostname mysql連接mysqld服務器並且用一條GRANT命令改變口令。見7.26 GRANT和REVOKE句法。你也可以用MySQLadmin -h hostname -u user password ’new passWord’ 進行。  
用MySQLadmin -h hostname flush-privileges或用SQL命令FLUSH PRIVILEGES來裝載權限表。  



18.10 文件許可權限問題 
如果你有與文件許可有關的問題,例如,如果當你創建一張表時,MySQL發出下列錯誤消息:  
ERROR: Can’t find file: ’path/with/filename.frm’ (Errcode: 13)  

那麼可能是在mysqld啟動時,環境變量UMASK可能設置不正確。缺省的umask值是0660。你可以如下啟動safe_MySQLd改變其行為: 
shell> UMASK=384  # = 600 in octal 
shell> export UMASK 
shell> /path/to/safe_MySQLd & 


18.11 文件沒找到 
如果你從MySQL得到ERROR ’...’ not found (errno: 23), Can’t open file: ... (errno: 24)或任何其他有errno 23或errno 24的錯誤,它意味著,你沒有為MySQL分配足夠的文件描述符。你能使用perror實用程序得到錯誤號含義是什麼的描述: 
shell> perror 23 
File table overflow 
shell> perror 24 
Too many open files 

這裡的問題是mysqld正在試圖同時保持打開太多的文件。你也可以告訴mysqld一次不打開那麼多的文件,或增加mysqld可得到的文件描述符數量。為了告訴mysqld一次保持打開更少的文件,你可以通過使用safe_MySQLd的-O table_cache=32選項(缺省值是64)使表緩沖更小。減小max_connections值也將減少打開文件的數量(缺省值是90)。 
要想改變mysqld可用的文件描述符數量,修改safe_mysqld腳本。腳本中有一條注釋了的行ulimit -n 256。你可以刪除’#’字符來去掉該行的注釋,並且改變數字256改變為MySQLd可用的文件描述符的數量。 
ulimit能增加文件描述符的數量,但是只能到操作系統強加的限制。如果你需要增加每個進程可用的文件描述符數量的OS限制,參見你的操作系統文檔。注意,如果你運行tcsh外殼,ulimit將不工作!當你請求當前限制時,tcsh也將報告不正確的值!在這種情況下,你應該用sh啟動safe_MySQLd! 


18.12 使用DATE列的問題 
一個DATE值的格式是’YYYY-MM-DD’。根據ANSI SQL,不允許其他格式。你應該在UPDATE表達式和SELECT語句的WHERE子句中使用這個格式。例如: 
MySQL> SELECT * FROM tbl_name WHERE date >= ’1997-05-05’; 

為了方便,如果日期用在數字上下文,MySQL自動變換一個日期到一個數字(並且反過來也如此)。當更新時和將一個日期與TIMESTAMP、DATE或DATETIME列比較的一個WHERE子句中,也是足夠靈活以允許一種“寬松”的字符串格式。(寬松格式意味著任何標點字符用作在部件之間的分割符。例如,’1998-08-15’和’1998#08#15’是等價的。)MySQL也能變換不包含分割符的一個字符串(例如 ’19980815’),如果它作為一個日期說得通。特殊日期’0000-00-00’可以作為’0000-00-00’被存儲和檢索。當通過MyODBC使用一個’0000-00-00’日期時,在MyODBC 2.50.12和以上版本,它將自動被轉換為NULL,因為ODBC不能處理這種日期。 
因為MySQL實行了上述的變換,下列語句可以工作: 
MySQL> INSERT INTO tbl_name (idate) VALUES (19970505); 
MySQL> INSERT INTO tbl_name (idate) VALUES (’19970505’); 
MySQL> INSERT INTO tbl_name (idate) VALUES (’97-05-05’); 
MySQL> INSERT INTO tbl_name (idate) VALUES (’1997.05.05’); 
MySQL> INSERT INTO tbl_name (idate) VALUES (’1997 05 05’); 
MySQL> INSERT INTO tbl_name (idate) VALUES (’0000-00-00’); 

MySQL> SELECT idate FROM tbl_name WHERE idate >= ’1997-05-05’; 
MySQL> SELECT idate FROM tbl_name WHERE idate >= 19970505; 
MySQL> SELECT mod(idate,100) FROM tbl_name WHERE idate >= 19970505; 
MySQL> SELECT idate FROM tbl_name WHERE idate >= ’19970505’; 

然而,下列將不工作:  
MySQL> SELECT idate FROM tbl_name WHERE STRCMP(idate,’19970505’)=0; 

STRCMP()是字符串函數,因此它將idate轉換為一個字符串並且實施字符串比較。它不將’19970505’轉換為一個日期並實施日期比較。 
注意,MySQL不檢查日期是否正確。如果你存儲一個不正確的日期,例如’1998-2-31’,錯誤的日期將被存儲。如果日期不能被變換到任何合理的值,在DATE字段中存儲一個0。這主要是一個速度問題並且我們認為檢查日期是應用程序的責任,而不服務器。 


18.13 時區問題 
如果你有一個問題,SELECT NOW()以GMT時間返回值而不是你的本地時間,你必須設定TZ環境變量為你的當前時區。這應該在服務器運行的環境進行,例如在safe_mysqld或MySQL.server中。 


18.14 在搜索中的大小寫敏感性 
缺省地,MySQL搜索是大小寫不敏感的(盡管有一些字符集從來不是忽略大小寫的,例如捷克語)。這意味著,如果你用col_name LIKE ’a%’搜尋,你將得到所有以A或a開始的列值。如果你想要使這個搜索大小寫敏感,使用象INDEX(col_name, "A")=0檢查一個前綴。或如果列值必須確切是"A",使用STRCMP(col_name, "A") = 0。 
簡單的比較操作(>=、>、= 、< 、<=、排序和聚合)是基於每個字符的“排序值”。有同樣排序值的字符(象E,e和’e)被視為相同的字符! 
LIKE比較在每個字符的大寫值上進行(E==e 但是E<>’e)。 
如果你想要一個列總是被當作大小寫敏感的方式,聲明它為BINARY。見7.7 CREATE TABLE句法。 
如果你使用以所謂的big5編碼的中文數據,你要使所有的字符列是BINARY,它可行,是因為big5編碼字符的排序順序基於 ASCII代碼的順序。 


18.15 NULL值問題 
NULL值的概念是造成SQL的新手的混淆的普遍原因,他們經常認為NULL是和一個空字符串’’的一樣的東西。不是這樣的!例如,下列語句是完全不同的: 
MySQL> INSERT INTO my_table (phone) VALUES (NULL); 
MySQL> INSERT INTO my_table (phone) VALUES (""); 

兩個語句把值插入到phone列,但是第一個插入一個NULL值而第二個插入一個空字符串。第一個的含義可以認為是“電話號碼不知道”,而第二個則可意味著“她沒有電話”。  
在SQL中,NULL值在於任何其他值甚至NULL值比較時總是假的(FALSE)。包含NULL的一個表達式總是產生一個NULL值,除非在包含在表達式中的運算符和函數的文檔中指出。在下列例子,所有的列返回NULL: 
MySQL> SELECT NULL,1+NULL,CONCAT(’Invisible’,NULL); 

如果你想要尋找值是NULL的列,你不能使用=NULL測試。下列語句不返回任何行,因為對任何表達式,expr = NULL是假的: 
MySQL> SELECT * FROM my_table WHERE phone = NULL; 

要想尋找NULL值,你必須使用IS NULL測試。下例顯示如何找出NULL電話號碼和空的電話號碼: 
MySQL> SELECT * FROM my_table WHERE phone IS NULL; 
MySQL> SELECT * FROM my_table WHERE phone = ""; 

在MySQL中,就像很多其他的SQL服務器一樣,你不能索引可以有NULL值的列。你必須聲明這樣的列為NOT NULL,而且,你不能插入NULL到索引的列中。當用LOAD DATA INFILE讀取數據時,空列用’’更新。如果你想要在一個列中有NULL值,你應該在文本文件中使用\N。字面詞’NULL’也可以在某些情形下使用。見7.16 LOAD DATA INFILE句法。當使用ORDER BY時,首先呈現NULL值。如果你用DESC以降序排序,NULL值最後顯示。當使用GROUP BY時,所有的NULL值被認為是相等的。為了有助於NULL的處理,你能使用IS NULL和IS NOT NULL運算符和IFNULL()函數。 
對某些列類型,NULL值被特殊地處理。如果你將NULL插入表的第一個TIMESTAMP列,則插入當前的日期和時間。如果你將NULL插入一個AUTO_INCREMENT列,則插入順序中的下一個數字。
18.16 alias問題  
你可以在GROUP BY、ORDER BY或在HAVING部分中使用別名引用列。別名也可以用來為列取一個更好點的名字:  
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;  

注意,你的 ANSI SQL 不允許你在一個WHERE子句中引用一個別名。這是因為在WHERE代碼被執行時,列值還可能沒有終結。例如下列查詢是不合法:SELECT id,COUNT(*) AS cnt FROM table_name WHERE cnt > 0 GROUP BY id;  

WHERE語句被執行以確定哪些行應該包括GROUP BY部分中,而HAVING用來決定應該只用結果集合中的哪些行。   


18.17 從關聯的表中刪除行  
因為MySQL不支持子選擇或在DELETE語句中使用多個表,你應該使用下列方法從2個關聯的表中刪除行:   
在主表中基於某個WHERE條件SELECT行。   
在主表中基於相同的條件DELETE行。   
DELETE FROM related_table WHERE related_column IN (selected_rows)   
如果在related_column查詢中的字符的全部數量超過1,048,576(缺省值max_allowed_packet),你應該分成更小的部分並且執行多個DELETE語句。如果related_column是一個索引,你每次只刪除100-1000個related_column id將可能使得DELETE最快。如果related_column不是一個索引,速度與IN子句中參數的數量無關。  


18.18 解決沒有匹配行的問題  
如果你有一個復雜的查詢,涉及多個表,但沒有返回任何行,你應該使用下列過程查找你的詢問有什麼不對:   
EXPLAIN測試查詢並且檢查你是否能找出顯然是錯誤的一些東西。見7.22 EXPLAIN句法(得到關於一個SELECT的信息)。   
僅選擇那些在WHERE子句中使用的字段。   
一次從查詢中刪除一個表,直到它返回一些行。如果表很大,對查詢使用LIMIT 10是一個好主意。   
對應該已經匹配一行的列做一個SELECT,針對從詢問中做後被刪除的表。   
如果你將FLOAT或DOUBLE列與有小數的數字進行比較,你不能使用=!。這個問題在大多數計算機語言是常見的,因為浮點值不是准確的值。  
MySQL> SELECT * FROM table_name WHERE float_column=3.5;  
   ->  
MySQL> SELECT * FROM table_name WHERE float_column between 3.45 and 3.55;  

在大多數情況下,將FLOAT改成一個DOUBLE將修正它!  
如果你仍然不能發現錯誤是什麼,創建一個最小的可運行mysql test < query.sql的測試來顯示你的問題。你可以用MySQLdump --quick database tables > query.sql創建一個測試文件,在一個編輯器編輯文件,刪除一些插入行(如果有太多這些語句)並且在文件末尾加入你的選擇語句。測試你仍然有問題,可以這樣做:  
shell> MySQLadmin create test2  
shell> MySQL test2 < query.sql  

使用mysqlbug的郵寄測試文件到[email protected]。  


18.19 與ALTER TABLE有關的問題  
如果ALTER TABLE死於這樣一個錯誤:  
Error on rename of ’./database/name.frm’ to ’./database/B-a.frm’ (Errcode: 17)  

問題可能是MySQL在前一個ALTER TABLE中已經崩潰並且留下了一個名為“A-xxx”或“B-xxx”的老的數據庫表。在這種情況下,到MySQL數據目錄中並刪除所有名字以A-或B-開始的文件。(你可以把他們移到別的地方而不是刪除他們)。  
ALTER TABLE工作方式是:   
以要求的改變創建一個名為“A-xxx”的新表。   
從老表把所有行拷貝到“A-xxx”。   
老表被改名為“B-xxx”。   
“A-xxx”被改名為你的老表的名字。   
“B-xxx”被刪除。   
如果某些改名操作出錯,MySQL試圖還原改變。如果出錯嚴重(當然,這不應該發生。),MySQL可能留下了老表為“B-xxx”但是一個簡單改名就應該恢復你的數據。  


18.20 怎樣改變一張表中列的順序  
SQL的要點是中抽象應用程序以避免數據存儲格式。你應該總是以你想要檢索數據的意願指定順序。例如:  
SELECT col_name1, col_name2, col_name3 FROM tbl_name;  

將以col_name1、col_name2、col_name3的順序返回列,而:  
SELECT col_name1, col_name3, col_name2 FROM tbl_name;   

將以col_name1、col_name3、col_name2的順序返回列。  
在一個應用程序中,你應該決不基於他們的位置使用SELECT * 檢索列,因為被返回的列的順序永遠不能保證;對你的數據庫的一個簡單改變可能導致你的應用程序相當有戲劇性地失敗。  
不管怎樣,如果你想要改變列的順序,你可以這樣做:   
以正確的列順序創建一張新表。   
執行INSERT INTO new_table SELECT fIElds-in-new_table-order FROM old_table.  
刪除或改名old_table。   
ALTER TABLE new_table RENAME old_table。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved