📄 06-4.html
字号:
</P>
<P>
使用这个接口代替普通 SQL 的原因是:
</P>
<UL>
<LI>
它比 <CODE>SELECT</CODE> 快,因为:
<UL>
<LI>
在 <CODE>HANDLER OPEN</CODE> 中,一个指定的存储引擎被分配给当前线程。
<LI>
较少的复杂解析。
<LI>
没有优化器和没有查询检查开销。
<LI>
在两个处理请求之间不需要锁定使用的表。
<LI>
接口处理机并不提供一个一致性的查看数据 (举例来说,读污染 dirty-reads 是允许的),因而,存储引擎可以做 SQL 通常不允许的优化。
</UL>
<LI>
它使得更加容易地移植一个使用对 MySQL 的 ISAM 类似接口的应用程序。
<LI>
它允许你在一个以 SQL 不容易完成(在某些不可能的完全)的情况下遍历一个数据库。当使用提供了一个交互式的用户接口访问数据库的应用程序时,接口处理机是更加自然的查看数据的方式。
</UL>
<H3><A NAME="INSERT"></A>6.4.3 <CODE>INSERT</CODE> 句法</H3>
<P>
<A NAME="IDX1427"></A>
</P>
<PRE>
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, ... ]
</PRE>
<P>
<CODE>INSERT</CODE> 将新行插入到一个已存在的表中。<CODE>INSERT ... VALUES</CODE> 形式的语句基于明确的值插入记录行。<CODE>INSERT ... SELECT</CODE> 形式的语句从另一个或多个表中选取出值,并将其插入。有多重值列表的 <CODE>INSERT ... VALUES</CODE> 形式的语句在 MySQL 3.22.5 或更新的版本中被支持。<CODE>col_name=expression</CODE> 句法在
MySQL 3.22.10 或更新的版本中得到支持。
</P>
<P>
<CODE>tbl_name</CODE> 是记录将要被插入的表。列名列表或 <CODE>SET</CODE> 子句指出语句指定的值赋给哪个列:
</P>
<UL>
<LI>
如果在 <CODE>INSERT ... VALUES</CODE> 或 <CODE>INSERT ... SELECT</CODE> 中没有指定列列表,那么所有列的值必须在 <CODE>VALUES()</CODE> 列表中或由 <CODE>SELECT</CODE> 提供。如果你不知道表的列的次序,可以使用 <CODE>DESCRIBE tbl_name</CODE> 来决定它。
<P></P>
<LI>
<A NAME="IDX1428"></A>
任何没有明确指定一个值的列均会被设置为它的缺省值。举例来说,如果你指定的一个列列表没有指定表中所有的列,未指定的列将被设置为它们的缺省值。缺省值赋值的描述在章节 <A HREF="06-5.html#CREATE_TABLE">6.5.3 <CODE>CREATE TABLE</CODE> 句法</A>。
你也可以使用关键词 <CODE>DEFAULT</CODE> 来将一个列设置为它的默认值(这在 MySQL 4.0.3 中被新加入)。这使它更加容易地书写赋予值到所有除了几列的 <CODE>INSERT</CODE> 语句,因为它允许您避免书写一个不完全的 <CODE>VALUES()</CODE> 的列表(在该列表没有包含表中的每个列的列值)。否则,你将不得不在 <CODE>VALUES()</CODE> 列表中写出列列表指定对应的值。
MySQL 通常都会为每个字段设置一个缺省值。这是某些强加在 MySQL 上的,在事务型表与非事务型表中均工作。
我们的观点是在应用程序端检查字段的内容,而不是在数据库服务器端。
<P></P>
<LI>
一个 <CODE>expression</CODE> 可以引用先前在值列表中设置的任何列。例如,你可以这样:
<PRE>
mysql> INSERT INTO tbl_name (col1,col2) VALUES(15,col1*2);
</PRE>
但是不能这样:
<PRE>
mysql> INSERT INTO tbl_name (col1,col2) VALUES(col2*2,15);
</PRE>
<LI>
如果你指定关键词 <CODE>LOW_PRIORITY</CODE>,<CODE>INSERT</CODE> 的执行将会被延迟,直到没有其它客户端正在读取表。在这种情况下,客户端不得不等待插入语句被完成,如果表被频繁地使用,那么这将会花费很长一段时间。这与 <CODE>INSERT DELAYED</CODE> 让客户端立即继续执行正好相反。查看章节 <A HREF="6-4.html#INSERT_DELAYED">6.4.4 <CODE>INSERT DELAYED</CODE> 句法</A>。注意,<CODE>LOW_PRIORITY</CODE> 通常不对 <CODE>MyISAM</CODE> 使用,因为这将禁止并发的插入。查看章节 <A HREF="manual2.html#MyISAM">7.1 <CODE>MyISAM</CODE> 表</A>。
<P></P>
<LI>
如果你在一个有许多条记录行值的 <CODE>INSERT</CODE> 中指定关键词 <CODE>IGNORE</CODE>,任何在表中现有的 <CODE>PRIMARY</CODE> 或 <CODE>UNIQUE</CODE> 键上重复的记录行均会被忽略而不被插入。如果你不指定 <CODE>IGNORE</CODE>,当有任何记录行在一个现有的键值上重复时,插入均会被中止。你可以通过 C API 函数 <CODE>mysql_info()</CODE> 测定共有多少记录行被插入到表中。
<P></P>
<LI>
如果你指定 <CODE>ON DUPLICATE KEY UPDATE</CODE> 子句(在 MySQL 4.1.0 中被新加入),并且被插入的一个记录行在 <CODE>PRIMARY</CODE> 或 <CODE>UNIQUE</CODE> 键上将会产生一个重复值,那么老的记录行将被 <CODE>UPDATE</CODE>。举例来说:
<PRE>
mysql> INSERT INTO table (a,b,c) VALUES (1,2,3)
--> ON DUPLICATE KEY UPDATE c=c+1;
</PRE>
假设列 <CODE>a</CODE> 被定义为 <CODE>UNIQUE</CODE>,并且已存在了一个 <CODE>1</CODE>,它将与下面的语句产生同样的结果:
<PRE>
mysql> UPDATE table SET c=c+1 WHERE a=1;
</PRE>
<STRONG>注意:</STRONG>如果列 <CODE>b</CODE> 也是唯一的,<CODE>UPDATE</CODE> 命令将要被写成这样:
<PRE>
mysql> UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;
</PRE>
并且如果 <CODE>a=1 OR b=2</CODE> 匹配几个记录行,只有 <STRONG>一个</STRONG> 记录行将被更新!大体上,在有多重 <CODE>UNIQUE</CODE> 键的表上,你应该尽是避免使用 <CODE>ON DUPLICATE KEY</CODE> 子句。
当使用了 <CODE>ON DUPLICATE KEY UPDATE</CODE> 后,<CODE>DELAYED</CODE> 选项将被忽略。
<P></P>
<LI>
如果 MySQL 被设置为使用 <CODE>DONT_USE_DEFAULT_FIELDS</CODE> 选项,<CODE>INSERT</CODE> 语句将产生一个错误,除非你为所有需要一个非 <CODE>NULL</CODE> 值的列明确指定值。查看章节 <A HREF="manual1.html#configure_options">2.3.3 典型的 <CODE>configure</CODE> 选项</A>。
<P></P>
<LI>
通过使用 <CODE>mysql_insert_id</CODE> 函数你可以找到用于一个 <CODE>AUTO_INCREMENT</CODE> 列的值。查看章节 <A HREF="manual2.html#mysql_insert_id">8.1.3.130 <CODE>mysql_insert_id()</CODE></A>。
</UL>
<P>
<A NAME="IDX1429"></A>
如果你使用 <CODE>INSERT ... SELECT</CODE> 或一个 <CODE>INSERT ... VALUES</CODE> 语句插入多值列,你可以使用 C API 函数
<CODE>mysql_info()</CODE> 得到查询的信息。信息字串的格式如下:
</P>
<PRE>
Records: 100 Duplicates: 0 Warnings: 0
</PRE>
<P>
<CODE>Duplicates</CODE> 指出因与某些现有的唯一索引值重复而不能被插入的记录行数目。<CODE>Warnings</CODE> 指出在尝试插入的列值中在某些方面可能有问题的数目。在下列任何一个条件下,警告都会发生:
</P>
<UL>
<LI>
向一个定义为 <CODE>NOT NULL</CODE> 的列中插入 <CODE>NULL</CODE> 值。该列被设置为它的缺省值。
<LI>
将一个超出列范围的值赋给一个数字列。该值被剪切到该范围内的适当的端点。
<LI>
将一个例如 <CODE>'10.34 a'</CODE> 的值赋给一个数字列。尾部的无用信息将被剥离,保留数字部分并将其插入。如果该值看起来根本就不是一个数字,该列将被设置为 <CODE>0</CODE>。
<LI>
将一个超出了列最大长度的字符串插入到一个 <CODE>CHAR</CODE>、<CODE>VARCHAR</CODE>、<CODE>TEXT</CODE> 或 <CODE>BLOB</CODE> 列中。该值将被剪切到该列的最大长度。
<LI>
将一个对列类型不合法的值插入到一个日期或时间列中。该列被适当格式的零值。
</UL>
<P>
<A NAME="IDX1430"></A>
<A NAME="IDX1431"></A>
</P>
<H4><A NAME="INSERT_SELECT"></A>6.4.3.1 <CODE>INSERT ... SELECT</CODE> 句法</H4>
<PRE>
INSERT [LOW_PRIORITY] [IGNORE] [INTO] tbl_name [(column list)] SELECT ...
</PRE>
<P>
使用 <CODE>INSERT ... SELECT</CODE> 语句,你可以从一个或多个表中读取多个记录行,并将其快速地插入到一个表中。
</P>
<PRE>
INSERT INTO tblTemp2 (fldID) SELECT tblTemp1.fldOrder_ID FROM tblTemp1 WHERE
tblTemp1.fldOrder_ID > 100;
</PRE>
<P>
一个 <CODE>INSERT ... SELECT</CODE> 语句有下列条件的限止:
</P>
<UL>
<LI>
<CODE>INSERT</CODE> 语句中的目标表不能在 <CODE>SELECT</CODE> 查询部分的 <CODE>FROM</CODE> 子句中出现,因为在 ANSI SQL 中,禁止你从正在插入的表中 <CODE>SELECT</CODE>。(问题是因为,<CODE>SELECT</CODE> 可能会发现在同一运行期内先前被插入的记录。当使用子选择子句时,这种情况将会更容易混淆!)
<LI>
<CODE>AUTO_INCREMENT</CODE> 列像平常一样工作。
<LI>
你可以使用 C API 函数 <CODE>mysql_info()</CODE> 得到查询的信息。查看章节 <A HREF="06-4.html#INSERT">6.4.3 <CODE>INSERT</CODE> 句法</A>。
<LI>
为了确保二进制日志可以被用于重建最初的表,MySQL 将不允许在 <CODE>INSERT ... SELECT</CODE> 期间并发的插入。
</UL>
<P>
你当然也可以使用 <CODE>REPLACE</CODE> 代替 <CODE>INSERT</CODE> 来盖写老的记录行。
</P>
<H3><A NAME="INSERT_DELAYED"></A>6.4.4 <CODE>INSERT DELAYED</CODE> 句法</H3>
<P>
<A NAME="IDX1432"></A>
<A NAME="IDX1433"></A>
</P>
<P>
<A NAME="IDX1434"></A>
</P>
<PRE>
INSERT DELAYED ...
</PRE>
<P>
<CODE>INSERT</CODE> 语句的 <CODE>DELAYED</CODE> 选项是一个 MySQL 特有的选项,如果你的客户端不能等待 <CODE>INSERT</CODE> 的完成,这将会是很有用的。This is a common problem when you use MySQL for logging and
当你打开日志记录使用 MySQL 并且你周期性的需花费很长时间才完成的 <CODE>SELECT</CODE> 和 <CODE>UPDATE</CODE> 语句时,这将是一个很普遍的问题。<CODE>DELAYED</CODE> 在 MySQL 3.22.15 中被引入。它是 MySQL 对 ANSI SQL92 的一个扩展。
</P>
<P>
<CODE>INSERT DELAYED</CODE> 仅仅工作与 <CODE>ISAM</CODE> 和 <CODE>MyISAM</CODE> 表。注意,因为 <CODE>MyISAM</CODE> 表支持并发的 <CODE>SELECT</CODE> 和 <CODE>INSERT</CODE>,如果在数据文件中没有空闲的块,那你将很少需要对 <CODE>MyISAM</CODE> 表使用 <CODE>INSERT DELAYED</CODE>。查看章节 <A HREF="manual2.html#MyISAM">7.1 <CODE>MyISAM</CODE> 表</A>。
</P>
<P>
当你使用 <CODE>INSERT DELAYED</CODE> 时,客户端将立即得到一个 OK,当表不被任何其它线程使用时,该行将被插入。
</P>
<P>
使用 <CODE>INSERT DELAYED</CODE> 的另一个主要的好处就是,从很多客户端来的插入请求会被打包在一起并写入一个块中。这比做许多单独的插入要快的多。
</P>
<P>
注意,当前的记录行队列是被存储在内存中的,一直到他们被插入到表中。这就意味着,如果你使用强制的方法(<CODE>kill -9</CODE>) 杀死 <CODE>mysqld</CODE>,或者如果意外地死掉,任何没有写到磁盘中的记录行队列都将会丢失!
</P>
<P>
下面详细地描述当你为 <CODE>INSERT</CODE> 或 <CODE>REPLACE</CODE> 使用 <CODE>DELAYED</CODE> 选项时会发生什么。在这个描述中,“线程”是遇到一个 <CODE>INSERT DELAYED</CODE> 命令的线程,“处理器”是处理所有对于一个特定表的 <CODE>INSERT DELAYED</CODE> 语句的线程。
</P>
<UL>
<LI>
当一个线程对一个表执行一个 <CODE>DELAYED</CODE> 语句时,将会创建一个处理器线程用以处理对该表的所有 <CODE>DELAYED</CODE> 语句,除非这样的处理器已经存在。
<P></P>
<LI>
线程检查处理器是否已经获得了一个 <CODE>DELAYED</CODE> 锁;如果还没有,这告诉处理程序去获得。即使其它的线程已在表上加了一个 <CODE>READ</CODE> 或 <CODE>WRITE</CODE> 锁,也能获得 <CODE>DELAYED</CODE> 锁。然而,处理器将等待所有的 <CODE>ALTER TABLE</CODE> 锁或 <CODE>FLUSH TABLES</CODE> 以保证表结构是最新的。
<P></P>
<LI>
线程执行 <CODE>INSERT</CODE> 语句,但是并不将记录行写到表中,它将最终的记录行的副本放到被处理器线程管理的队列中。任何语法错误都会被线程发现并报告给客户程序。
<P></P>
<LI>
客户端不能报告结果记录行中重复次数或 <CODE>AUTO_INCREMENT</CODE> 值;它不能从服务器获得它们,因为 <CODE>INSERT</CODE> 早在插入操作被完成之前就返回了。如果你使用 C API,<CODE>mysql_info()</CODE> 函数也因同样的原因而不能获得任何有意义的信息。
<P></P>
<LI>
当记录行被插入到表中时,二进制的日志文件将被处理器线程更新。对于多记录行的插入,当第一个记录行被插入时,二进制日志被更新。
<P></P>
<LI>
当每写入 <CODE>delayed_insert_limit</CODE> 个记录行后,处理器检查是否仍有任何 <CODE>SELECT</CODE> 语句没有解决。如果是这样,处理器允许在继续之前让这些语句先执行。
<P></P>
<A NAME="IDX1435"></A>
<A NAME="IDX1436"></A>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -