- 13.2.4.1. INSERT ... SELECT語法
- 13.2.4.2. INSERT DELAYED語法
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
VALUES ({expr | DEFAULT},...),(...),...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
或:
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
SET col_name={expr | DEFAULT}, ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
或:
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
INSERT用于向一個已有的表中插入新行。INSERT...VALUES和INSERT...SET形式的語句根據明確指定的值插入行。INSERT...SELECT形式的語句插入從其它表中選出的行。在13.2.4.1節,“INSERT ... SELECT語法”中對INSERT...SELECT進行了進一步的討論。
行應被插入到tbl_name表中。可以按以下方法指定列。本語句向這些列提供值。
· 列名稱清單或SET子句明確的指示了列。
· 如果您不為INSERT...VALUES或INSERT...SELECT指定列的清單,則表中每列的值必須在VALUES清單中提供,或由SELECT提供。如果您不知道表中各列的順序,則使用DESCRIBE tbl_name查詢。
列值可以采用多種方法給定:
· 如果不是在嚴格模式下運行,則所有沒有明確給定值的列都被設置為默認值(明確的或隱含的)。例如,如果您指定了一個列清單,但此清單沒有對表中所有的列進行命名,則未命名的各列被設置為默認值。默認值的賦值在13.1.5節,“CREATE TABLE語法”中進行了說明。也可參見1.8.6.2節,“對無效數據的約束”。
有時候,您需要對所有沒有默認值的列明確地指定值。如果您希望,在沒有明確指定值時,INSERT語句可以生成錯誤信息,則您應該使用STRICT模式。請參見5.3.2節,“SQL服務器模式”。
· 使用關鍵詞DEFAULT,明確地把列設置為默認值。這樣,編寫向所有列賦值的INSERT語句時可以更容易,因為使用DEFAULT可以避免編寫出不完整的、未包含全部列值的VALUES清單。如果不使用DEFUALT,您必須編寫一個列名稱清單,與VALUES清單中的每個值對應。
您還可以使用DEFAULT(col_name)作為一種更通用的形式,在表達式中使用,用于生成一個列的默認值。
· 如果列清單和VALUES清單均為空清單,則INSERT會創建一個行,每個列都被設置為默認值:
· mysql> INSERT INTO tbl_name () VALUES();
在STRICT模式中,如果有一列沒有默認值,則會出現錯誤。或者,MySQL會對所有沒有明確定義默認值的列使用隱含的默認值。
· 您可以指定一個表達式expr來提供一個列值。如果表達式的類型與列值不匹配,這樣做會造成類型轉化。并且,給定值的轉化會導致不同的插入值,插入何值由列類型而定。例如,向一個INT, FLOAT, DECIMAL(10,6)或YEAR列插入字符串'1999.0e-2',插入值分別是1999,19.9921,19.992100和1999。存儲在INT和YEAR列中的值為1999的原因是,在從字符串到整數的轉化中,只把字符串的前面部分看作有效的整數或年份。對于浮點列和固定點列,在從字符串到浮點的轉化中,把整個字符串均看作有效的浮點值。
表達式expr可以引用在值清單中已設置的所有列。例如,您可以這么操作,因為用于col2的值引用了col1,而col1已經被賦值:
mysql> INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);
但是以下語句不合法,因為用于col1的值引用了col2,而col2在col1之后被賦值:
mysql> INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);
有一種例外情況,那就是含有AUTO_INCREMENT值的列。因為AUTO_INCREMENT值在其它值賦值之后被生成,所以任何在賦值時對AUTO_INCREMENT列的引用都會返回0。
INSERT語句支持下列修改符:
· 如果您使用DELAYED關鍵字,則服務器會把待插入的行放到一個緩沖器中,而發送INSERT DELAYED語句的客戶端會繼續運行。如果表正在被使用,則服務器會保留這些行。當表空閑時,服務器開始插入行,并定期檢查是否有新的讀取請求。如果有新的讀取請求,則被延遲的行被延緩執行,直到表再次空閑時為止。請參見13.2.4.2節,“INSERT DELAYED語法”。
· 如果您使用LOW_PRIORITY關鍵詞,則INSERT的執行被延遲,直到沒有其它客戶端從表中讀取為止。當原有客戶端正在讀取時,有些客戶端剛開始讀取。這些客戶端也被包括在內。此時,INSERT LOW_PRIORITY語句等候。因此,在讀取量很大的情況下,發出INSERT LOW_PRIORITY語句的客戶端有可能需要等待很長一段時間(甚至是永遠等待下去)。(這與INSERT DELAYED形成對比,INSERT DELAYED立刻讓客戶端繼續執行。請參見13.2.4.2節,“INSERT DELAYED語法”。)注意LOW_PRIORITY通常不應用于MyISAM表,因為這么做會取消同時進行的插入。請參見15.1節,“MyISAM存儲引擎”。
· 如果您指定了HIGH_PRIORITY,同時服務器采用--low-priority-updates選項啟動,則HIGH_PRIORITY將覆蓋--low-priority-updates選項。這么做還會導致同時進行的插入被取消。
· 使用mysql_affected_rows() C API函數,可以獲得用于INSERT的受影響行的值。請參見25.2.3.1節,“mysql_affected_rows()”。
· 如果您在一個INSERT語句中使用IGNORE關鍵詞,在執行語句時出現的錯誤被當作警告處理。例如,沒有使用IGNORE時,如果一個行復制了原有的UNIQUE索引或PRIMARY KEY值,會導致出現重復關鍵字錯誤,語句執行失敗。使用IGNORE時,該行仍然未被插入,但是不會出現錯誤。IGNORE未被指定時,如果數據轉化引發錯誤,則會使語句執行失敗。使用IGNORE后,無效數據被調整到最接近的值,并被插入;此時,生成警告,但是語句執行不會失敗。您可以使用mysql_info() C API函數測定有多少行被插入到表中。
如果您指定了ON DUPLICATE KEY UPDATE,并且插入行后會導致在一個UNIQUE索引或PRIMARY KEY中出現重復值,則執行舊行UPDATE。例如,如果列a被定義為UNIQUE,并且包含值1,則以下兩個語句具有相同的效果:
mysql> INSERT INTO table (a,b,c) VALUES (1,2,3)
-> ON DUPLICATE KEY UPDATE c=c+1;
mysql> UPDATE table SET c=c+1 WHERE a=1;
如果行作為新記錄被插入,則受影響行的值為1;如果原有的記錄被更新,則受影響行的值為2。
注釋:如果列b也是唯一列,則INSERT與此UPDATE語句相當:
mysql> UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
如果a=1 OR b=2與多個行向匹配,則只有一個行被更新。通常,您應該盡量避免對帶有多個唯一關鍵字的表使用ON DUPLICATE KEY子句。
您可以在UPDATE子句中使用VALUES(col_name)函數從INSERT...UPDATE語句的INSERT部分引用列值。換句話說,如果沒有發生重復關鍵字沖突,則UPDATE子句中的VALUES(col_name)可以引用被插入的col_name的值。本函數特別適用于多行插入。VALUES()函數只在INSERT...UPDATE語句中有意義,其它時候會返回NULL。
示例:
mysql> INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
-> ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
本語句與以下兩個語句作用相同:
mysql> INSERT INTO table (a,b,c) VALUES (1,2,3)
-> ON DUPLICATE KEY UPDATE c=3;
mysql> INSERT INTO table (a,b,c) VALUES (4,5,6)
-> ON DUPLICATE KEY UPDATE c=9;
當您使用ON DUPLICATE KEY UPDATE時,DELAYED選項被忽略。
您可以使用SQL LAST_INSERT_ID()函數查找用于AUTO_INCREMENT列的值。從C API的內部,使用mysql_insert_id()函數。不過,您應該注意,兩個函數的作用并不總是相同的。在12.9.3節,“信息函數”和25.2.3.36節,“mysql_insert_id()”中進一步討論了與AUTO_INCREMENT列有關的INSERT語句的作用。
如果您使用INSERT...VALUES語句時采用了多個值清單或INSERT...SELECT,則該語句按以下格式返回一個信息字符串:
Records: 100 Duplicates: 0 Warnings: 0
記錄指示了經過語句處理的行的數目。(因為重復數目可以不是零,所以該數目不一定是實際被插入的行的數目。)重復數目指的是不能被插入的行的數目,因為這些行會復制部分原有的唯一索引值。警告指的是插入有錯誤或有問題的列值的次數。在以下情況下會出現警告:
· 向一個已定義為NOT NULL的列中插入NULL。對于一個多行INSERT語句或INSERT INTO...SELECT語句,根據列數據的類型,列被設置為隱含的默認值。對于數字類型,默認值為0;對于字符串類型,默認值為空字符串('');對于日期和時間類型,默認值為“zero”值。對INSERT INTO...SELECT語句的處理方法與對多行插入的處理方法一樣,因為服務器不能檢測來自SELECT的結果,不能判斷是否返回單一行。(對于單一行INSERT,當NULL被插入一個NOT NULL列時,不會出現警告,而是出現錯誤,并且語句運行失敗。)
· 數字列的值被設置在列的值范圍之外。此值被修改為未最接近的值范圍端點。
· 向一個數字列賦予一個例如'10.34 a'的值。尾部的非數字文本被刪節,其余的數字部分被插入,如果字符串值沒有前導的數字部分,則該列被設置為0。
· 向一個字符串列(CHAR, VARCHAR, TEXT或BLOB)中插入的字符串超過了列的最大長度。此值被刪節到列的最大長度。
· 向日期或時間列中插入的值對于該列的類型是不合法的。根據列的類型,該列被設置到相應的零值。
如果您正在使用C API,則可以通過調用mysql_info()函數獲取信息字符串。請參見25.2.3.34節,“mysql_info()”。