發新話題

MySQL 數據操縱:SELECT, INSERT, UPDATE, DELETE

MySQL 數據操縱:SELECT, INSERT, UPDATE, DELETE

MySQL Reference Manual for version 4.1.0-alpha.

6.4 數據操縱:SELECT, 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 子句被執行時,列值可能還沒有被計算確定。查看章節 A.5.4 使用 alias 的限制。

    * FROM table_references 子句表示從哪個表中檢索記錄行。如果你命名超過超過一個表,並執行一個 join。對於 join 句法的信息,查看章節 6.4.1.1 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 (在當前的數據庫中) 引用一張表,或以 dbname.tbl_name 明確地指定其個數據。你要以以 col_name、tbl_name.col_name 或 db_name.tbl_name.col_name 引用一個列。 你不需要在一個 SELECT 語句中引用的列前指定 tbl_name 或 db_name.tbl_name 前綴,除非引用列存在二義性。查看章節 6.1.2 數據庫、表、索引、列和別名,對於有歧義的列引用需要更加顯式的列引用格式。

    * 一個表的引用可以使用 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 支持的任何函數。查看章節 6.3 用於 SELECT 和 WHERE 子句的函數。

    * 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() 可以檢索到記錄行的數目。查看章節 6.3.6.2 輔助功能函數。 請注意,在早於 4.1.0 的版本中,LIMIT 0 是不工作的,它將被優化為立即返回(結果集的記錄數為 0)。查看章節 5.2.8 MySQL 如何優化 LIMIT。

    * 如果你使用了 QUERY_CACHE_TYPE=2 (DEMAND),SQL_CACHE 告訴 MySQL 將存儲查詢結果放入查詢高速緩存內。查看章節 6.9 MySQL 的查詢高速緩存。

    * SQL_NO_CACHE 告訴 MySQL 不允許將查詢結果存儲到查詢緩存內。查看章節 6.9 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 中的描述。查看章節 6.3.7 用於 GROUP BY 子句的函數。

    * STRAIGHT_JOIN 強制優化器以表在 FROM 子句中列出的順序聯結。如果優化器以一個非優化的次序聯結各表,你可以使用它來加速一個查詢。查看章節 5.2.1 EXPLAIN 句法(得到有關 SELECT 的信息)。

    * 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 語句中的相同。查看章節 6.4.9 LOAD DATA INFILE 句法。 在結果文本文件中,只有下列的字符被 ESCAPED BY 指定的字符轉義:
          o ESCAPED BY 字符
          o 在 FIELDS TERMINATED BY 中的第一個字符
          o 在 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 服務器不能夠創建一個其他用戶擁有的文件,(你決不應該以 root 身份運行 mysqld),該文件必須是公共可讀寫的,以便於你能操作它。

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

TOP

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 的。查看章節 5.2.6 MySQL 如何優化 LEFT JOIN 和 RIGHT JOIN。

    * 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;

