MySQL 4.1.0 中文參考手冊 --- 6.4 資料操縱:SELECT, INSERT, UPDATE, DELETE (轉)

gugu99發表於2008-01-27
MySQL 4.1.0 中文參考手冊 --- 6.4 資料操縱:SELECT, INSERT, UPDATE, DELETE (轉)[@more@] 4.1.0 中文參考手冊"> words" content="MySQL,4.1.0,Shuixin13,MySQL 4.1.0,中文,中文參考手冊,犬犬(心帆)"> CSS rel=STYLESHEET>

MySQL Reference Manual for version 4.1.0-alpha.


6.4 資料操縱:, INSERT, UPDATE, DELETE

6.4.1 SELECT 句法

SELECT [STRAIGHT_JOIN] [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] [HIGH_PRIORITY] [DISTINCT | DISTINCTROW | ALL] select_expression,... [INTO {OUTFILE | DUMPFILE} 'file_name' export_options] [FROM table_references [WHERE where_definition] [GROUP BY {unsigned_integer | col_name | formula} [ASC | DESC], ...] [HAVING where_definition] [ORDER BY {unsigned_integer | col_name | formula} [ASC | DESC] ,...] [LIMIT [offset,] rows | rows OFFSET offset] [PROCEDURE procedure_name(argument_list)] [FOR UPDATE | LOCK IN SHARE MODE]]


SELECT 用於檢索從一個或多個表中選取出的行。select_expression 表示你希望檢索的列。 SELECT 也可以被用於檢索沒有引用任何表的計算列。例如:

mysql> SELECT 1 + 1; -> 2


