MySQL与标准SQL的不同

我们尽力使MySQL Server遵循ANSI SQL标准和ODBC SQL标准,但在某些情况下,MySQL Server会以不同的方式执行操作。

  • MySQL和标准SQL权限系统之间存在一些差异。例如,在MySQL中,当你删除一个表时,该表的权限不会自动被撤销。你必须显式地使用REVOKE语句来撤销该表的权限。这与标准SQL在处理表权限上有所不同。
  • CAST() 函数不支持将数据类型转换为 REAL 或 BIGINT。
SELECT INTO TABLE 的差异 

MySQL Server 不支持 Sybase SQL 的 SELECT ... INTO TABLE 扩展语法。相反,MySQL Server 支持 INSERT INTO ... SELECT 的标准 SQL 语法,其基本上是相同的功能。

INSERT INTO tbl_temp2 (fld_id)
 SELECT tbl_temp1.fld_order_id
 FROM tbl_temp1 WHERE tbl_temp1.fld_order_id > 100;

 另外,你还可以使用 SELECT ... INTO OUTFILE 或 CREATE TABLE ... SELECT。

你可以使用 SELECT ... INTO 与用户定义的变量一起使用。相同的语法也可以在存储过程中使用游标和本地变量。

UPDATE 的差异

如果你在表格中的更新语句中的表达式中访问了被更新的列,UPDATE 会使用该列的当前值。下面语句中的第二个赋值将 col2 设置为当前(更新后)的 col1 值,而不是原始的 col1 值。结果是 col1 和 col2 具有相同的值。这种行为与标准 SQL 不同。

UPDATE t1 SET col1 = col1 + 1, col2 = col1;
 FOREIGN KEY 约束的差异

MySQL 对 FOREIGN KEY 约束的实现与 SQL 标准在以下关键方面存在差异:

  • 如果父表中有多行具有相同的参考键值,InnoDB 在外键检查时会将其他具有相同键值的父行视为不存在。例如,如果你定义了一个 RESTRICT 类型的约束,并且有一个具有多个父行的子行,那么 InnoDB 不允许删除任何一个父行。
  • 如果 ON UPDATE CASCADE 或 ON UPDATE SET NULL 在同一级联期间递归更新了之前已更新过的同一张表,则其行为类似于 RESTRICT。这意味着你不能使用自引用的 ON UPDATE CASCADE 或 ON UPDATE SET NULL 操作。这是为了防止由级联更新引起的无限循环。但是,自引用的 ON DELETE SET NULL 和自引用的 ON DELETE CASCADE 是可以的。级联操作不可嵌套超过15层深度。
  • 在执行插入、删除或更新多行的 SQL 语句时,外键约束(就像唯一约束一样)会逐行进行检查。在进行外键检查时,InnoDB 会对必须检查的子记录或父记录设置共享行级锁。MySQL 会立即检查外键约束,而不是推迟到事务提交之后。根据 SQL 标准,应该是推迟检查的默认行为。也就是说,在整个 SQL 语句被处理之后才会进行约束检查。这意味着无法使用外键删除自引用的行。
  • 没有任何存储引擎,包括 InnoDB,能够识别或强制执行引用完整性约束定义中使用的 MATCH 子句。使用显式的 MATCH 子句不会产生指定的效果,并且会导致 ON DELETE 和 ON UPDATE 子句被忽略。应避免指定 MATCH 子句。
    SQL标准中的MATCH子句控制在将复合(多列)外键与引用表中的主键进行比较时如何处理NULL值。MySQL基本上实现了MATCH SIMPLE定义的语义,允许外键全部或部分为NULL。在这种情况下,即使不匹配引用表中的任何行,仍然可以插入包含此类外键的(子表)行。
  • 为了提高性能,MySQL要求引用的列被索引。然而,MySQL不强制要求引用的列是唯一的或声明为 NOT NULL。引用非唯一键的外键约束不符合标准SQL,而是InnoDB的扩展。另一方面,NDB存储引擎要求任何作为外键引用的列必须有一个明确的唯一键(或主键)。

    对于UPDATE或DELETE CASCADE等操作,对非唯一键或包含NULL值的外键引用的处理未定义得很好。建议您只使用引用 UNIQUE(包括 PRIMARY)和 NOT NULL 键的外键。

  • 对于不支持外键的存储引擎(如MyISAM),MySQL服务器会解析并忽略外键规范。

  • MySQL解析但忽略“内联REFERENCES规范”(如SQL标准定义的),其中引用是作为列规范的一部分定义的。只有在作为单独的FOREIGN KEY规范的一部分指定时,MySQL才接受REFERENCES子句。
    将列定义为使用REFERENCES tbl_name(col_name)子句没有实际效果,只是作为备忘录或注释,提醒您当前正在定义的列是要引用另一个表中的列。使用此语法时,需要注意以下几点:

    • MySQL不执行任何检查来确保col_name实际存在于tbl_name中(甚至不会验证tbl_name本身是否存在)。

    • MySQL不对tbl_name执行任何操作,例如根据对您正在定义的表中行的操作来删除行;换句话说,这种语法不会引发任何ON DELETE或ON UPDATE行为。(尽管您可以在REFERENCES子句中编写ON DELETE或ON UPDATE子句,但也会被忽略。)

    • 这种语法创建了一个列,但不会创建任何类型的索引或键。

        您可以将这样创建的列用作连接列,就像在这里显示的那样: 

