MySQL 4.1.0 中文參考手冊 --- 6.4 資料操縱:SELECT, INSERT, UPDATE, DELETE (轉)
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 BY
或HAVING
子句中。例如: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_name
、tbl_name.col_name
或db_name.tbl_name.col_name
引用一個列。 你不需要在一個SELECT
語句中引用的列前指定tbl_name
或db_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 BY
和GROUP 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;
DISTINCT
、DISTINCTROW
和ALL
選項指定重複的記錄行是否被返回。預設為 (ALL
),返回所有匹配的記錄行。DISTINCT
和DISTINCTROW
是同義詞,它指定結果集重複的記錄行被排除。- 所有以
SQL_
開頭、STRAIGHT_JOIN
和HIGH_PRIORITY
的選項是 MySQL 對 ANSI SQL 的擴充套件。 HIGH_PRIORITY
將給SELECT
語句比一個表有更高的優先順序。你只應該對非常快的或需要立即返回的查詢使用它。 如果一個表已被讀鎖定,甚至是有一個更新語句正在等待表的釋放,一個SELECT HIGH_PRIORITY
查詢也將會執行。SQL_BIG_RESULT
可以與GROUP BY
或DISTINCT
一同使用,以告訴最佳化器結果集將有許多記錄行。在這種情況下,如果需要,MySQL 將直接使用基於的臨時表。同樣的,在這種情況下,MySQL 更願意以GROUP BY
上的一個鍵進行排序而不是建立一個臨時表。SQL_BUFFER_RESULT
將強制把結果放入一個臨時表。這將有助於 MySQL 儘早地釋放表和有助於將大的結果集傳送到客戶端。SQL_SMALL_RESULT
, 一個 MySQL 特有的選項,可以與GROUP BY
或DISTINCT
一同使用,以告訴最佳化器結果集將會很小。在這種情況下,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
中指定ASC
和DESC
: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
來使用這個形式的SELECT
。SELECT ... INTO OUTFILE
主要是有意於讓你能夠在服務主機上快速地轉儲一個表。如果你希望將結果檔案建立在其它的主機上,而不是伺服器上,你就不能使用SELECT ... INTO OUTFILE
。在這種情況下,你應該使用某些客戶端例如mysqldump --tab
或mysql -e "SELECT ..." > outfile
產生檔案來代替它。SELECT ... INTO OUTFILE
是LOAD DATA INFILE
的逆操作;語句中的export_options
部分的句法由FIELDS
和LINES
子句組成,它們與與用在LOAD DATA INFILE
語句中的相同。檢視章節 。在結果文字檔案中,只有下列的字元被ESCAPED BY
指定的字元轉義:ESCAPED BY
字元- 在
FIELDS TENATED BY
中的第一個字元 - 在
LINES TERMINATED BY
中的第一個字元
ASCII 0
被轉換到ESCAPED BY
後而跟一個 0 (ASCII 48
)。上述行為的原因是,你必須 轉義任何FIELDS TERMINATED BY
、ESCAPED BY
或LINES 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 OUTFILE
和INTO 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_name
或tbl_name alias_name
命以別名:mysql> SELECT t1.name, t2.salary FROM employee AS t1, info AS t2 -> WHERE t1.name = t2.name;
ON
條件是可以用在一個WHERE
子句中的任何形式的條件。- 如果在一個
LEFT JOIN
的ON
或USING
部分中右表沒有匹配的記錄,一個所有列被設定為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 ... NEXT
和 HANDLER ... 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 ... VALUES
或INSERT ... 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_PRIORITY
,INSERT
的執行將會被延遲,直到沒有其它客戶端正在讀取表。在這種情況下,客戶端不得不等待插入語句被完成,如果表被頻繁地使用,那麼這將會花費很長一段時間。這與INSERT DELAYED
讓客戶端立即繼續執行正好相反。檢視章節 。注意,LOW_PRIORITY
通常不對MyISAM
使用,因為這將禁止併發的插入。檢視章節 。 - 如果你在一個有許多條記錄行值的
INSERT
中指定關鍵詞IGNORE
,任何在表中現有的PRIMARY
或UNIQUE
鍵上重複的記錄行均會被忽略而不被插入。如果你不指定IGNORE
,當有任何記錄行在一個現有的鍵值上重複時,插入均會被中止。你可以透過 C 函式mysql_info()
測定共有多少記錄行被插入到表中。 - 如果你指定
ON DUPLICATE KEY UPDATE
子句(在 MySQL 4.1.0 中被新加入),並且被插入的一個記錄行在PRIMARY
或UNIQUE
鍵上將會產生一個重複值,那麼老的記錄行將被UPDATE
。舉例來說:mysql> INSERT INTO table (a,b,c) VALUES (1,2,3) --> 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
。 - 將一個超出了列最大長度的字串插入到一個
CHAR
、VARCHAR
、TEXT
或BLOB
列中。該值將被剪下到該列的最大長度。 - 將一個對列型別不合法的值插入到一個日期或時間列中。該列被適當格式的零值。
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 並且你週期性的需花費很長時間才完成的 SELECT
和 UPDATE
語句時,這將是一個很普遍的問題。DELAYED
在 MySQL 3.22.15 中被引入。它是 MySQL 對 ANSI SQL92 的一個擴充套件。
INSERT DELAYED
僅僅工作與 ISAM
和 MyISAM
表。注意,因為 MyISAM
表支援併發的 SELECT
和 INSERT
,如果在資料檔案中沒有空閒的塊,那你將很少需要對 MyISAM
表使用 INSERT DELAYED
。檢視章節 。
當你使用 INSERT DELAYED
時,客戶端將立即得到一個 OK,當表不被任何其它執行緒使用時,該行將被插入。
使用 INSERT DELAYED
的另一個主要的好處就是,從很多客戶端來的插入請求會被打包在一起並寫入一個塊中。這比做許多單獨的插入要快的多。
注意,當前的記錄行佇列是被儲存在中的,一直到他們被插入到表中。這就意味著,如果你使用強制的方法(kill -9
) 殺死 mysqld
,或者如果意外地死掉,任何沒有寫到磁碟中的記錄行佇列都將會丟失!
下面詳細地描述當你為 INSERT
或 REPLACE
使用 DELAYED
選項時會發生什麼。在這個描述中,“執行緒”是遇到一個 INSERT DELAYED
命令的執行緒,“”是處理所有對於一個特定表的 INSERT DELAYED
語句的執行緒。
- 當一個執行緒對一個表執行一個
DELAYED
語句時,將會建立一個處理器執行緒用以處理對該表的所有DELAYED
語句,除非這樣的處理器已經存在。 - 執行緒檢查處理器是否已經獲得了一個
DELAYED
鎖;如果還沒有,這告訴處理程式去獲得。即使其它的執行緒已在表上加了一個READ
或WRITE
鎖,也能獲得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_PRIORITY
,UPDATE
的執行將被延遲,直到沒有其它的客戶端正在讀取表。
如果你指定關鍵詞 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 BY
或 LIMIT
。
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]
DELETE
從 table_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_PRIORITY
,DELETE
的執行將被延遲,直到沒有其它的客戶端正在讀取表。
如果你指定關鍵詞 QUICK
,那麼在刪除過程中儲存引擎將不會歸併索引葉,這可能會加速某些型別的刪除操作。
在 MyISAM
表中,刪除了的記錄被放在一個連結表中維護,以後的 INSERT
操作將重新使用刪除後的記錄位置。為了回收閒置的空間,並減小檔案尺寸,使用 OPTIMIZE TABLE
語句或 myisamchk
實用程式重新組織表。OPTIMIZE TABLE
使用比較容易,但是 myisamchk
更快點。檢視章節 和章節 。
第一個多表刪除格式從 MySQL 4.0.0 開始被支援。第二個多表刪除格式從 MySQL 4.0.2 開始被支援。
僅僅在 FROM
或 USING
子句 之前 列出的表中的匹配記錄行被刪除。效果就是,你要以從多個表中同時刪除記錄行,並且同樣可以有其它的表用於檢索。
在表名後的 .*
僅僅是為了相容 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
在上面的情況下,我們僅僅從 t1
和 t2
表中刪除匹配的記錄行。
如果一個 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 BY
或 LIMIT
。
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
完全一樣,除了如果在表中存在一個老的記錄與新記錄在一個 UNIQUE
或 PRIMARY KEY
上有相同的值,那麼在新記錄被插入之前,老的記錄將被刪除。檢視章節 。
換句話說,你不可以從一個 REPLACE
中訪問老的記錄行的值。某些老的 MySQL 版本中,你或許可以這樣做,但是這是一個 ,現在已被修正了。
為了能夠使用 REPLACE
,你必須有對該表的 INSERT
和 DELETE
許可權。
當你使用一個 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_PRIORITY
,LOAD 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;
REPLACE
和 IGNORE
關鍵詞控制對與現有的記錄在唯一鍵值上重複的記錄的處理。如果你指定 REPLACE
,新的記錄行將替換有相同唯一鍵值的現有記錄行。如果你指定 IGNORE
,將跳過與現有的記錄行在唯一鍵值上重複的輸入記錄行。如果你沒有指定任何一個選項,當重複鍵值出現時,將會發生一個錯誤,文字檔案的剩餘部分也將被忽略。
如果你使用 LOCAL
關鍵詞從一個本地檔案中讀取資料,在此操作過程中,伺服器沒有辦法停止檔案的傳送,因此預設的處理方式就好像是 IGNORE
被指定一樣。
如果你在一個空的 MyISAM
表上使用 LOAD DATA INFILE
,所有非唯一索引會以一個分批方式被建立(就像 REPAIR
)。當有許多索引時,這通常可以使 LOAD DATA INFILE
更快一些。
LOAD DATA INFILE
的 SELECT ... INTO OUTFILE
的逆操作。檢視章節 。使用 SELECT ... INTO OUTFILE
將資料從一個資料庫寫到一個檔案中。使用 LOAD DATA INFILE
讀取檔案到資料庫中。兩個命令的 FIELDS
和 LINES
子句的句法是一樣的。兩個子句都是可選的,但是如果兩個同時被指定,FIELDS
子句必須出現在 LINES
子句之前。
如果你指定一個 FIELDS
子句,它的子句 (TERMINATED BY
、[OPTIONALLY] ENCLOSED BY
和 ESCAPED 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 OUTFILE
和 LOAD 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 BY
和 FIELDS ESCAPED BY
值必須是一個單個字元。FIELDS TERMINATED BY
和 LINES 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"
如果你指定 OPTIONALLY
,ENCLOSED BY
字元僅被作用於包圍 CHAR
和 VARCHAR
欄位:
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 BY
和LINES 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 BY
和FIELDS ENCLOSED BY
值都是空的 (''
),一個固定行(無定界符) 格式被使用。用固定行格式時,在欄位之間不使用分隔符。代替的,列值的寫入和讀取使用列的“顯示”寬度。例如,如果一個列被定義為INT(7)
,列的值將使用 7 個字元的欄位被寫入。對於輸入,列值透過讀取 7 個字元來獲得。固定行格式也影響對NULL
值的處理;見下面。注意,如果你正在使用一個多位元組的字符集,固定長度格式將不能工作。
NULL
值的處理有很多,取決於你所使用的 FIELDS
和 LINES
選項:
- 對於預設的
FIELDS
和LINES
值,輸出時,NULL
被寫成N
,當讀入時,N
被作為NULL
讀入(假設ESCAPED BY
字元為 “”)。 - 如果
FIELDS ENCLOSED BY
是非空的,一個欄位包含文字詞NULL
的,它的值做為一個NULL
值被讀入 (這不同於被FIELDS ENCLOSED BY
包圍的詞NULL
,它是被作為'NULL'
讀入的)。 - 如果
FIELDS ESCAPED BY
是空的,NULL
值被寫為詞NULL
。 - 用固定行格式時 (它發生於
FIELDS TERMINATED BY
和FIELDS ENCLOSED BY
兩者均為空),NULL
被寫為一個空的字串。注意,當將表中的NULL
值和空字串一起寫到檔案中時,它們將被混淆,因為它們都是作為空字串被寫入的。如果你在檔案時,需要對他們兩個進行區分,你不應該使用固定行格式。
一些不能被 LOAD DATA INFILE
支援的情況:
- 固定尺寸的記錄行 (
FIELDS TERMINATED BY
和FIELDS ENCLOSED BY
均為空) 和BLOB
或TEXT
列。 - 如果你指定一個分隔符與另一個相同,或是另一個的字首,
LOAD DATA INFILE
可能會不能正確地解釋輸入。例如,下列的FIELDS
子句將會產生問題:FIELDS TERMINATED BY '"' ENCLOSED BY '"'
- 如果
FIELDS ESCAPED BY
為空,一個欄位值中包含有FIELDS ENCLOSED BY
或LINES TERMINATED BY
被FIELDS TERMINATED BY
跟隨的值時,將會引起LOAD DATA INFILE
過早地停止讀取一個欄位或一行。這是因為LOAD DATA INFILE
不能夠正確地決定欄位或行值在哪裡結果。
下面的例子將裝載 persondata
表的所有列:
mysql> LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;
沒有欄位列被指定,因而 LOAD DATA INFILE
認為輸入行包含表列中所有的欄位。使用預設的 FIELDS
和 LINES
值。
如果你希望裝載表中的某些列,那指定一個欄位列表:
mysql> LOAD DATA INFILE 'persondata.txt' -> INTO TABLE persondata (col1,col2,...);
如果輸入檔案的欄位次序不同於表中列的順序,你也必須指定一個欄位列表。否則 MySQL 不知道如何將輸入欄位與表中的列匹配。
如果一個行有很少的欄位,沒有輸入欄位的列將被設定為預設值。預設值賦值在章節 中被描述。
一個空的欄位值不同於欄位值丟失的解釋:
- 對於字串型別,列被設定為空字串。
- 對於數字型別,列被設定為
0
。 - 對於日期和時間型別,列被設定為適合列型別的“零”值。檢視章節 。
注意,如果在一個 INSERT
或 UPDATE
語句中明確地將一個空字串賦給一個字串、數字或日期或時間型別,你會得到與上面相同的結果。
如果對 TIMESTAMP
列指定一個 NULL
值,或者當欄位列表被指定時, TIMESTAMP
在欄位列表中被遺漏(僅僅第一個 TIMESTAMP
列被影響),TIMESTAMP
列會被設定為當前的日期和時間。
如果輸入的記錄行有太多的欄位,多餘的欄位將被忽略,並增加警告的數目。
LOAD DATA INFILE
認為所有的輸入均是字串,因而,對於 ENUM
或 SET
列,你不能以 INSERT
語句的形式為其設定數字值。所有的 ENUM
和 SET
必須以字串指定!
如果你正在使用 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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SQLite語句(二):INSERT DELETE UPDATE SELECTSQLitedelete
- DBeaver如何生成select,update,delete,insert語句delete
- mysql update join,insert select 語法MySql
- java-Mybatis XML 對映器(select,insert, update 和 delete)JavaMyBatisXMLdelete
- 利用insert,update和delete注入獲取資料delete
- DOJO API 中文參考手冊API
- mysql 在delete、insert、update 時,page的變化MySqldelete
- MySQL資料災難挽救之Delete\UpdateMySqldelete
- 【MySQL 5.7參考手冊】8.14.2 General Thread StatesMySqlthread
- sql server 帶有OUTPUT的INSERT,DELETE,UPDATESQLServerdelete
- JavaScript物件參考手冊JavaScript物件
- KunlunDB功能之insert/update/delete...returning語句delete
- 輕量ORM-SqlRepoEx (四)INSERT、UPDATE、DELETE 語句ORMSQLdelete
- MySQL8-中文參考-三-MySql
- 翻譯:insert on duplicate key update(已提交到MariaDB官方手冊)
- 譯-MYSQL5.7參考手冊--數值型別概述MySql型別
- SQL Server的Merge —— 一步實現 insert,update,deleteSQLServerdelete
- Python sys模組參考手冊Python
- Python os模組參考手冊Python
- 20200116 - HTML 和 CSS 參考手冊HTMLCSS
- PHP-imap 使用參考手冊PHP
- MySQL8-中文參考-三十二-MySql
- MySQL insert on duplicate key update 死鎖MySql
- 譯-MYSQL5.7參考手冊--11.1.1數值型別概述MySql型別
- MySQL教程DML資料操縱語言示例詳解鍵塾MySql
- RedHat Advance Server上安裝Oracle 9204 RAC參考手冊(轉)RedhatServerOracle
- mysql insert into ... select的鎖問題MySql
- 解析MySQL中INSERT INTO SELECT的使用MySql
- HTML 標籤參考手冊 - 功能排序HTML排序
- insert into select
- JavaScript完全參考手冊第3版pdfJavaScript
- MYSQL中的DDL(用來操縱資料庫物件的語言)1MySql資料庫物件
- mysql database manual(mysql資料庫手冊)MySqlDatabase資料庫
- MT7682參考手冊,MT7682晶片設計原理資料介紹晶片
- Laravel5.6 如何列印 SQL?insert/update/select 列印方法總結LaravelSQL
- select for update
- Global.asa程式設計完全參考手冊程式設計
- oracle 參考資料Oracle
- MySQL 關於 INSERT INTO...ON DUPLICATE KEY UPDATE 的使用MySql