所有使用的關鍵詞必須嚴格以上面所顯示的次序被給出。舉例來說,一個 HAVING 子句必須出現在 GROUP BY 子句後,在 ORDER BY 字句之前。

  • 一個 SELECT 可以使用 AS 指定一個別名。別名可以當作表示式的列名,用於 ORDER BYHAVING 子句中。例如:

    mysql> SELECT CONCAT(last_name,', ',first_name) AS full_name FROM mytable ORDER BY full_name;

    
    
  • 在一個 WHERE 子句中使用一個列別名是不允許的,因為,當 WHERE 子句被時,列值可能還沒有被計算確定。檢視章節 。

  • FROM table_references 子句表示從哪個表中檢索記錄行。如果你命名超過超過一個表,並執行一個 join。對於 join 句法的資訊,檢視章節 。對於每個引用的表,你可以順便指定一個別名。

    table_name [[AS] alias] [[USE INDEX (key_list)] | [IGNORE INDEX (key_list)] | FORCE INDEX (key_list)]]

    到 MySQL 3.23.12 時,當 MySQL 在從一個表中檢索資訊時,你可以提示它選擇了哪一個。如果 EXPLAIN 顯示 MySQL 使用了可能的索引列表中錯誤的索引,這個特性將是很有用的。透過指定 USE INDEX (key_list),你可以告訴 MySQL 使用可能的索引中最合適的一個索引在表中查詢記錄行。可選的二選一句法 IGNORE INDEX (key_list) 可被用於告訴 MySQL 不使用特定的索引。在 MySQL 4.0.9 中,你也可以使用 FORCE INDEX。這個有點像 USE INDEX (key_list),但是有了這個附加物,一個表的掃描被採用時,將會有非常大的開銷。換句法說,如果沒有方法使用給定的索引在表中尋找記錄行,這時表掃描才會被使用。 USE/IGNORE/FORCE KEY 分別是 USE/IGNORE/FORCE INDEX 的同義詞。
    

  • 你可以以 tbl_name (在當前的中) 引用一張表,或以 name.tbl_name 明確地指定其個資料。你要以以 col_nametbl_name.col_namedb_name.tbl_name.col_name 引用一個列。 你不需要在一個 SELECT 語句中引用的列前指定 tbl_namedb_name.tbl_name 字首,除非引用列存在二義性。檢視章節 ,對於有歧義的列引用需要更加顯式的列引用格式。

  • 一個表的引用可以使用 tbl_name [AS] alias_name 給以別名:

    mysql> SELECT t1.name, t2.salary FROM employee AS t1, info AS t2 -> WHERE t1.name = t2.name; mysql> SELECT t1.name, t2.salary FROM employee t1, info t2 -> WHERE t1.name = t2.name;

    
    
  • 選取出來用於輸出的列可以在 ORDER BYGROUP BY 子句中使用列名、列的別名或列的位置來引用。列的位置從 1 開始:

    mysql> SELECT college, region, seed FROM tournament -> ORDER BY region, seed; mysql> SELECT college, region AS r, seed AS s FROM tournament -> ORDER BY r, s; mysql> SELECT college, region, seed FROM tournament -> ORDER BY 2, 3;

    為了以倒序排序,可以在 ORDER BY 子句中用於排序的列名後新增一個 DESC (遞減 descending)關鍵詞。預設為升序排序;這也可以透過使用 ASC 關鍵詞明確指定。
    

  • WHERE 子句中可以使用 MySQL 支援的任何。檢視章節 。

  • HAVING 子句可以引用任何列或在 select_expression 中命名的別名。它在最後被執行,僅僅就在專案被送到客戶端之前,不進行任何。所以不要對應該放在 WHERE 子句中的專案使用 HAVING。舉例來說,不要寫成這樣:

    mysql> SELECT col_name FROM tbl_name HAVING col_name > 0;

    用這個代替:
    

    mysql> SELECT col_name FROM tbl_name WHERE col_name > 0;

    在 MySQL 3.22.5 或以後的版本中,你也可以這下面的形式書寫一個查詢:
    

    mysql> SELECT user,MAX(salary) FROM users -> GROUP BY user HAVING MAX(salary)>10;

    在較早的 MySQL 版本中,你可能需要用下面的代替了:
    

    mysql> SELECT user,MAX(salary) AS sum FROM users -> group by user HAVING sum>10;

    
    
  • DISTINCTDISTINCTROWALL 選項指定重複的記錄行是否被返回。預設為 (ALL),返回所有匹配的記錄行。DISTINCTDISTINCTROW 是同義詞,它指定結果集重複的記錄行被排除。

  • 所有以 SQL_ 開頭、STRAIGHT_JOINHIGH_PRIORITY 的選項是 MySQL 對 ANSI SQL 的擴充套件。

  • HIGH_PRIORITY 將給 SELECT 語句比一個表有更高的優先順序。你只應該對非常快的或需要立即返回的查詢使用它。 如果一個表已被讀鎖定,甚至是有一個更新語句正在等待表的釋放,一個 SELECT HIGH_PRIORITY 查詢也將會執行。

  • SQL_BIG_RESULT 可以與 GROUP BYDISTINCT 一同使用,以告訴最佳化器結果集將有許多記錄行。在這種情況下,如果需要,MySQL 將直接使用基於的臨時表。同樣的,在這種情況下,MySQL 更願意以 GROUP BY 上的一個鍵進行排序而不是建立一個臨時表。

  • SQL_BUFFER_RESULT 將強制把結果放入一個臨時表。這將有助於 MySQL 儘早地釋放表和有助於將大的結果集傳送到客戶端。

  • SQL_SMALL_RESULT, 一個 MySQL 特有的選項,可以與 GROUP BYDISTINCT 一同使用,以告訴最佳化器結果集將會很小。在這種情況下,MySQL 將使用的臨時表結果表,而不是使用排序。在 MySQL 3.23 中,這通常是不需要的。

  • SQL_CALC_FOUND_ROWS (版本 4.0.0 和更新的) 告訴 MySQL 計算在不考慮 LIMIT 子句時結果集中將有多少行記錄。然後使用 SELECT FOUND_ROWS() 可以檢索到記錄行的數目。檢視章節 。請注意,在早於 4.1.0 的版本中,LIMIT 0 是不工作的,它將被最佳化為立即返回(結果集的記錄數為 0)。檢視章節 。

  • 如果你使用了 QUERY_CACHE_TYPE=2 (DEMAND),SQL_CACHE 告訴 MySQL 將儲存查詢結果放入查詢快取記憶體內。檢視章節 。

  • SQL_NO_CACHE 告訴 MySQL 不允許將查詢結果儲存到查詢快取內。檢視章節 。

  • 如果使用了 GROUP BY,輸出記錄將會依照 GROUP BY 列進行排序,就好像你對所有 GROUP BY 中的所有欄位使用了 ORDER BY。MySQL 擴充套件了 GROUP BY 的用法,所以你也可以在 GROUP BY 中指定 ASCDESC

    SELECT a,COUNT(b) FROM test_table GROUP BY a DESC

    
    
  • MySQL 擴充套件了的 GROUP BY 用法允許你選取沒有在 GROUP BY 子句中提及的欄位。如果你的查詢沒有得到你所期望的結果,請檢視 GROUP BY 中的描述。檢視章節 。

  • STRAIGHT_JOIN 強制最佳化器以表在 FROM 子句中列出的順序聯結。如果最佳化器以一個非最佳化的次序聯結各表,你可以使用它來加速一個查詢。檢視章節 。

  • LIMIT 子句可以被用於強制 SELECT 語句返回指定的記錄數。LIMIT 接受一個或兩個數字引數。引數必須是一個整數常量。如果給定兩個引數,第一個引數指定第一個返回記錄行的偏移量,第二個引數指定返回記錄行的最大數目。初始記錄行的偏移量是 0(而不是 1):為了與 PostgreSQL 相容,MySQL 也支援句法: LIMIT # OFFSET #

    mysql> SELECT * FROM table LIMIT 5,10; # 檢索記錄行 6-15

    為了檢索從某一個偏移量到記錄集的結束所有的記錄行,可以指定第二個引數為 -1:
    

    mysql> SELECT * FROM table LIMIT 95,-1; # 檢索記錄行 96-last.

    如果只給定一個引數,它表示返回最大的記錄行數目:
    

    mysql> SELECT * FROM table LIMIT 5; # 檢索前 5 個記錄行

    換句話說,LIMIT n 等價於 LIMIT 0,n

  • SELECT ... INTO OUTFILE 'file_name' 格式的 SELECT 將選擇的記錄行寫入一個。檔案被建立在主機上,並且不可以是已存在的 (不管別的,這可以防止資料庫表和檔案例如 `/etc/passwd' 被破壞)。你必須在伺服器主機上有 FILE 來使用這個形式的 SELECTSELECT ... INTO OUTFILE 主要是有意於讓你能夠在服務主機上快速地轉儲一個表。如果你希望將結果檔案建立在其它的主機上,而不是伺服器上,你就不能使用 SELECT ... INTO OUTFILE。在這種情況下,你應該使用某些客戶端例如 mysqldump --tabmysql -e "SELECT ..." > outfile 產生檔案來代替它。 SELECT ... INTO OUTFILELOAD DATA INFILE 的逆操作;語句中的 export_options 部分的句法由 FIELDSLINES 子句組成,它們與與用在 LOAD DATA INFILE 語句中的相同。檢視章節 。在結果文字檔案中,只有下列的字元被 ESCAPED BY 指定的字元轉義:
    • ESCAPED BY 字元
    • FIELDS TENATED BY 中的第一個字元
    • LINES TERMINATED BY 中的第一個字元
    另外,ASCII 0 被轉換到 ESCAPED BY 後而跟一個 0 (ASCII 48)。上述行為的原因是,你必須 轉義任何 FIELDS TERMINATED BYESCAPED BYLINES TERMINATED BY 字元,以便能可靠地將檔案讀回。ASCII 0 被轉義是為了更容易地使用某些分頁程式檢視它。因為結果檔案並不需要遵從 SQL 句法,所以其它是不需要轉義。下面的例子得到的檔案是可用於許多老程式的格式。

    SELECT a,b,a+b INTO OUTFILE "/tmp/result.text" FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY "n" FROM test_table;

    
    
  • 如果使用 INTO DUMPFILE 代替 INTO OUTFILE,MySQL 將在檔案中只寫一行,沒任何列或行端接和任何轉義。如果你希望儲存一個 blob 列到檔案中,這是非常有用的。
  • 注意,任何由 INTO OUTFILEINTO DUMPFILE 建立的檔案將被所有可讀寫!原因是, MySQL 伺服器不能夠建立一個其他使用者擁有的檔案,(你決不應該以 身份執行 mysqld),該檔案必須是公共可讀寫的,以便於你能操作它。

  • 如果你以頁/行鎖使用在一個儲存引擎上 FOR UPDATE,被檢索的記錄行將被寫鎖。

6.4.1.1 JOIN 句法

MySQL 支援在 SELECT 中使用下面所示的 JOIN 句法:

table_reference, table_reference table_reference [CROSS] JOIN table_reference table_reference INNER JOIN table_reference join_condition table_reference STRAIGHT_JOIN table_reference table_reference LEFT [OUTER] JOIN table_reference join_condition table_reference LEFT [OUTER] JOIN table_reference table_reference NATURAL [LEFT [OUTER]] JOIN table_reference { OJ table_reference LEFT OUTER JOIN table_reference ON conditional_expr } table_reference RIGHT [OUTER] JOIN table_reference join_condition table_reference RIGHT [OUTER] JOIN table_reference table_reference NATURAL [RIGHT [OUTER]] JOIN table_reference


table_reference 定義如下:

table_name [[AS] alias] [[USE INDEX (key_list)] | [IGNORE INDEX (key_list)] | [FORCE INDEX (key_list)]]


join_condition 定義如下:

ON conditional_expr | USING (column_list)


通常不應該在 ON 存在任何條件式,它是用於限制在結果集中有哪個行的(對於這個規則也有例外)。如果你希望哪個記錄行應該在結果中,你必須在 WHERE 子句中限制它。

注意,在早於 3.23.17 的版本中,INNER JOIN 不接受一個 join_condition

上面所顯示的最後一個 LEFT OUTER JOIN 句法僅僅是為了與 ODBC 相容而存在的:

  • 一個表引用可以使用 tbl_name AS alias_nametbl_name alias_name 命以別名:

    mysql> SELECT t1.name, t2.salary FROM employee AS t1, info AS t2 -> WHERE t1.name = t2.name;

    
    
  • ON 條件是可以用在一個 WHERE 子句中的任何形式的條件。

  • 如果在一個 LEFT JOINONUSING 部分中右表沒有匹配的記錄,一個所有列被設定為 NULL 的記錄行將被用於右表。你可以透過這個行為找到一個表在另一個表中沒有配對物的記錄:

    mysql> SELECT table1.* FROM table1 -> LEFT JOIN table2 ON table1.id=table2.id -> WHERE table2.id IS NULL;

    這個例子在 table1 中找到所有的記錄行,其 id 值沒有出現在 table2 中(即,所有在 table1 存在的,但在 table2 中沒有對應記錄的記錄行)。當然,這是假定 table2.id 被宣告為 NOT NULL 的。檢視章節 。
    

  • USING (column_list) 子句指定了一個列的列表,列表的中列必須同時存在於兩個表中。例如 USING 子句如下所示:

    A LEFT JOIN B USING (C1,C2,C3,...)

    它可以被定義為在語義上等同於一個這樣的 ON 表示式:
    

    A.C1=B.C1 AND A.C2=B.C2 AND A.C3=B.C3,...

    
    
  • 兩個表的 NATURAL [LEFT] JOIN 被定義為在語義上等同於使用了 USING 子句指定存在於兩張表中的所有列的一個 INNER JOIN 或一個 LEFT JOIN

  • INNER JOIN, (逗號) 在語義上是等同的。都是在所有的表之間進行一個全聯結。通常,在 WHERE 條件中指定表應該如何聯結。

  • RIGHT JOIN 作用類似於 LEFT JOIN。為了保持資料庫邊的程式碼上精簡,LEFT JOIN 被推薦使用來代替 RIGHT JOIN

  • STRAIGHT_JOIN 等同於 JOIN,除了左表先於右表被讀入。當聯結最佳化器將表的順序放錯時(很少),這可用於這種情況。

  • 到 MySQL 3.23.12 時,當 MySQL 在從一個表中檢索資訊時,你可以提示它選擇了哪一個索引。如果 EXPLAIN 顯示 MySQL 使用了可能的索引列表中錯誤的索引,這個特性將是很有用的。透過指定 USE INDEX (key_list),你可以告訴 MySQL 使用可能的索引中最合適的一個索引在表中查詢記錄行。可選的二選一句法 IGNORE INDEX (key_list) 可被用於告訴 MySQL 不使用特定的索引。 在 MySQL 4.0.9 中,你也可以使用 FORCE INDEX。這個有點像 USE INDEX (key_list),但是有了這個附加物,一個表的掃描被採用時,將會有非常大的開銷。換句法說,如果沒有方法使用給定的索引在表中尋找記錄行,這時表掃描才會被使用。 USE/IGNORE/FORCE KEY 分別是 USE/IGNORE/FORCE INDEX 的同義詞。

一些例子:

mysql> SELECT * FROM table1,table2 WHERE table1.id=table2.id; mysql> SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id; mysql> SELECT * FROM table1 LEFT JOIN table2 USING (id); mysql> SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id -> LEFT JOIN table3 ON table2.id=table3.id; mysql> SELECT * FROM table1 USE INDEX (key1,key2) -> WHERE key1=1 AND key2=2 AND key3=3; mysql> SELECT * FROM table1 IGNORE INDEX (key3) -> WHERE key1=1 AND key2=2 AND key3=3;


檢視章節 。

6.4.1.2 UNION 句法

SELECT ... UNION [ALL] SELECT ... [UNION SELECT ...]


UNION 在 MySQL 4.0.0 中被實現。

UNION 用於將多個 SELECT 語句的結果聯合到一個結果集中。

SELECT 中的 select_expression 部分列出的列必須具有同樣的型別。第一個 SELECT 查詢中使用的列名將作為結果集的列名返回。

SELECT 命令是一個普通的選擇命令,但是有下列的限制:

  • 只有最後一個 SELECT 命令可以有 INTO OUTFILE

如果你不為 UNION 使用關鍵詞 ALL,所有返回的記錄行將是唯一的,就好像你為整個返回集使用了一個 DISTINCT。如果你指定了 ALL,那麼你將得到從所有使用的 SELECT 語句中返回的所有匹配記錄行。

如果你希望對整個 UNION 結果使用一個 ORDER BY,你應該使用圓括號:

(SELECT a FROM table_name WHERE a=10 AND B=1 ORDER BY a LIMIT 10) UNION (SELECT a FROM table_name WHERE a=11 AND B=2 ORDER BY a LIMIT 10) ORDER BY a;


6.4.2 HANDLER 句法

HANDLER tbl_name OPEN [ AS alias ] HANDLER tbl_name READ index_name { = | >= | <= | < } (value1,value2,...) [ WHERE ... ] [LIMIT ... ] HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST } [ WHERE ... ] [LIMIT ... ] HANDLER tbl_name READ { FIRST | NEXT } [ WHERE ... ] [LIMIT ... ] HANDLER tbl_name CLOSE


HANDLER 語句提供了直接訪問 MyISAM 表儲存引擎的介面。

HANDLER 語句的第一個形式開啟一個表,透過後來的 HANDLER ... READ 語句使它可讀取。這個表將不能被其它執行緒共享,也不會被關閉,除非執行緒 HANDLER tbl_name CLOSE 或執行緒關閉。

第二個形式讀取指定的索引遵從那個條件並且適合 WHERE 條件的一行(或更多的,由 LIMIT 子句指定)。如果索引由幾個部分組成(範圍有幾個列),值以逗號分隔的列表指定;如果只提供的一部分值,那麼第一個列是必需的。

第三個形式從表中以索引的順序讀取匹配 WHERE 條件的一行(或更多的,由 LIMIT 子句指定)。

第四個形式(沒有索引清單)從表中以自然的列順序(在資料檔案中儲存的次序)讀取匹配 WHERE 條件的一行(或更多的,由 LIMIT 子句指定)。如果期望做一個全表掃描,它將比 HANDLER tbl_name READ index_name 更快。

HANDLER ... CLOSE 關閉一個以 HANDLER ... OPEN 開啟的表。

HANDLER 是一個稍微低階的語句。舉例來說,它不提供一致性。更確切地說,HANDLER ... OPEN 接受一個表的快照,並且 鎖定表。這就意味著在一個 HANDLER ... OPEN 被執行後,表資料仍會被 (這個或其它的執行緒) 修改,這些修改可能在 HANDLER ... NEXTHANDLER ... PREV 掃描中才會部分地出現。

使用這個介面代替普通 SQL 的原因是:

  • 它比 SELECT 快,因為:
    • HANDLER OPEN 中,一個指定的儲存引擎被分配給當前執行緒。
    • 較少的複雜解析。
    • 沒有最佳化器和沒有查詢檢查開銷。
    • 在兩個處理請求之間不需要鎖定使用的表。
    • 介面處理機並不提供一個一致性的檢視資料 (舉例來說,讀汙染 dirty-reads 是允許的),因而,儲存引擎可以做 SQL 通常不允許的最佳化。
  • 它使得更加容易地移植一個使用對 MySQL 的 ISAM 類似介面的應用程式。
  • 它允許你在一個以 SQL 不容易完成(在某些不可能的完全)的情況下遍歷一個資料庫。當使用提供了一個互動式的使用者介面訪問資料庫的應用程式時,介面處理機是更加自然的檢視資料的方式。

6.4.3 INSERT 句法

INSERT [LOW_PRIORITY | DELAYED] [IGNORE] [INTO] tbl_name [(col_name,...)] VALUES ((expression | DEFAULT),...),(...),... [ ON DUPLICATE KEY UPDATE col_name=expression, ... ] or INSERT [LOW_PRIORITY | DELAYED] [IGNORE] [INTO] tbl_name [(col_name,...)] SELECT ... or INSERT [LOW_PRIORITY | DELAYED] [IGNORE] [INTO] tbl_name SET col_name=(expression | DEFAULT), ... [ ON DUPLICATE KEY UPDATE col_name=expression, ... ]


INSERT 將新行插入到一個已存在的表中。INSERT ... VALUES 形式的語句基於明確的值插入記錄行。INSERT ... SELECT 形式的語句從另一個或多個表中選取出值,並將其插入。有多重值列表的 INSERT ... VALUES 形式的語句在 MySQL 3.22.5 或更新的版本中被支援。col_name=expression 句法在 MySQL 3.22.10 或更新的版本中得到支援。

tbl_name 是記錄將要被插入的表。列名列表或 SET 子句指出語句指定的值賦給哪個列:

  • 如果在 INSERT ... VALUESINSERT ... SELECT 中沒有指定列列表,那麼所有列的值必須在 VALUES() 列表中或由 SELECT 提供。如果你不知道表的列的次序,可以使用 DESCRIBE tbl_name 來決定它。

  • 任何沒有明確指定一個值的列均會被設定為它的預設值。舉例來說,如果你指定的一個列列表沒有指定表中所有的列,未指定的列將被設定為它們的預設值。預設值賦值的描述在章節 。你也可以使用關鍵詞 DEFAULT 來將一個列設定為它的預設值(這在 MySQL 4.0.3 中被新加入)。這使它更加容易地書寫賦予值到所有除了幾列的 INSERT 語句,因為它允許您避免書寫一個不完全的 VALUES() 的列表(在該列表沒有包含表中的每個列的列值)。否則,你將不得不在 VALUES() 列表中寫出列列表指定對應的值。 MySQL 通常都會為每個欄位設定一個預設值。這是某些強加在 MySQL 上的,在事務型表與非事務型表中均工作。我們的觀點是在應用程式端檢查欄位的內容,而不是在資料庫伺服器端。

  • 一個 expression 可以引用先前在值列表中設定的任何列。例如,你可以這樣:

    mysql> INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);

    但是不能這樣:
    

    mysql> INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);

    
    
  • 如果你指定關鍵詞 LOW_PRIORITYINSERT 的執行將會被延遲,直到沒有其它客戶端正在讀取表。在這種情況下,客戶端不得不等待插入語句被完成,如果表被頻繁地使用,那麼這將會花費很長一段時間。這與 INSERT DELAYED 讓客戶端立即繼續執行正好相反。檢視章節 。注意,LOW_PRIORITY 通常不對 MyISAM 使用,因為這將禁止併發的插入。檢視章節 。

  • 如果你在一個有許多條記錄行值的 INSERT 中指定關鍵詞 IGNORE,任何在表中現有的 PRIMARYUNIQUE 鍵上重複的記錄行均會被忽略而不被插入。如果你不指定 IGNORE,當有任何記錄行在一個現有的鍵值上重複時,插入均會被中止。你可以透過 C 函式 mysql_info() 測定共有多少記錄行被插入到表中。

  • 如果你指定 ON DUPLICATE KEY UPDATE 子句(在 MySQL 4.1.0 中被新加入),並且被插入的一個記錄行在 PRIMARYUNIQUE 鍵上將會產生一個重複值,那麼老的記錄行將被 UPDATE。舉例來說:

    mysql> INSERT INTO table (a,b,c) VALUES (1,2,3) --&gt ON DUPLICATE KEY UPDATE c=c+1;

    假設列 a 被定義為 UNIQUE,並且已存在了一個 1,它將與下面的語句產生同樣的結果:
    

    mysql> UPDATE table SET c=c+1 WHERE a=1;

    注意:如果列 b 也是唯一的,UPDATE 命令將要被寫成這樣:
    

    mysql> UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;

    並且如果 a=1 OR b=2 匹配幾個記錄行,只有 一個 記錄行將被更新!大體上,在有多重 UNIQUE 鍵的表上,你應該盡是避免使用 ON DUPLICATE KEY 子句。當使用了 ON DUPLICATE KEY UPDATE 後,DELAYED 選項將被忽略。
    

  • 如果 MySQL 被設定為使用 DONT_USE_DEFAULT_FIELDS 選項,INSERT 語句將產生一個錯誤,除非你為所有需要一個非 NULL 值的列明確指定值。檢視章節 。

  • 透過使用 mysql_insert_id 函式你可以找到用於一個 AUTO_INCREMENT 列的值。檢視章節 。

如果你使用 INSERT ... SELECT 或一個 INSERT ... VALUES 語句插入多值列,你可以使用 C API 函式 mysql_info() 得到查詢的資訊。資訊字串的格式如下:

Records: 100 Duplicates: 0 Warnings: 0


Duplicates 指出因與某些現有的唯一索引值重複而不能被插入的記錄行數目。Warnings 指出在嘗試插入的列值中在某些方面可能有問題的數目。在下列任何一個條件下,警告都會發生:

  • 向一個定義為 NOT NULL 的列中插入 NULL 值。該列被設定為它的預設值。
  • 將一個超出列範圍的值賦給一個數字列。該值被剪下到該範圍內的適當的端點。
  • 將一個例如 '10.34 a' 的值賦給一個數字列。尾部的無用資訊將被剝離,保留數字部分並將其插入。如果該值看起來根本就不是一個數字,該列將被設定為 0
  • 將一個超出了列最大長度的字串插入到一個 CHARVARCHARTEXTBLOB 列中。該值將被剪下到該列的最大長度。
  • 將一個對列型別不合法的值插入到一個日期或時間列中。該列被適當格式的零值。

6.4.3.1 INSERT ... SELECT 句法

INSERT [LOW_PRIORITY] [IGNORE] [INTO] tbl_name [(column list)] SELECT ...


使用 INSERT ... SELECT 語句,你可以從一個或多個表中讀取多個記錄行,並將其快速地插入到一個表中。

INSERT INTO tblTemp2 (fldID) SELECT tblTemp1.fldOrder_ID FROM tblTemp1 WHERE tblTemp1.fldOrder_ID > 100;


一個 INSERT ... SELECT 語句有下列條件的限止:

  • INSERT 語句中的目標表不能在 SELECT 查詢部分的 FROM 子句中出現,因為在 ANSI SQL 中,禁止你從正在插入的表中 SELECT。(問題是因為,SELECT 可能會發現在同一執行期內先前被插入的記錄。當使用子選擇子句時,這種情況將會更容易混淆!)
  • AUTO_INCREMENT 列像平常一樣工作。
  • 你可以使用 C API 函式 mysql_info() 得到查詢的資訊。檢視章節 。
  • 為了確保二進位制日誌可以被用於重建最初的表,MySQL 將不允許在 INSERT ... SELECT 期間併發的插入。

你當然也可以使用 REPLACE 代替 INSERT 來蓋寫老的記錄行。

6.4.4 INSERT DELAYED 句法

INSERT DELAYED ...


INSERT 語句的 DELAYED 選項是一個 MySQL 特有的選項,如果你的客戶端不能等待 INSERT 的完成,這將會是很有用的。This is a common problem when you use MySQL for logging and 當你開啟日誌記錄使用 MySQL 並且你週期性的需花費很長時間才完成的 SELECTUPDATE 語句時,這將是一個很普遍的問題。DELAYED 在 MySQL 3.22.15 中被引入。它是 MySQL 對 ANSI SQL92 的一個擴充套件。

INSERT DELAYED 僅僅工作與 ISAMMyISAM 表。注意,因為 MyISAM 表支援併發的 SELECTINSERT,如果在資料檔案中沒有空閒的塊,那你將很少需要對 MyISAM 表使用 INSERT DELAYED。檢視章節 。

當你使用 INSERT DELAYED 時,客戶端將立即得到一個 OK,當表不被任何其它執行緒使用時,該行將被插入。

使用 INSERT DELAYED 的另一個主要的好處就是,從很多客戶端來的插入請求會被打包在一起並寫入一個塊中。這比做許多單獨的插入要快的多。

注意,當前的記錄行佇列是被儲存在中的,一直到他們被插入到表中。這就意味著,如果你使用強制的方法(kill -9) 殺死 mysqld,或者如果意外地死掉,任何沒有寫到磁碟中的記錄行佇列都將會丟失!

下面詳細地描述當你為 INSERTREPLACE 使用 DELAYED 選項時會發生什麼。在這個描述中,“執行緒”是遇到一個 INSERT DELAYED 命令的執行緒,“”是處理所有對於一個特定表的 INSERT DELAYED 語句的執行緒。

  • 當一個執行緒對一個表執行一個 DELAYED 語句時,將會建立一個處理器執行緒用以處理對該表的所有 DELAYED 語句,除非這樣的處理器已經存在。

  • 執行緒檢查處理器是否已經獲得了一個 DELAYED 鎖;如果還沒有,這告訴處理程式去獲得。即使其它的執行緒已在表上加了一個 READWRITE 鎖,也能獲得 DELAYED 鎖。然而,處理器將等待所有的 ALTER TABLE 鎖或 FLUSH TABLES 以保證表結構是最新的。

  • 執行緒執行 INSERT 語句,但是並不將記錄行寫到表中,它將最終的記錄行的副本放到被處理器執行緒管理的佇列中。任何語法錯誤都會被執行緒發現並報告給客戶程式。

  • 客戶端不能報告結果記錄行中重複次數或 AUTO_INCREMENT 值;它不能從伺服器獲得它們,因為 INSERT 早在插入操作被完成之前就返回了。如果你使用 C API,mysql_info() 函式也因同樣的原因而不能獲得任何有意義的資訊。

  • 當記錄行被插入到表中時,二進位制的日誌檔案將被處理器執行緒更新。對於多記錄行的插入,當第一個記錄行被插入時,二進位制日誌被更新。

  • 當每寫入 delayed_insert_limit 個記錄行後,處理器檢查是否仍有任何 SELECT 語句沒有解決。如果是這樣,處理器允許在繼續之前讓這些語句先執行。

  • 當處理器發現在它的佇列中沒有太多的記錄行時,表將被解鎖。如果在 delayed_insert_timeout 秒內沒有接收到新的 INSERT DELAYED 命令,處理器執行緒將終止。

  • 如果在一個特定的處理器佇列中已有超過 delayed_queue_size 個記錄行未被解決,執行緒要求 INSERT DELAYED 等待,只到在佇列中有可用空間。這樣做是為了保證 mysqld 伺服器對延遲記憶體佇列不使用全部的記憶體。

  • 處理器執行緒在 MySQL 程式列表中的 Command 列上顯示為 delayed_insert。如果執行一個 FLUSH TABLES 命令或以 KILL thread_id 殺死它,它將會被殺死。然而,它在退出前會首先將所佇列記錄行儲存到表中。這些期間,它將不再接收其它執行緒的任何新的 INSERT 命令。如果再此之後執行一個 INSERT DELAYED 命令,一個新處理器執行緒將會被建立。注意,上面的意思是,如果一個 INSERT DELAYED 處理器已在執行,那麼 INSERT DELAYED 命令將有比正常 INSERT 命令更高的優先順序!其它的更新命令將不得不等到 INSERT DELAYED 佇列被清空,殺死處理器執行緒(以 KILL thread_id) 或執行 FLUSH TABLES

  • 下列狀態變數提供了有關 INSERT DELAYED 命令的資訊: 變數 含義 Delayed_insert_threads 處理器執行緒數目 Delayed_writes 使用 INSERT DELAYED 寫入的記錄行的數目 Not_flushed_delayed_rows 等待被寫入的記錄行數目 透過發出一個 SHOW STATUS 語句或透過執行一個 mysqladmin extended-status 命令,你可以檢視這些變數。

注意,如果表沒有在使用中,INSERT DELAYED 將比一個正常的 INSERT 慢。讓伺服器為你使用 INSERT DELAYED 的每張表處理一個單獨的執行緒,也是有額外的開銷的。這就意味著,你應該在確定你的確需要它時才使用 INSERT DELAYED

6.4.5 UPDATE 句法

UPDATE [LOW_PRIORITY] [IGNORE] tbl_name SET col_name1=expr1 [, col_name2=expr2 ...] [WHERE where_definition] [ORDER BY ...] [LIMIT rows] or UPDATE [LOW_PRIORITY] [IGNORE] tbl_name [, tbl_name ...] SET col_name1=expr1 [, col_name2=expr2 ...] [WHERE where_definition]


UPDATE 以新的值更新現存表中行的列。SET 子句指出要修改哪個列和他們應該給定的值。WHERE 子句如果被給出,指定哪個記錄行應該被更新。否則,所有的記錄行被更新。如果 ORDER BY 子句被指定,記錄行將被以指定的次序更新。

如果你指定關鍵詞 LOW_PRIORITYUPDATE 的執行將被延遲,直到沒有其它的客戶端正在讀取表。

如果你指定關鍵詞 IGNORE,該更新語句將不會異常中止,即使在更新過程中出現重複鍵錯誤。導致衝突的記錄行將不會被更新。

如果在一個表示式中從 tbl_name 中訪問一個列,UPDATE 使用列的當前值。舉例來說,下面的語句設定 age 列值為它的當前值加 1 :

mysql> UPDATE persondata SET age=age+1;


UPDATE 賦值是從左到右計算的。舉例來說,下列語句將 age 列設定為它的兩倍,然後再加 1 :

mysql> UPDATE persondata SET age=age*2, age=age+1;


如果你設定列為其當前的值,MySQL 注意到這點,並不更新它。

UPDATE 返回實際被改變的記錄行數目。在 MySQL 3.22 或更新的版本中,C API 函式 mysql_info() 返回被匹配並更新的記錄行數目,以及在 UPDATE 期間發生的警告的數目。

在 MySQL 3.23 中,你可以使用 LIMIT # 來確保只有給定的記錄行數目被更改。

如果一個 ORDER BY 子句被使用(從 MySQL 4.0.0 開始支援),記錄行將以指定的次序被更新。這實際上只有連同 LIMIT 一起才有用。

從 MySQL 4.0.4 開始,你也可以執行一個包含多個表的 UPDATE 的操作:

UPDATE items,month SET items.price=month.price WHERE items.id=month.id;


注意:多表 UPDATE 不可以使用 ORDER BYLIMIT

6.4.6 DELETE 句法

DELETE [LOW_PRIORITY] [QUICK] FROM table_name [WHERE where_definition] [ORDER BY ...] [LIMIT rows] or DELETE [LOW_PRIORITY] [QUICK] table_name[.*] [, table_name[.*] ...] FROM table-references [WHERE where_definition] or DELETE [LOW_PRIORITY] [QUICK] FROM table_name[.*] [, table_name[.*] ...] USING table-references [WHERE where_definition]


DELETEtable_name 中刪除 where_definition 中給定條件的記錄行,並返回刪除的記錄數目。

如果你發出一個沒有 WHERE 子句的 DELETE,所有的記錄行將被刪除。如果你以 AUTOCOMMIT 執行它,那麼它類似於 TRUNCATE。檢視章節 。在 MySQL 3.23 中,沒有一個 WHERE 子句的 DELETE 將返回零作為受影響的記錄數目。

當你刪除所有記錄行時,如果你真的希望知道多少條記錄被刪除,你可以使用一個這種形式的 DELETE 語句:

mysql> DELETE FROM table_name WHERE 1>0;


注意,這將比一個沒有 WHERE 子句的 DELETE FROM table_name 語句慢,因為它一次只刪除一行。

如果你指定關鍵詞 LOW_PRIORITYDELETE 的執行將被延遲,直到沒有其它的客戶端正在讀取表。

如果你指定關鍵詞 QUICK,那麼在刪除過程中儲存引擎將不會歸併索引葉,這可能會加速某些型別的刪除操作。

MyISAM 表中,刪除了的記錄被放在一個連結表中維護,以後的 INSERT 操作將重新使用刪除後的記錄位置。為了回收閒置的空間,並減小檔案尺寸,使用 OPTIMIZE TABLE 語句或 myisamchk 實用程式重新組織表。OPTIMIZE TABLE 使用比較容易,但是 myisamchk 更快點。檢視章節 和章節 。

第一個多表刪除格式從 MySQL 4.0.0 開始被支援。第二個多表刪除格式從 MySQL 4.0.2 開始被支援。

僅僅在 FROMUSING 子句 之前 列出的表中的匹配記錄行被刪除。效果就是,你要以從多個表中同時刪除記錄行,並且同樣可以有其它的表用於檢索。

在表名後的 .* 僅僅是為了相容 Access

DELETE t1,t2 FROM t1,t2,t3 WHERE t1.id=t2.id AND t2.id=t3.id or DELETE FROM t1,t2 USING t1,t2,t3 WHERE t1.id=t2.id AND t2.id=t3.id


在上面的情況下,我們僅僅從 t1t2 表中刪除匹配的記錄行。

如果一個 ORDER BY 子句被使用(從 MySQL 4.0.0 開始支援), 記錄行將以指定的次序刪除。這實際上只有連同 LIMIT 一起才有用。示例如下:

DELETE FROM somelog WHERE user = 'jcole' ORDER BY timestamp LIMIT 1


這將刪除匹配 WHERE 子句的,並且最早被插入(透過 timestamp 來確定)的記錄行。

DELETE 語句的LIMIT rows 選項是 MySQL 特有的,它告訴伺服器在控制權被返回到客戶端之前可被刪除的最大記錄行數目。這可以用來確保一個特定的 DELETE 命令不會佔用太長的時間。你可以簡單地重複使用 DELETE 命令,直到被影響的記錄行數目小於 LIMIT 值。

從 MySQL 4.0 開始,在 DELETE 語句中可以指定多個表,用以從一個表中刪除依賴於多表中的特殊情況的記錄行。然而,在一個多表刪除中,不能使用 ORDER BYLIMIT

6.4.7 TRUNCATE 句法

TRUNCATE TABLE table_name


在 3.23 中,TRUNCATE TABLE 被對映為 COMMIT ; DELETE FROM table_name。檢視章節 。

在下面的方式中,TRUNCATE TABLE 不同於 DELETE FROM ...

  • 刪簡操作撤銷並重建表,這將比一個接一個地刪除記錄行要快得多。
  • 非事務的;如果存在一個活動的事務或一個有效的表鎖定,你將會得到一個錯誤。
  • 不返回刪除了的記錄行數目。
  • 只要表定義檔案 `table_name.frm' 是有效的,即使資料或索引檔案已經被損壞,也可以透過這種方式重建表。

TRUNCATE 是一個 SQL 的擴充套件。

6.4.8 REPLACE句法

REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name,...)] VALUES (expression,...),(...),... or REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name [(col_name,...)] SELECT ... or REPLACE [LOW_PRIORITY | DELAYED] [INTO] tbl_name SET col_name=expression, col_name=expression,...


