MySQL 基本概念介绍

2021-04-30 database mysql

在此主要介绍下与数据库相关的一些操作,其中有一部分是与 MySQL 相关的功能。

简介

sql logo

SQL-92 是最常用的 Structured Query Language, SQL 标准,其定义了一些常见的语法等,详细的可参考 SQL-92,常见的 SQL 操作包括如下:

  • DDL 数据库模式定义语言,create 。
  • DML 数据操纵语言,insert、delete、update 。
  • DCL 数据库控制语言 ,grant、remove 。
  • DQL 数据库查询语言,select 。

不过不同的数据库对 SQL-92 标准会有所扩展,这也就造成了一些数据库操作的不兼容,或者是一些细节上的差异。

外键

创建外键的语法规则如下:

[CONSTRAINT symbol] FOREIGN KEY [id] (index_col_name, ...)
    REFERENCES tbl_name (index_col_name, ...)
    [ON DELETE {RESTRICT | CASCADE | SET NULL | NO ACTION}]
    [ON UPDATE {RESTRICT | CASCADE | SET NULL | NO ACTION}]

外键维护数据完整性的 5 种方式:

  1. CASCADE 从父表删除或更新且自动删除或更新子表中匹配的行,可以为 ON DELETE CASCADEON UPDATE CASCADE
  2. SET NULL 从父表删除或更新行,设置子表中的外键列为 NULL,需要对应列也可为 NULL
  3. NO ACTION SQL-92 标准中,如果有外键的,那么删除或更新主键时会报错;
  4. RESTRICT 拒绝对父表的删除或更新操作。一些数据库有延期检查,一般 NO ACTION 是一个延期检查;而在 MySQL 中,外键约束是被立即检查的,所以 RESTRICT 与上述同样。
  5. SET DEFAULT 这个动作被解析程序识别,但 InnoDB 不支持包含 ON DELETE SET DEFAULTON UPDATE SET DEFAULT 子句的表定义。

如下是测试用例:

----- 创建用户表
mysql> CREATE TABLE `user` (
  `id` int(11) NOT NULL auto_increment COMMENT '用户ID',
  `name` varchar(50) NOT NULL default '' COMMENT '名字',
  `sex` int(1) NOT NULL default '0' COMMENT '0为男,1为女',
  PRIMARY KEY  (`id`)
) ENGINE=innodb DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
----- 写入测试数据
mysql> INSERT INTO user(name, sex) VALUES("andy", 0),("lily", 1);

----- 创建订单表
mysql> CREATE TABLE `order` (
  `order_id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '订单ID',
  `u_id` INT(11) NOT NULL DEFAULT '0' COMMENT '用户ID',
  `username` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '用户名',
  `money` INT(11) NOT NULL DEFAULT '0' COMMENT '钱数',
  `datetime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '生成时间',
  PRIMARY KEY(`order_id`),
  INDEX (`u_id`),
  FOREIGN KEY order_f_key (u_id) REFERENCES user(id)
) ENGINE=innodb DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
mysql> INSERT INTO `order`(`u_id`, `username`, `money`, `datetime`)
       VALUES('1', 'andy','10', CURRENT_TIMESTAMP);

----- 由于order表中有依赖,导致删除user表时失败
mysql> DELETE FROM user WHERE id =1;
----- 写入数据时由于user表中不存在,导致写入失败
mysql> INSERT INTO `order`(`u_id`, `username`, `money`, `datetime`)
       VALUES('5', 'foobar', '123', CURRENT_TIMESTAMP);

----- MySQL中没有修改外键操作,需要先删除再重新添加
mysql> ALTER TABLE `order` DROP FOREIGN KEY order_ibfk_1;
mysql> ALTER TABLE `order` ADD FOREIGN KEY(u_id) REFERENCES user(id)
       ON DELETE CASCADE ON UPDATE CASCADE;

mysql> REPLACE INTO `order`(`u_id`, `username`, `money`, `datetime`)
       VALUES('2', 'andy','10', CURRENT_TIMESTAMP);

sql_mode

sql_mode 是个很容易被忽视的变量,在生产环境必须将这个值设置为严格模式,所以开发、测试环境的数据库也必须要设置,这样在开发测试阶段就可以发现问题。

----- 查看变量
mysql> SHOW VARIABLES LIKE 'sql_mode%'\G
 *************************** 1. row ***************************
 Variable_name: sql_mode
         Value: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,
         NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
         1 row in set (0.01 sec)

----- 设置变量
mysql> SET GLOBAL sql_mode='';

简单列举如下常用的,详细可以参考官方手册 MySQL Reference Manual - Server SQL Modes

  • NO_ZERO_IN_DATE 在严格模式下,不允许日期和月份为零。
  • NO_ZERO_DATE 不允许插入零日期,插入零日期会抛出错误而不是警告。
  • NO_AUTO_CREATE_USER 禁止 GRANT 创建密码为空的用户。
  • ONLY_FULL_GROUP_BY 参考如下。

ONLY_FULL_GROUP_BY

对于 GROUP BY 聚合操作,如果在 SELECT 中的列没有在 GROUP BY 中出现 (可以是聚合函数),那么认为这个 SQL 是不合法的。

例如 SELECT language_id, COUNT(1), length FROM film GROUP BY language_id; 是不合法的,原因是 MySQL 允许在 SELECT 列表中存在除聚集函数或 GROUP BY 以外的表达式,但是这些表达式的结果并不确定,通常也就没有太多意义,反而可能会导致错误。

实际上 SQLServer、Oracle、PostgreSQL 基本都不支持这种语法,为此,MySQL 5.7 修订了这一语义。另外,需要注意 SELECT id+1 FROM tt GROUP BY 1+id; 这种是不允许的,而 SELECT id+1 FROM tt GROUP BY id+1; 则可以。

其它

注释

在 MySQL 中可以通过 # (从开始到结束)、/* ... */ (可以多行) 表示注释内容;从 MySQL-3.23 版本开始,可以通过 /*! ... */ 这种特有的注释方式标示 MySQL 特有特性。

MySQL 会解析其中的关键字,而其它数据库则会视为注释,从而保证兼容性。另外,从 3.23 开始支持 "-- " 格式的注释,功能与 # 类似;需要注意的是,双短划线之后有一个空格。

接下来,重点说下 /*! ... */ 这个注释,简言之,MySQL 会执行其中的内容,例如,MySQL 支持 STRAIGHT_JOIN 写法,而其它数据库可能不支持,那么就可以写成 SELECT /*! STRAIGHT_JOIN */ col1 FROM table1,table2 WHERE... 这种方式。

另外,可以在叹号后面添加版本号,表示只有当 MySQL 的版本大于等于该版本时才会执行,例如只有 MySQL-3.23.02 之后才支持 TEMPORARY,那么可以写为 CREATE /*!32302 TEMPORARY */ TABLE t (a INT);

其它的示例 CREATE DATABASE blog /*!40100 DEFAULT CHARACTER SET latin1 */;

show tables

默认在使用 LIKE 过滤时,不能使用 AND/OR 等条件,可以通过如下方式添加过滤条件。

----- 只能使用单个like语句
mysql> SHOW TABLES LIKE 'host%';

----- 如果要使用多个,需要使用WHERE子句,其中FROM子句可以省略
mysql> SHOW TABLES FROM `sys` WHERE `Tables_in_sys` LIKE 'user%' OR `Tables_in_sys` LIKE 'host%';

参考