查看章節 5.2.6 MySQL 如何優化 LEFT JOIN 和 RIGHT JOIN。
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 快,因為:
          o 在 HANDLER OPEN 中,一個指定的存儲引擎被分配給當前線程。
          o 較少的複雜解析。
          o 沒有優化器和沒有查詢檢查開銷。
          o 在兩個處理請求之間不需要鎖定使用的表。
          o 接口處理機並不提供一個一致性的查看數據 (舉例來說,讀污染 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 來決定它。

    * 任何沒有明確指定一個值的列均會被設置為它的缺省值。舉例來說,如果你指定的一個列列表沒有指定表中所有的列,未指定的列將被設置為它們的缺省值。缺省值賦值的描述在章節 6.5.3 CREATE TABLE 句法。 你也可以使用關鍵詞 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 讓客戶端立即繼續執行正好相反。查看章節 6.4.4 INSERT DELAYED 句法。注意,LOW_PRIORITY 通常不對 MyISAM 使用,因為這將禁止並發的插入。查看章節 7.1 MyISAM 表。

    * 如果你在一個有許多條記錄行值的 INSERT 中指定關鍵詞 IGNORE,任何在表中現有的 PRIMARY 或 UNIQUE 鍵上重複的記錄行均會被忽略而不被插入。如果你不指定 IGNORE,當有任何記錄行在一個現有的鍵值上重複時,插入均會被中止。你可以通過 C API 函數 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 值的列明確指定值。查看章節 2.3.3 典型的 configure 選項。

    * 通過使用 mysql_insert_id 函數你可以找到用於一個 AUTO_INCREMENT 列的值。查看章節 8.1.3.130 mysql_insert_id()。

如果你使用 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 列中。該值將被剪切到該列的最大長度。
    * 將一個對列類型不合法的值插入到一個日期或時間列中。該列被適當格式的零值。

TOP

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() 得到查詢的信息。查看章節 6.4.3 INSERT 句法。
    * 為了確保二進制日誌可以被用於重建最初的表,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。查看章節 7.1 MyISAM 表。

當你使用 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。查看章節 6.4.7 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 更快點。查看章節 4.5.1 OPTIMIZE TABLE 句法 和章節 4.4.6.10 表優化。

第一個多表刪除格式從 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。查看章節 6.4.6 DELETE 句法。

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

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

TRUNCATE 是一個 Oracle 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 上有相同的值,那麼在新記錄被插入之前,老的記錄將被刪除。查看章節 6.4.3 INSERT 句法。

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

為了能夠使用 REPLACE,你必須有對該表的 INSERT 和 DELETE 權限。

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

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

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

TOP

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 權限。查看章節 4.2.7 由 MySQL 提供的權限。

在 MySQL 3.23.49 和 MySQL 4.0.2 中,只有當你沒有以 --local-infile=0 選項啟動 mysqld,或你沒有禁止你的客戶端程序支持 LOCAL的情況下,LOCAL 才會工作。查看章節 4.2.4 LOAD DATA LOCAL 的安全性問題.

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

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

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

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

你也可以使用 mysqlimport 實用程序裝載數據文件;它通過發送一個 LOAD DATA INFILE 命令到服務器來動作。--local 選項使得 mysqlimport 從客戶端主機讀取數據文件。如果客戶端與服務器支持壓縮協議,你可以指定 --compress 選項,以在較慢的網絡中獲得更好的性能。

當從服務器主機定位文件時,服務器使用下列規則:

    * 如果給定一個完整的路徑,服務器使用該路徑名。
    * 如果給定一個有一個或多個前置構件的相對路徑,服務器以相對服務器的數據目錄搜索文件。
    * 如果給定一個沒有前置構件的文件名,服務器從當前數據庫的數據庫目錄搜尋文件。

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

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 的逆操作。查看章節 6.4.1 SELECT 句法。使用 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 也可以被用來讀取從外部來源獲得的文件。例如,dBASE 格式的文件,字段以逗號分隔並以雙引號包圍著。如果文件中的行以一個換行符終止,那麼下面所示的可以說明你將用來裝載文件的字段和行處理選項:

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 '\r\n' 子句。

舉例來說,為了讀取一個文件到一個 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

TOP

對於輸入,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」 (即,\0 或\N,如果轉義字符為 `\')。這些序列被解釋為 ASCII 0 (一個零值字節) 和 NULL。查看下面的有關 NULL 處理的規則。

關於更多的 「\」 轉義句法信息,查看章節 6.1.1 文字:怎麼寫字符串與數字。

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

    * 如果 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 不知道如何將輸入字段與表中的列匹配。

如果一個行有很少的字段,沒有輸入字段的列將被設置為缺省值。缺省值賦值在章節 6.5.3 CREATE TABLE 句法 中被描述。

一個空的字段值不同於字段值丟失的解釋:

    * 對於字符串類型,列被設置為空字符串。
    * 對於數字類型,列被設置為 0。
    * 對於日期和時間類型,列被設置為適合列類型的「零」值。查看章節 6.2.2 Date 和 Time 類型。

注意,如果在一個 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 語句插入時發生警告的情況一樣 (查看章節 6.4.3 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 的更多信息,請查看章節 5.2.9 INSERT 查詢的速度。
6.4.10 DO 句法

DO expression, [expression, ...]

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

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

TOP

發新話題

本站所有圖文均屬網友發表,僅代表作者的觀點與本站無關,如有侵權請通知版主會盡快刪除。