REPLACE 功能與 INSERT 完全一樣,除了如果在表中存在一個老的記錄與新記錄在一個 UNIQUEPRIMARY KEY 上有相同的值,那麼在新記錄被插入之前,老的記錄將被刪除。檢視章節 。

換句話說,你不可以從一個 REPLACE 中訪問老的記錄行的值。某些老的 MySQL 版本中,你或許可以這樣做,但是這是一個 ,現在已被修正了。

為了能夠使用 REPLACE,你必須有對該表的 INSERTDELETE 許可權。

當你使用一個 REPLACE 時,如果新的記錄行代替了老的記錄行,mysql_affected_rows() 將返回 2。這是因為在新行被插入之前,重複記錄行被先刪除了。

這個事實使得判斷 REPLACE 是否是新增一條記錄還是替換一條記錄很容易:檢查受影響記錄行的值是 1 (新增)還是 2(替換)。

注意,除非你使用一個 UNIQUE 索引或 PRIMARY KEY ,使用 REPLACE 命令是沒有感覺的,因為它會僅僅執行一個 INSERT

6.4.9 LOAD DATA INFILE 句法

LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE] INTO TABLE tbl_name [FIELDS [TERMINATED BY 't'] [[OPTIONALLY] ENCLOSED BY ''] [ESCAPED BY '' ] ] [LINES TERMINATED BY 'n'] [IGNORE number LINES] [(col_name,...)]