CREATE TABLE person (
 id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
 name CHAR(60) NOT NULL,
 PRIMARY KEY (id)
);

CREATE TABLE shirt (
 id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
 style ENUM('t-shirt', 'polo', 'dress') NOT NULL,
 color ENUM('red', 'blue', 'orange', 'white', 'black') NOT NULL,
 owner SMALLINT UNSIGNED NOT NULL REFERENCES person(id),
 PRIMARY KEY (id)
);
INSERT INTO person VALUES (NULL, 'Antonio Paz');
SELECT @last := LAST_INSERT_ID();
INSERT INTO shirt VALUES
(NULL, 'polo', 'blue', @last),
(NULL, 'dress', 'white', @last),
(NULL, 't-shirt', 'blue', @last);
INSERT INTO person VALUES (NULL, 'Lilliana Angelovska');
SELECT @last := LAST_INSERT_ID();
INSERT INTO shirt VALUES
(NULL, 'dress', 'orange', @last),
(NULL, 'polo', 'red', @last),
(NULL, 'dress', 'blue', @last),
(NULL, 't-shirt', 'white', @last);
SELECT * FROM person;
+----+---------------------+
| id | name                |
+----+---------------------+
| 1  | Antonio Paz          |
| 2  | Lilliana Angelovska  |
+----+---------------------+
SELECT * FROM shirt;
+----+---------+--------+-------+
| id | style   | color | owner  |
+----+---------+--------+-------+
| 1  | polo    | blue  | 1      |
| 2  | dress   | white | 1      |
| 3  | t-shirt | blue  | 1      |
| 4  | dress   | orange| 2      |
| 5  | polo    | red   | 2      |
| 6  | dress   | blue  | 2      |
| 7  | t-shirt | white | 2      |
+----+---------+--------+-------+
SELECT s.* FROM person p INNER JOIN shirt s
 ON s.owner = p.id
 WHERE p.name LIKE 'Lilliana%'
 AND s.color <> 'white';
+----+-------+--------+-------+
| id | style | color  | owner |
+----+-------+--------+-------+
| 4  | dress | orange | 2     |
| 5  | polo  | red    | 2     |
| 6  | dress | blue   | 2     |
+----+-------+--------+-------+

当以这种方式使用时,“REFERENCES”子句不会显示在SHOW CREATE TABLE或DESCRIBE的输出中。

SHOW CREATE TABLE shirt\G
*************************** 1. row ***************************
Table: shirt
Create Table: CREATE TABLE `shirt` (
`id` smallint(5) unsigned NOT NULL auto_increment,
`style` enum('t-shirt','polo','dress') NOT NULL,
`color` enum('red','blue','orange','white','black') NOT NULL,
`owner` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
'--' 作为注释起始符号

 标准SQL使用C语法中的 /* this is a comment */ 来进行注释,MySQL服务器也支持这种语法。MySQL还支持扩展此语法的方式,以便将特定于MySQL的SQL嵌入到注释中。

标准SQL使用“--”作为开始注释的序列。而MySQL服务器使用#作为开始注释的字符。MySQL服务器也支持一种变体的--注释风格。即--开始注释序列必须后跟一个空格(或控制字符,如换行符)。此空格是必需的,以防止在自动生成的SQL查询中出现以下构造的问题,其中我们自动插入payment的值用于payment:

UPDATE account SET credit=credit-payment

考虑如果payment有一个负值(如-1),会发生什么情况:

UPDATE account SET credit=credit--1

credit--1是SQL中的一个有效表达式,但是--被解释为注释的开始,表达式的一部分被丢弃了。结果是一个语句的含义与原意完全不同:

UPDATE account SET credit=credit

该语句根本没有改变任何值。这说明允许以--开头的注释可能会产生严重的后果。

根据我们的实现,在MySQL服务器中,使用--作为注释起始符号时,后面需要加上一个空格才能被识别为注释的开始序列。因此,credit--1 是可以安全使用的。

你可能感兴趣的:(MySQL,mysql)