UPDATE 语句html
UPDATE 是修改表中行的 DML 语句。mysql
UPDATE 语句能够用 WITH 子句开头,定义在 UPDATE 中可访问的公共表表达式。sql
单表语法:安全
1. UPDATE [LOW_PRIORITY] [IGNORE] table_reference 2. SET assignment_list 3. [WHERE where_condition] 4. [ORDER BY ...] 5. [LIMIT row_count] 6. 7. value: 8. {expr | DEFAULT} 9. 10. assignment: 11. col_name = value 12. 13. assignment_list: 14. assignment [, assignment] ...
多表语法:ide
1. UPDATE [LOW_PRIORITY] [IGNORE] table_references 2. SET assignment_list 3. [WHERE where_condition]
对于单表语法,UPDATE 语句用新值更新命名表中现有行的列。SET 子句指示要修改的列及其应给定的值。每一个值能够用表达式给定,也可使用关键字 DEFAULT 将列显式设置为其默认值。WHERE 子句(若是给定)指定要更新哪些行。若是没有 WHERE 子句,全部行都将更新。若是指定了 ORDER BY 子句,则按指定的顺序更新行。LIMIT 子句对能够更新的行数进行了限制。函数
对于多表语法,UPDATE 更新 table_references 中每一个表中知足条件的行。每一个匹配的行都会更新一次,即便它与条件匹配屡次。对于多表语法,不能使用 ORDER BY 和 LIMIT。优化
对于分区表,此语句的单表和多表形式都支持使用 PARTITION 选项用做表引用的一部分。此选项接受分区或子分区列表。只检查列出的分区(或子分区)是否匹配,不在这些分区或子分区中的行不会更新,不管它是否知足 where_condition 条件。日志
注意code
与在 INSERT 或 REPLACE 语句中使用 PARTITION 的状况不一样,即便列出的分区(或子分区)中没有与 where_condition 匹配的行,UPDATE ... PARTITION 语句也被认为是成功的。htm
where_condition 是一个表达式,要更新的每一行都必须知足此表达式的条件。
只须要拥有在 UPDATE 语句实际更新引用的列的 UPDATE 权限。对于任何已读取但未修改的列,只须要 SELECT 权限。
UPDATE 语句支持如下修饰符:
● 使用 LOW_PRIORITY 修饰符,UPDATE 的执行将被延迟,直到没有其余客户端从表中读取数据。这只影响只使用表级锁定的存储引擎(如 MyISAM、MEMORY 和 MERGE)。
● 使用 IGNORE 修饰符,即便在更新过程当中发生错误,更新语句也不会停止。不会更新在惟一键值上引起重复键冲突的行。可能致使数据转换错误的值的行将更新为最接近的有效值。
包括 ORDER BY 子句的 UPDATE IGNORE 语句被标记为不安全的基于语句的复制。(这是由于行的更新顺序决定了哪些行被忽略。)当使用基于语句的模式时,这些语句在错误日志中生成警告,在使用 MIXED 模式时,这些语句将使用基于行的格式写入二进制日志。
若是从要在表达式中更新的表中访问列,则 UPDATE 将使用该列的当前值。例如,下面的语句将 col1 设置为比当前值多1:
1. UPDATE t1 SET col1 = col1 + 1;
下面语句中的第二个赋值将 col2 设置为当前(更新的)col1 值,而不是原始 col1 值。结果是 col1 和 col2 的值相同。此行为与标准 SQL 不一样。
1. UPDATE t1 SET col1 = col1 + 1, col2 = col1;
单表 UPDATE 分配一般从左到右进行计算。对于多表更新,不能保证以任何特定的顺序执行分配。
若是将列设置为当前的值,MySQL 会注意到这一点,而且不会更新它。
若是把已声明为 NOT NULL 的列设置为 NULL,则在启用了严格 SQL 模式会出错;不然,该列将设置为列数据类型的隐式默认值,而且警告计数将递增。对于数值类型,隐式默认值为0;对于字符串类型,隐式默认值为空字符串(''),对于日期和时间类型,默认值为“零”。
若是显式更新生成列,则惟一容许的值是 DEFAULT。
UPDATE 返回实际更改的行数。mysql_info() C API 函数返回匹配和更新的行数以及更新过程当中出现的警告数。
可使用 LIMIT row_count 来限制 UPDATE 的范围。LIMIT 子句是匹配行的限制。只要找到知足 WHERE 子句的 row_count 行,语句就会当即中止,而无论这些行是否实际被更改。
若是 UPDATE 语句包含 ORDER BY 子句,则按该子句指定的顺序更新行。这在某些可能致使错误的状况下很是有用。假设表 t 包含一个具备惟一索引的列 id。如下语句可能会出现重复键错误而失败,这取决于行的更新顺序:
1. UPDATE t SET id = id + 1;
例如,若是表在 id 列中包含值 1 和 2,而且在 2 更新为 3 以前 1 先更新为2,则会发生错误。若要避免此问题,请添加 ORDER BY 子句,使 id 值较大的行在值较小的行以前更新:
1. UPDATE t SET id = id + 1 ORDER BY id DESC;
还能够执行覆盖多个表的 UPDATE 操做。可是,不能将 ORDER BY 或 LIMIT 用于多表更新。table_references 子句列出了链接中涉及的表。
1. UPDATE items,month SET items.price=month.price 2. WHERE items.id=month.id;
前面的示例显示了使用逗号运算符的内部联接,但多表更新语句可使用 SELECT 语句中容许的任何类型的联接,例如 LEFT JOIN。
若是使用包含 InnoDB 表且有外键约束的多表 UPDATE 语句,那么 MySQL 优化器可能会按照与父/子关系不一样的顺序处理表。在本例中,语句失败并回滚。相反,更新一个表并依赖 InnoDB 提供的 ON UPDATE 功能来相应地修改其余表。
不能在更新一个表的同时直接从子查询中对同一表进行选择。能够经过使用多表更新来解决此问题,其中一个表是从实际要更新的表派生的,并使用别名引用派生表。假设但愿更新一个名为 items 的表,该表是使用如下语句定义的:
1. CREATE TABLE items ( 2. id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, 3. wholesale DECIMAL(6,2) NOT NULL DEFAULT 0.00, 4. retail DECIMAL(6,2) NOT NULL DEFAULT 0.00, 5. quantity BIGINT NOT NULL DEFAULT 0 6. );
若要下降利润为30%或更高而且库存少于100的商品的零售价,能够尝试使用以下所示的 UPDATE 语句,该语句在 WHERE 子句中使用子查询。以下所示,此语句不起做用:
1. mysql> UPDATE items 2. > SET retail = retail * 0.9 3. > WHERE id IN 4. > (SELECT id FROM items 5. > WHERE retail / wholesale >= 1.3 AND quantity > 100); 6. ERROR 1093 (HY000): You can't specify target table 'items' for update in FROM clause
替代方法是可使用多表更新,其中子查询被移动到要更新的表列表中,使用别名在最外层的 WHERE 子句中引用它,以下所示:
1. UPDATE items, 2. (SELECT id FROM items 3. WHERE id IN 4. (SELECT id FROM items 5. WHERE retail / wholesale >= 1.3 AND quantity < 100)) 6. AS discounted 7. SET items.retail = items.retail * 0.9 8. WHERE items.id = discounted.id;
由于默认状况下,优化器会尝试将派生表 discounted 合并到最外层的查询块中,只有在强制物化派生表时,这才有效。能够在运行更新以前将 optimizer_switch 系统变量的 derived_merge 标志设置为 off,或使用 NO_MERGE 优化器提示来执行此操做,以下所示:
1. UPDATE /*+ NO_MERGE(discounted) */ items, 2. (SELECT id FROM items 3. WHERE retail / wholesale >= 1.3 AND quantity < 100) 4. AS discounted 5. SET items.retail = items.retail * 0.9 6. WHERE items.id = discounted.id;
在这种状况下使用优化器提示的好处是,它只适用于使用它的查询块中,所以在执行 UPDATE 以后,没必要再次更改 optimizer_switch 的值。
另外一种多是重写子查询,使其不使用 IN 或 EXISTS,以下所示:
1. UPDATE items, 2. (SELECT id, retail / wholesale AS markup, quantity FROM items) 3. AS discounted 4. SET items.retail = items.retail * 0.9 5. WHERE discounted.markup >= 1.3 6. AND discounted.quantity < 100 7. AND items.id = discounted.id;
在这种状况下,子查询默认状况下是物化的,而不是合并的,所以不须要禁用派生表的合并。