LOAD DATA INFILE 語句以非常高的速度從一個文字檔案中讀取記錄行並插入到一個表中。如果 LOCAL 關鍵詞被指定,檔案從客戶端主機讀取。如果 LOCAL 沒有被指定,檔案必須位於伺服器上。(LOCAL 在 MySQL 3.22.6 或更新的版本中被支援。)

由於安全性的原因,當讀取位於伺服器端的文字檔案時,檔案必須處於資料庫目錄或可被所有人讀取的地方。同時,為了對伺服器端的檔案使用 LOAD DATA INFILE,你必須在伺服器主機上有 FILE 許可權。檢視章節 d">4.2.7 由 MySQL 提供的許可權。

在 MySQL 3.23.49 和 MySQL 4.0.2 中,只有當你沒有以 --local-infile=0 選項啟動 mysqld,或你沒有禁止你的客戶端程式支援 LOCAL的情況下,LOCAL 才會工作。檢視章節 .

如果你指定關鍵詞 LOW_PRIORITYLOAD DATA 語句的執行將會被延遲,直到沒有其它的客戶端正在讀取表。

如果你對一個 MyISAM 表指定關鍵詞 CONCURRENT,那麼當 LOAD DATA正在執行時,其它的執行緒仍可以從表中檢索資料。使用這個選項時,如果同時也有其它的執行緒正在使用表,這當然會有一點影響 LOAD DATA 的執行。

使用 LOCAL 將比讓伺服器直接訪問檔案要慢一些,因為檔案的內容必須從客戶端主機傳送到伺服器主機。而在另一方面,你不再需要有 FILE 許可權用於裝載本地檔案。

如果你使用先於 MySQL 3.23.24 的版本,你不能夠以 LOAD DATA INFILE 讀取一個 FIFO 。如果你需要從一個 FIFO (例如,gunz的輸出檔案) 中讀取,可以使用 LOAD DATA LOCAL INFILE 代替。

你也可以使用 mysqlimport 實用程式裝載資料檔案;它透過傳送一個 LOAD DATA INFILE 命令到伺服器來動作。--local 選項使得 mysqlimport 從客戶端主機讀取資料檔案。如果客戶端與伺服器支援,你可以指定 --compress 選項,以在較慢的中獲得更好的效能。

當從伺服器主機定位檔案時,伺服器使用下列規則:

  • 如果給定一個完整的路徑,伺服器使用該路徑名。
  • 如果給定一個有一個或多個前置構件的相對路徑,伺服器以相對伺服器的資料目錄搜尋檔案。
  • 如果給定一個沒有前置構件的檔名,伺服器從當前資料庫的資料庫目錄搜尋檔案。

注意,這些規則意味著,一個以 `./myfile.txt' 給出的檔案是從伺服器的資料目錄中讀取的,然而,以 `myfile.txt' 給出的一個檔案是從當前資料庫的資料目錄下讀取的。舉例來說,下面的 LOAD DATA 語句從 db1 資料庫目錄下讀取檔案 `data.txt',因為 db1 是當前資料庫,即使該語句明確地指定讀取的檔案被放入到 資料庫中的一個表中:

mysql> USE db1; mysql> LOAD DATA INFILE "data.txt" INTO TABLE db2.my_table;


REPLACEIGNORE 關鍵詞控制對與現有的記錄在唯一鍵值上重複的記錄的處理。如果你指定 REPLACE,新的記錄行將替換有相同唯一鍵值的現有記錄行。如果你指定 IGNORE,將跳過與現有的記錄行在唯一鍵值上重複的輸入記錄行。如果你沒有指定任何一個選項,當重複鍵值出現時,將會發生一個錯誤,文字檔案的剩餘部分也將被忽略。

如果你使用 LOCAL 關鍵詞從一個本地檔案中讀取資料,在此操作過程中,伺服器沒有辦法停止檔案的傳送,因此預設的處理方式就好像是 IGNORE 被指定一樣。

如果你在一個空的 MyISAM 表上使用 LOAD DATA INFILE,所有非唯一索引會以一個分批方式被建立(就像 REPAIR)。當有許多索引時,這通常可以使 LOAD DATA INFILE 更快一些。

LOAD DATA INFILESELECT ... INTO OUTFILE 的逆操作。檢視章節 。使用 SELECT ... INTO OUTFILE 將資料從一個資料庫寫到一個檔案中。使用 LOAD DATA INFILE 讀取檔案到資料庫中。兩個命令的 FIELDSLINES 子句的句法是一樣的。兩個子句都是可選的,但是如果兩個同時被指定,FIELDS 子句必須出現在 LINES 子句之前。

如果你指定一個 FIELDS 子句,它的子句 (TERMINATED BY[OPTIONALLY] ENCLOSED BYESCAPED BY) 也是可選的,不過,你必須至少指定它們中的一個。

如果你沒有指定一個 FIELDS 子句,預設的相同於如果你這樣寫:

FIELDS TERMINATED BY 't' ENCLOSED BY '' ESCAPED BY ''


如果你沒有指定一個 LINES 子句,預設的相同於如果你這樣寫:

LINES TERMINATED BY 'n'


換句話說,當讀取輸入時,預設值導致 LOAD DATA INFILE 表現如下:

  • 在換行符處尋找行的邊界。
  • 在定位符處將行分開放到欄位中。
  • 不認為欄位由任何引號字元封裝。
  • 將有 “” 開頭的定位符、換行符或 `' 解釋為欄位值的一個文字字元。

相反的,當寫入輸出時,預設值導致 SELECT ... INTO OUTFILE 表現如下:

  • 在欄位值間加上定位符。
  • 不用任何引號字元封裝欄位。
  • 使用 “” 轉義出現在欄位值中的定位符、換行符或 `' 字元例項。
  • 在行的結尾處加上換行符。

注意,為了寫 FIELDS ESCAPED BY '',你必須指定兩個反斜線,該值會作為一個反斜線被讀入。

IGNORE number LINES 選項可被用於忽略檔案開頭處的一個列名的頭:

mysql> LOAD DATA INFILE "/tmp/file_name" INTO TABLE test IGNORE 1 LINES;


當你一前一後地使用 SELECT ... INTO OUTFILELOAD DATA INFILE 將資料從一個資料庫寫到一個檔案中,然後再從檔案中將它讀入資料庫中時,兩個命令的欄位和行處理選項必須匹配。否則,LOAD DATA INFILE 將不能正確地解釋檔案內容。假設你使用 SELECT ... INTO OUTFILE 以逗號分隔欄位的方式將資料寫入到一個檔案中:

mysql> SELECT * INTO OUTFILE 'data.txt' -> FIELDS TERMINATED BY ',' -> FROM ...;


為了將由逗號分隔的檔案讀回時,正確的語句應該是:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2 -> FIELDS TERMINATED BY ',';


如果你試圖用下面所示的語句讀取檔案,它將不會工作,因為命令 LOAD DATA INFILE 以定位符區分欄位值:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2 -> FIELDS TERMINATED BY 't';


可能的結果是每個輸入行將被解釋為一個單獨的欄位。

LOAD DATA INFILE 也可以被用來讀取從外部來源獲得的檔案。例如,SE 格式的檔案,欄位以逗號分隔並以雙引號包圍著。如果檔案中的行以一個換行符終止,那麼下面所示的可以說明你將用來裝載檔案的欄位和行處理選項:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name -> FIELDS TERMINATED BY ',' ENCLOSED BY '"' -> LINES TERMINATED BY 'n';


任何欄位和行處理選項都可以指定一個空字串('')。如果不是空的,FIELDS [OPTIONALLY] ENCLOSED BYFIELDS ESCAPED BY 值必須是一個單個字元。FIELDS TERMINATED BYLINES TERMINATED BY 值可以超過一個字元。例如,為了寫入由回車換行符終止的行,或讀取包含這樣的行的檔案,應該指定一個 LINES TERMINATED BY 'rn' 子句。

舉例來說,為了讀取一個檔案到一個 SQL 表中,檔案以一行 %% 分隔(開玩笑的),你可以這樣做:

CREATE TABLE jokes (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, joke TEXT NOT NULL); LOAD DATA INFILE "/tmp/jokes.txt" INTO TABLE jokes FIELDS TERMINATED BY "" LINES TERMINATED BY "n%%n" (joke);


FIELDS [OPTIONALLY] ENCLOSED BY 控制欄位的包圍字元。對於輸出 (SELECT ... INTO OUTFILE),如果你省略單詞 OPTIONALLY,所有的欄位被 ENCLOSED BY 字元包圍。這樣的一個輸出檔案(以一個逗號作為欄位分界符)示例如下:

"1","a string","100.20" "2","a string containing a , comma","102.20" "3","a string containing a " quote","102.20" "4","a string containing a ", quote and comma","102.20"


如果你指定 OPTIONALLYENCLOSED BY 字元僅被作用於包圍 CHARVARCHAR 欄位:

1,"a string",100.20 2,"a string containing a , comma",102.20 3,"a string containing a " quote",102.20 4,"a string containing a ", quote and comma",102.20


注意,在一個欄位值中出現的 ENCLOSED BY 字元,透過用 ESCAPED BY 字元作為其字首對其轉義。同時也要注意,如果你指定一個空的 ESCAPED BY 值,可能會產生不能被 LOAD DATA INFILE 正確讀出的輸出檔案。例如,如果跳脫字元為空,上面顯示的輸出將變成如下顯示的輸出。請注意第四行的第二個欄位,它包含一個逗號跟在一個引號後的兩個字元,這(錯誤的)看起來像是一個欄位的終止:

1,"a string",100.20 2,"a string containing a , comma",102.20 3,"a string containing a " quote",102.20 4,"a string containing a ", quote and comma",102.20


對於輸入,ENCLOSED BY 字元如果存在,它將從欄位值的尾部被剝離。(不管 OPTIONALLY 是否被指定,都是這樣;對於輸入解釋,OPTIONALLY 不會影響它。) 由ESCAPED BY 字元領先於 ENCLOSED BY 字元的出現,將被解釋為當前欄位值的一部分。另外,在欄位中出現的重複的 ENCLOSED BY 字元被解釋為單個 ENCLOSED BY ,只要欄位本身也是以該字元開始的。例如,如果 ENCLOSED BY '"' 被指定,引號將做如下處理:

"The ""BIG"" boss" -> The "BIG" boss The "BIG" boss -> The "BIG" boss The ""BIG"" boss -> The ""BIG"" boss


FIELDS ESCAPED BY 控制如何寫入或讀出特殊字元。如果 FIELDS ESCAPED BY 字元不是空的,它將被用於做為下列輸出字元的字首:

  • FIELDS ESCAPED BY 字元
  • FIELDS [OPTIONALLY] ENCLOSED BY 字元
  • FIELDS TERMINATED BYLINES TERMINATED BY 值的第一個字元。
  • ASCII 0 (實際上在跳脫字元後寫上 ASCII '0',而不是一個零值位元組)

如果 FIELDS ESCAPED BY 字元為空,沒有字元被轉義。指定一個空的跳脫字元可能不是一個好的主意,特別是如果你的資料欄位值中包含剛才列表中的任何字元時。

對於輸入,如果 FIELDS ESCAPED BY 字元不為空,該字元的出現將會被剝離,後續的字元在字面上做為欄位值的一部分。除了一個轉義的 “0”“N” (即,N,如果跳脫字元為 `')。這些序列被解釋為 ASCII 0 (一個零值位元組) 和 NULL。檢視下面的有關 NULL 處理的規則。

關於更多的 “” 轉義句法資訊,檢視章節 。

在某些情況下,欄位與行處理相互作用:

  • 如果 LINES TERMINATED BY 是一個空字串,FIELDS TERMINATED BY 是非空的,行也用 FIELDS TERMINATED BY 終止。
  • 如果 FIELDS TERMINATED BYFIELDS ENCLOSED BY 值都是空的 (''),一個固定行(無定界符) 格式被使用。用固定行格式時,在欄位之間不使用分隔符。代替的,列值的寫入和讀取使用列的“顯示”寬度。例如,如果一個列被定義為 INT(7),列的值將使用 7 個字元的欄位被寫入。對於輸入,列值透過讀取 7 個字元來獲得。固定行格式也影響對 NULL 值的處理;見下面。注意,如果你正在使用一個多位元組的字符集,固定長度格式將不能工作。

NULL 值的處理有很多,取決於你所使用的 FIELDSLINES 選項:

  • 對於預設的 FIELDSLINES 值,輸出時,NULL 被寫成 N,當讀入時,N 被作為 NULL 讀入(假設 ESCAPED BY 字元為 “”)。
  • 如果 FIELDS ENCLOSED BY 是非空的,一個欄位包含文字詞 NULL 的,它的值做為一個 NULL 值被讀入 (這不同於被 FIELDS ENCLOSED BY 包圍的詞 NULL,它是被作為 'NULL' 讀入的)。
  • 如果 FIELDS ESCAPED BY 是空的,NULL 值被寫為詞 NULL
  • 用固定行格式時 (它發生於 FIELDS TERMINATED BYFIELDS ENCLOSED BY 兩者均為空),NULL 被寫為一個空的字串。注意,當將表中的 NULL 值和空字串一起寫到檔案中時,它們將被混淆,因為它們都是作為空字串被寫入的。如果你在檔案時,需要對他們兩個進行區分,你不應該使用固定行格式。

一些不能被 LOAD DATA INFILE 支援的情況:

  • 固定尺寸的記錄行 (FIELDS TERMINATED BYFIELDS ENCLOSED BY 均為空) 和 BLOBTEXT 列。
  • 如果你指定一個分隔符與另一個相同,或是另一個的字首,LOAD DATA INFILE 可能會不能正確地解釋輸入。例如,下列的 FIELDS 子句將會產生問題:

    FIELDS TERMINATED BY '"' ENCLOSED BY '"'

    
    
  • 如果 FIELDS ESCAPED BY 為空,一個欄位值中包含有 FIELDS ENCLOSED BYLINES TERMINATED BYFIELDS TERMINATED BY 跟隨的值時,將會引起 LOAD DATA INFILE 過早地停止讀取一個欄位或一行。這是因為 LOAD DATA INFILE 不能夠正確地決定欄位或行值在哪裡結果。

下面的例子將裝載 persondata 表的所有列:

mysql> LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;


沒有欄位列被指定,因而 LOAD DATA INFILE 認為輸入行包含表列中所有的欄位。使用預設的 FIELDSLINES 值。

如果你希望裝載表中的某些列,那指定一個欄位列表:

mysql> LOAD DATA INFILE 'persondata.txt' -> INTO TABLE persondata (col1,col2,...);


如果輸入檔案的欄位次序不同於表中列的順序,你也必須指定一個欄位列表。否則 MySQL 不知道如何將輸入欄位與表中的列匹配。

如果一個行有很少的欄位,沒有輸入欄位的列將被設定為預設值。預設值賦值在章節 中被描述。

一個空的欄位值不同於欄位值丟失的解釋:

  • 對於字串型別,列被設定為空字串。
  • 對於數字型別,列被設定為 0
  • 對於日期和時間型別,列被設定為適合列型別的“零”值。檢視章節 。

注意,如果在一個 INSERTUPDATE 語句中明確地將一個空字串賦給一個字串、數字或日期或時間型別,你會得到與上面相同的結果。

如果對 TIMESTAMP 列指定一個 NULL 值,或者當欄位列表被指定時, TIMESTAMP 在欄位列表中被遺漏(僅僅第一個 TIMESTAMP 列被影響),TIMESTAMP 列會被設定為當前的日期和時間。

如果輸入的記錄行有太多的欄位,多餘的欄位將被忽略,並增加警告的數目。

LOAD DATA INFILE 認為所有的輸入均是字串,因而,對於 ENUMSET 列,你不能以 INSERT 語句的形式為其設定數字值。所有的 ENUMSET 必須以字串指定!

如果你正在使用 C API,當 LOAD DATA INFILE 查詢結束時,你可以呼叫 API 函式 mysql_info() 獲得有關查詢的資訊。資訊串的格式如下:

Records: 1 Deleted: 0 Skipped: 0 Warnings: 0


警告會在某些情況下發生,這些情況與值透過 INSERT 語句插入時發生警告的情況一樣 (檢視章節 ),但是 LOAD DATA INFILE 有一點與它不一樣,當在輸入行中有太多或過少的欄位,它也會產生警告。警告不會被儲存在任何地主;警告的數目僅能表示一切是否順利。如果得到警告,並希望確切地知道為什麼會得到它們,一個方法就是使用 SELECT ... INTO OUTFILE,將它儲存到另外一個檔案中,並與原先的輸入檔案進行比較。

如果你需要 LOAD DATA 從一個管道中讀取,你可以使用下面的技巧:

mkfifo /mysql/db/x/x chmod 666 /mysql/db/x/x cat < /dev/tcp/10.1.1.12/4711 > /nt/mysql/db/x/x mysql -e "LOAD DATA INFILE 'x' INTO TABLE x" x


如果你使用的版本早於 MySQL 3.23.25,你只能透過 LOAD DATA LOCAL INFILE 來執行上面。

有關 INSERT 相對 LOAD DATA INFILE 的和加快 LOAD DATA INFILE 的更多資訊,請檢視章節 。

DO expression, [expression, ...]


執行表示式,但不返回任何結果。這是 SELECT expression, expression 的一個縮寫,但是當你並不關心結果時,它稍有點優勢,因為它稍稍快一點。

這主要有益於有副作用的函式,比如 RELEASE_LOCK


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-998559/,如需轉載,請註明出處,否則將追究法律責任。

相關文章