• [技术干货] MySQL锁等待和死锁
    使用数据库时,有时会出现死锁。对于实际应用来说,就是出现系统卡顿。死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。就是所谓的锁资源请求产生了回路现象,即死循环,此时称系统处于死锁状态或系统产生了死锁。常见的报错信息为“Deadlock found when trying to get lock...”。死锁发生以后,只有部分或完全回滚其中一个事务,才能打破死锁。多数情况下只需要重新执行因死锁回滚的事务即可。下面我们通过一个实例来了解死锁是如何产生的。例 为了方便读者阅读,操作之前我们先查询 tb_student 表的数据和表结构。mysql> SELECT * FROM tb_student; +----+------+------+------+------+ | id | name | age  | sex  | num  | +----+------+------+------+------+ |  1 | 张三 |   31 | 男   |    4 | |  2 | 李四 |   28 | 男   |    4 | |  3 | 王五 |   13 | 女   |    4 | |  4 | 张四 |   13 | 女   |    4 | |  5 | 王四 |   15 | 男   |    4 | |  6 | 赵六 |   12 | 女   |    4 | +----+------+------+------+------+ 6 rows in set (0.01 sec) mysql> DESC tb_student; +-------+-------------+------+-----+---------+----------------+ | Field | Type        | Null | Key | Default | Extra          | +-------+-------------+------+-----+---------+----------------+ | id    | int(4)      | NO   | PRI | NULL    | auto_increment | | name  | varchar(25) | NO   |     | NULL    |                | | age   | int(11)     | YES  | MUL | NULL    |                | | sex   | char(1)     | YES  |     | NULL    |                | | num   | int(11)     | YES  |     | NULL    |                | +-------+-------------+------+-----+---------+----------------+ 5 rows in set (0.00 sec)以下操作需要打开两个会话窗口,即下面所提到的 A窗口和 B窗口。在 A窗口中执行以下命令:mysql> BEGIN; mysql> UPDATE tb_student SET num=5 WHERE age=13; Query OK, 2 rows affected (0.04 sec) Rows matched: 2  Changed: 2  Warnings: 0紧接着在 B窗口中执行以下命令。由于 age 是索引字段,与 A窗口中更新的是不同行的数据,所以这时不会出现锁等待现象。mysql> BEGIN; mysql> UPDATE tb_student SET num=8 WHERE age=15; Query OK, 1 row affected (0.01 sec) Rows matched: 1  Changed: 1  Warnings: 0然后在 A窗口中,执行以下命令,这时就会出现锁等待现象了。mysql> UPDATE tb_student SET num=10 WHERE age=15;最后在 B窗口中,执行以下命令,这时会出现相互等待资源的现象,也就是死锁现象。mysql> UPDATE tb_student SET num=12 WHERE age=13; ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction我们可以通过 SHOW ENGINE INNODB STATUS 命令查看死锁的信息,运行结果如下(这里只展示了部分信息):LATEST DETECTED DEADLOCK ------------------------ 2020-08-24 16:22:23 0x3944 *** (1) TRANSACTION: TRANSACTION 22656, ACTIVE 108 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 5 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 2 MySQL thread id 33, OS thread handle 8808, query id 1689 localhost ::1 root updating UPDATE tb_student SET num=10 WHERE age=15 *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 197 page no 8 n bits 80 index index_age of table `test`.`tb_student` trx id 22656 lock_mode X waiting Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 4; hex 8000000f; asc     ;; 1: len 4; hex 80000005; asc     ;; ......通过以上日志,我们就能确定造成死锁的事务和 SQL 语句。死锁检测InnoDB 的并发写操作会触发死锁,同时 InnoDB 也提供了死锁检测机制。通过设置 innodb_deadlock_detect 参数的值来控制是否打开死锁检测。innodb_deadlock_detect = ON :默认值,打开死锁检测。数据库发生死锁时,系统会自动回滚其中的某一个事务,让其它事务可以继续执行。innodb_deadlock_detect = OFF:关闭死锁检测。发生死锁时,系统会用锁等待来处理。锁等待是指在事务过程中产生的锁,其它事务需要等待上一个事务释放锁,才能占用该资源。如果该事务一直不释放,就需要持续等待下去,直到超过了锁等待时间。当超过锁等待允许的最大时间,就会出现死锁,然后当前事务执行失败,自动执行回滚操作。MySQL 通过 innodb_lock_wait_timeout 参数控制锁等待的时间,单位是秒。mysql> SHOW VARIABLES LIKE '%innodb_lock_wait%'; +--------------------------+-------+ | Variable_name            | Value | +--------------------------+-------+ | innodb_lock_wait_timeout | 120   | +--------------------------+-------+ 1 row in set, 1 warning (0.02 sec)在实际应用中,我们要尽量防止锁等待现象的发生,下面介绍几种避免死锁的方法:如果不同程序会并发存取多个表,或者涉及多行记录时,尽量约定以相同的顺序访问表,这样可以大大降低死锁的发生。业务中要及时提交或者回滚事务,可减少死锁产生的概率。在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率。对于非常容易产生死锁的业务部分,可以尝试使用升级锁粒度,通过表锁定来减少死锁产生的概率(表级锁不会产生死锁)。
  • [技术干货] MySQL Event事件(定时任务)
    在数据库管理中,经常要周期性的执行某一命令或 SQL 语句,于是 MySQL 5.1 版本以后就提供了事件,它可以很方便的实现 MySQL 数据库的计划任务,定期运行指定命令,使用起来非常简单方便。事件(Event)也可称为事件调度器(Event Scheduler),是用来执行定时任务的一组 SQL 集合,可以通俗理解成 MySQL 中的定时器。一个事件可调用一次,也可周期性的启动。事件可以作为定时任务调度器,取代部分原来只能用操作系统的计划任务才能执行的工作。另外,更值得一提的是,MySQL 的事件可以实现每秒钟执行一个任务,非常适合对实时性要求较高的环境,而操作系统的计划任务只能精确到每分钟一次。事件和触发器类似,都是在某些事情发生时启动。当数据库启动一条语句的时候,触发器就启动了,而事件是根据调度事件来启动的。由于他们彼此相似,所以事件也称为临时性触发器。查看事件是否开启在 MySQL 中,调度器 event_scheduler 负责调用事件。我们可以通过以下几种命令查看事件是否开启,一般情况下默认值为 OFF。SQL 命令和运行结果如下:mysql> SHOW VARIABLES LIKE 'event_scheduler'; +-----------------+-------+ | Variable_name   | Value | +-----------------+-------+ | event_scheduler | OFF   | +-----------------+-------+ 1 row in set, 1 warning (0.02 sec) mysql> SELECT @@event_scheduler; +-------------------+ | @@event_scheduler | +-------------------+ | OFF               | +-------------------+ 1 row in set (0.00 sec) mysql> SHOW PROCESSLIST; +----+------+-----------------+------+---------+------+----------+------------------+ | Id | User | Host            | db   | Command | Time | State    | Info             | +----+------+-----------------+------+---------+------+----------+------------------+ |  2 | root | localhost:56279 | NULL | Query   |    0 | starting | SHOW PROCESSLIST | +----+------+-----------------+------+---------+------+----------+------------------+ 1 row in set (0.01 sec)从结果可以看出,事件没有开启。因为参数 event_scheduler 的值为 OFF,并且在 PROCESSLIST 中查看不到 event_scheduler 的信息。如果参数 event_scheduler 的值为 ON,或者在 PROCESSLIST 中显示了 event_scheduler 的信息,则说明事件已经开启。开启事件开启事件主要通过以下两种方式实现。 1)通过设置全局参数修改可以使用 SET GLOBAL 命令设定全局变量 event_scheduler 的值,开启或关闭事件。将 event_scheduler 参数的值设置为 ON,表示开启事件;设置为 OFF,则关闭事件。例如,要开启事件可以在命令行窗口中输入以下命令。mysql> SET GLOBAL event_scheduler = ON ; Query OK, 0 rows affected (0.06 sec) mysql> SHOW VARIABLES LIKE 'event_scheduler'; +-----------------+-------+ | Variable_name   | Value | +-----------------+-------+ | event_scheduler | ON    | +-----------------+-------+ 1 row in set, 1 warning (0.01 sec)结果显示,event_scheduler 的值为 ON,表示事件已经开启。通过 SET GLOBAL 命令开启或关闭事件,MySQL 重启服务后事件又会回到原来的状态,如果想要始终开启或关闭事件,可以修改 MySQL 配置文件。2)更改配置文件在 MySQL 配置文件中找到 [mysqld] 选项,然后在下面添加以下代码开启事件。event_scheduler = ON在配置文件中添加代码并保存文件后,重启 MySQL 服务才能生效。通过该方法开启或关闭事件,重启 MySQL 服务后,不会回到原来的状态。例如,此时重启 MySQL 服务器,然后查看事件是否开启。mysql> SHOW VARIABLES LIKE 'event_scheduler'; +-----------------+-------+ | Variable_name   | Value | +-----------------+-------+ | event_scheduler | ON    | +-----------------+-------+ 1 row in set, 1 warning (0.01 sec)结果显示,参数 event_scheduler 的值为 ON,表示已经开启。
  • [技术干货] MySQL子查询改写为表连接
    子查询如递归函数一样,有时侯能达到事半功倍的效果,但是其执行效率较低。与表连接相比,子查询比较灵活,方便,形式多样,适合作为查询的筛选条件,而表连接更适合查看多表的数据。一般情况下,子查询会产生笛卡儿积,表连接的效率要高于子查询。因此在编写 SQL 语句时应尽量使用连接查询。在上一篇帖子《MySQL子查询》介绍表连接(内连接和外连接等)都可以用子查询替换,但反过来却不一定,有的子查询不能用表连接来替换。下面来介绍哪些子查询的查询命令可以改写为表连接。在检查那些倾向于编写成子查询的查询语句时,可以考虑将子查询替换为表连接,看看连接的效率是不是比子查询更好些。同样,如果某条使用子查询的 SELECT 语句需要花费很长时间才能执行完毕,那么可以尝试把它改写为表连接,看看执行效果是否有所改善。下面讨论具体该如何做。1. 改写用来查询匹配值的子查询下面这条示例语句包含一个子查询,它会把 score 表里的考试成绩查询出来:SELECT * FROM scoreWHERE grade_id IN (SELECT id FROM grade WHERE category = 'Java');在编写以上语句时,可以不使用子查询,而是把它转换为一个简单的连接:SELECT score.* FROM score INNER JOIN gradeON score.grade_id = grade.id WHERE grade.category = 'Java';再来看另一个示例。下面这条查询语句可以把所有女生的考试成绩查询出来:SELECT * from scoreWHERE student_id IN (SELECT student_id FROM student WHERE sex = 'F') ;这条语句可以转换为以下连接:SELECT score.* FROM score INNER JOIN studentON score.student_id = student.student_id WHERE student.sex = 'F' ;我们可以发现这些子查询语句都遵从这样一种形式:SELECT * FROM table1WHERE column1 IN (SELECT column2a FROM table2 WHERE column2b = value);其中,column1 代表 table1 中的字段,column2a 和 column2b 代表 table2 表中的字段。这类查询都可以被转换为下面这种形式的连接查询:SELECT table1. * FROM table1 INNER JOIN table2ON table1. column1 = table. column2a WHERE table2. column2b = value;在某些场合,子查询和关联查询可能会返回不同的结果。比如,当 table2 包含 column2a 的多个实例时,就会发生这种情况。这种形式的子查询只会为每个 column2a 值生成一个实例,而连接操作会为所有值生成实例,并且其输出会包含重复行。如果想要防止这种重复记录出现,就要在编写连接查询语句时使用 SELECT DISTINCT,而不能使用 SELECT。2. 改写用来查询非匹配(缺失)值的子查询另一种常见的子查询语句类型是:把存在于某个表里,但在另一个表里并不存在的那些值查找出来。“哪些值不存在”有关的问题通常都可以用 LEFT JOIN 来解决。如下语句用来测试哪些学生没有出现在 absence 表里(用于查找全勤学生):SELECT * FROM studentWHERE student_id NOT IN (SELECT student_id FROM absence) ;以上查询语句可以使用 LEFT JOIN 来改写:SELECT student.* FROM student LEFT JOIN absenceON student.student_id = absence.student_id WHERE absence.student_ id IS NULL;通常情况下,如果子查询语句符合如下所示的形式:SELECT * FROM table1WHERE column1 NOT IN ( SELECT column2 FROM table2) ;那么可以把它改写为下面这样的连接查询:SELECT table1.* FROM table1 LEFT JOIN table2ON table1.column1 = table2.column2 WHERE table2.column2 IS NULL;这里需要假设 table2.column2 被定义成了 NOT NULL 的。与 LEFT JOIN 相比,子查询更加直观。大部分人都可以毫无困难地理解“没被包含在...里面”的含义,因为它不是数据库编程技术带来的新概念。而“左连接”有所不同,很难用自然语言直观地描述出它的含义。
  • [技术干货] MySQL子查询
    子查询是 MySQL 中比较常用的查询方法,通过子查询可以实现多表查询。子查询指将一个查询语句嵌套在另一个查询语句中。子查询可以在 SELECT、UPDATE 和 DELETE 语句中使用,而且可以进行多层嵌套。在实际开发时,子查询经常出现在 WHERE 子句中。子查询在 WHERE 中的语法格式如下:WHERE <表达式> <操作符> (子查询)其中,操作符可以是比较运算符和 IN、NOT IN、EXISTS、NOT EXISTS 等关键字。1)IN | NOT IN当表达式与子查询返回的结果集中的某个值相等时,返回 TRUE,否则返回 FALSE;若使用关键字 NOT,则返回值正好相反。2)EXISTS | NOT EXISTS用于判断子查询的结果集是否为空,若子查询的结果集不为空,返回 TRUE,否则返回 FALSE;若使用关键字 NOT,则返回的值正好相反。例 1使用子查询在 tb_students_info 表和 tb_course 表中查询学习 Java 课程的学生姓名,SQL 语句和运行结果如下。mysql> SELECT name FROM tb_students_info      -> WHERE course_id IN (SELECT id FROM tb_course WHERE course_name = 'Java'); +-------+ | name  | +-------+ | Dany  | | Henry | +-------+ 2 rows in set (0.01 sec)结果显示,学习 Java 课程的只有 Dany 和 Henry。上述查询过程也可以分为以下 2 步执行,实现效果是相同的。1)首先单独执行内查询,查询出 tb_course 表中课程为 Java 的 id,SQL 语句和运行结果如下。mysql> SELECT id FROM tb_course      -> WHERE course_name = 'Java'; +----+ | id | +----+ |  1 | +----+ 1 row in set (0.00 sec)可以看到,符合条件的 id 字段的值为 1。2)然后执行外层查询,在 tb_students_info 表中查询 course_id 等于 1 的学生姓名。SQL 语句和运行结果如下。mysql> SELECT name FROM tb_students_info      -> WHERE course_id IN (1); +-------+ | name  | +-------+ | Dany  | | Henry | +-------+ 2 rows in set (0.00 sec)习惯上,外层的 SELECT 查询称为父查询,圆括号中嵌入的查询称为子查询(子查询必须放在圆括号内)。MySQL 在处理上例的 SELECT 语句时,执行流程为:先执行子查询,再执行父查询。例 2与例 1 类似,在 SELECT 语句中使用 NOT IN 关键字,查询没有学习 Java 课程的学生姓名,SQL 语句和运行结果如下。mysql> SELECT name FROM tb_students_info      -> WHERE course_id NOT IN (SELECT id FROM tb_course WHERE course_name = 'Java'); +--------+ | name   | +--------+ | Green  | | Jane   | | Jim    | | John   | | Lily   | | Susan  | | Thomas | | Tom    | | LiMing | +--------+ 9 rows in set (0.01 sec)可以看出,运行结果与例 1 刚好相反,没有学习 Java 课程的是除了 Dany 和 Henry 之外的学生。例 3使用=运算符,在 tb_course 表和 tb_students_info 表中查询出所有学习 Python 课程的学生姓名,SQL 语句和运行结果如下。mysql> SELECT name FROM tb_students_info     -> WHERE course_id = (SELECT id FROM tb_course WHERE course_name = 'Python'); +------+ | name | +------+ | Jane | +------+ 1 row in set (0.00 sec)结果显示,学习 Python 课程的学生只有 Jane。例 4使用<>运算符,在 tb_course 表和 tb_students_info 表中查询出没有学习 Python 课程的学生姓名,SQL 语句和运行结果如下。mysql> SELECT name FROM tb_students_info     -> WHERE course_id <> (SELECT id FROM tb_course WHERE course_name = 'Python'); +--------+ | name   | +--------+ | Dany   | | Green  | | Henry  | | Jim    | | John   | | Lily   | | Susan  | | Thomas | | Tom    | | LiMing | +--------+ 10 rows in set (0.00 sec)可以看出,运行结果与例 3 刚好相反,没有学习 Python 课程的是除了 Jane 之外的学生。例 5查询 tb_course 表中是否存在 id=1 的课程,如果存在,就查询出 tb_students_info 表中的记录,SQL 语句和运行结果如下。mysql> SELECT * FROM tb_students_info     -> WHERE EXISTS(SELECT course_name FROM tb_course WHERE id=1); +----+--------+------+------+--------+-----------+ | id | name   | age  | sex  | height | course_id | +----+--------+------+------+--------+-----------+ |  1 | Dany   |   25 | 男   |    160 |         1 | |  2 | Green  |   23 | 男   |    158 |         2 | |  3 | Henry  |   23 | 女   |    185 |         1 | |  4 | Jane   |   22 | 男   |    162 |         3 | |  5 | Jim    |   24 | 女   |    175 |         2 | |  6 | John   |   21 | 女   |    172 |         4 | |  7 | Lily   |   22 | 男   |    165 |         4 | |  8 | Susan  |   23 | 男   |    170 |         5 | |  9 | Thomas |   22 | 女   |    178 |         5 | | 10 | Tom    |   23 | 女   |    165 |         5 | | 11 | LiMing |   22 | 男   |    180 |         7 | +----+--------+------+------+--------+-----------+ 11 rows in set (0.01 sec)由结果可以看到,tb_course 表中存在 id=1 的记录,因此 EXISTS 表达式返回 TRUE,外层查询语句接收 TRUE 之后对表 tb_students_info 进行查询,返回所有的记录。EXISTS 关键字可以和其它查询条件一起使用,条件表达式与 EXISTS 关键字之间用 AND 和 OR 连接。例 6查询 tb_course 表中是否存在 id=1 的课程,如果存在,就查询出 tb_students_info 表中 age 字段大于 24 的记录,SQL 语句和运行结果如下。mysql> SELECT * FROM tb_students_info     -> WHERE age>24 AND EXISTS(SELECT course_name FROM tb_course WHERE id=1); +----+------+------+------+--------+-----------+ | id | name | age  | sex  | height | course_id | +----+------+------+------+--------+-----------+ |  1 | Dany |   25 | 男   |    160 |         1 | +----+------+------+------+--------+-----------+ 1 row in set (0.01 sec)结果显示,从 tb_students_info 表中查询出了一条记录,这条记录的 age 字段取值为 25。内层查询语句从 tb_course 表中查询到记录,返回 TRUE。外层查询语句开始进行查询。根据查询条件,从 tb_students_info 表中查询 age 大于 24 的记录。拓展子查询的功能也可以通过表连接完成,但是子查询会使 SQL 语句更容易阅读和编写。一般来说,表连接(内连接和外连接等)都可以用子查询替换,但反过来却不一定,有的子查询不能用表连接来替换。子查询比较灵活、方便、形式多样,适合作为查询的筛选条件,而表连接更适合于查看连接表的数据。
  • [技术干货] MySQL修改和删除事件(ALTER/DROP EVENT)
    修改事件在 MySQL 中,事件创建之后,可以使用 ALTER EVENT 语句修改其定义和相关属性。修改事件的语法格式如下:ALTER EVENT event_name     ON SCHEDULE schedule     [ON COMPLETION [NOT] PRESERVE]     [ENABLE | DISABLE | DISABLE ON SLAVE]     [COMMENT 'comment']    DO event_body;另外,ALTER EVENT 语句还有一个用法就是让一个事件关闭或再次让其活动。例 1修改 e_test 事件,让其每隔 30 秒向表 tb_eventtest 中插入一条数据,SQL 语句和运行结果如下所示:mysql> ALTER EVENT e_test ON SCHEDULE EVERY 30 SECOND     -> ON COMPLETION PRESERVE     -> DO INSERT INTO tb_eventtest(user,createtime) VALUES('MySQL',NOW()); Query OK, 0 rows affected (0.04 sec) mysql> TRUNCATE TABLE tb_eventtest; Query OK, 0 rows affected (0.04 sec) mysql> SELECT * FROM tb_eventtest; +----+-------+---------------------+ | id | user  | createtime          | +----+-------+---------------------+ |  1 | MySQL | 2020-05-21 13:23:49 | |  2 | MySQL | 2020-05-21 13:24:19 | +----+-------+---------------------+ 2 rows in set (0.00 sec)由结果可以看出,修改事件后,表 tb_eventtest 中的数据由原来的每 5 秒插入一条,变为每 30 秒插入一条。使用 ALTER EVENT 语句还可以临时关闭一个已经创建的事件。例 2临时关闭事件 e_test 的具体代码如下所示:mysql> ALTER EVENT e_test DISABLE; Query OK, 0 rows affected (0.00 sec)查询 tb_eventtest 表中的数据,SQL 语句如下:SELECT * FROM tb_eventtest;为了确定事件已关闭,可以查询两次(每次间隔 1 分钟)tb_eventtest 表的数据,SQL 语句和运行结果如下所示:mysql> TRUNCATE TABLE tb_eventtest; Query OK, 0 rows affected (0.05 sec) mysql> SELECT * FROM tb_eventtest; Empty set (0.00 sec) mysql> SELECT * FROM tb_eventtest; Empty set (0.00 sec)由结果可以看出,临时关闭事件后,系统就不再继续向表 tb_eventtest 中插入数据了。删除事件在 MySQL 中,可以使用 DROP EVENT 语句删除已经创建的事件。语法格式如下:DROP EVENT [IF EXISTS] event_name;例 3删除事件 e_test,SQL 语句和运行结果如下:mysql> DROP EVENT IF EXISTS e_test; Query OK, 0 rows affected (0.01 sec) mysql> SELECT * FROM information_schema.events \G Empty set (0.00 sec)
  • [技术干货] MySQL创建事件(CREATE EVENT)
    MySQL创建事件(CREATE EVENT)在 MySQL 中,可以通过 CREATE EVENT 语句来创建事件,其语法格式如下:CREATE EVENT [IF NOT EXISTS] event_name     ON SCHEDULE schedule     [ON COMPLETION [NOT] PRESERVE]     [ENABLE | DISABLE | DISABLE ON SLAVE]     [COMMENT 'comment']     DO event_body;从上面的语法可以看出,CRATE EVENT 语句由多个子句组成,各子句的详细说明如下表所示。子句说明DEFINER可选用于定义事件执行时检查权限的用户IF NOT EXISTS可选用于判断要创建的事件是否存在EVENT event_name必选用于指定事件名称,event_name 的最大长度为 64 个字符如果未指定 event_name,则默认为当前的 MySQL 用户名(不区分大小写)ON SCHEDULE schedule必选用于定义执行的时间和时间间隔schedule 表示触发点ON COMPLETION [NOT] PRESERVE可选用于定义事件是否循环执行,即是一次执行还是永久执行,默认为一次执行,即 NOT PRESERVEENABLE | DISABLE | DISABLE ON SLAVE可选,用于指定事件的一种属性。其中,关键字 ENABLE 表示该事件是活动的,即调度器检查事件是否必须调用;关键字 DISABLE 表示该事件是关闭的,即事件的声明存储到目录中,但是调度器不会检查它是否应该调用;关键字 DISABLE ON SLAVE 表示事件在从机中是关闭的。如果不指定以上 3 个选项中的任何一个,默认为 ENABLECOMMENT 'comment'可选,用于定义事件的注释DO event_body必选用于指定事件启动时所要执行的代码,可以是任何有效的 SQL 语句、存储过程或者一个计划执行的事件。如果包含多条语句,则可以使用 BEGIN..END 复合结构在 ON SCHEDULE 子句中,参数 schedule 的值为一个 AT 子句,用于指定事件在某个时刻发生,其语法格式如下:AT timestamp [+ INTERVAL interval]...     | EVERY interval     [STARTS timestamp [+ INTERVAL interval] ...]     [ENDS timestamp[+ INTERVAL interval]...]参数说明如下:timestamp:一般用于只执行一次,表示一个具体的时间点,后面加上一个时间间隔,表示在这个时间间隔后事件发生。EVERY 子句:用于事件在指定时间区间内每隔多长时间发生一次,其中 STARTS 子句用于指定开始时间;ENDS 子句用于指定结束时间。interval:一般用于周期性执行,表示一个从现在开始的时间,其值由一个数值和单位构成。例如,使用“4 WEEK”表示 4 周,使用“'1:10'HOUR_MINUTE”表示 1 小时 10 分钟。间隔的长短用 DATE_ADD() 函数支配。interval 参数可以是以下值:YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |     WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |     DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND一般情况下,不建议使用不标准(以上未加粗关键字)的时间单位。例 1在 test 数据库中创建一个名称为 e_test 的事件,用于每隔 5 秒向表 tb_eventtest 中插入一条数据。创建 tb_eventtest 表,SQL 语句和运行结果如下:mysql> CREATE TABLE tb_eventtest(     -> id INT(11) PRIMARY KEY AUTO_INCREMENT,     -> user VARCHAR(20),     -> createtime DATETIME); Query OK, 0 rows affected (0.07 sec)创建 e_test 事件,SQL 语句和运行结果如下:mysql> CREATE EVENT IF NOT EXISTS e_test ON SCHEDULE EVERY 5 SECOND     -> ON COMPLETION PRESERVE     -> DO INSERT INTO tb_eventtest(user,createtime)VALUES('MySQL',NOW()); Query OK, 0 rows affected (0.04 sec)创建事件后,查询 tb_eventtest 中的数据,SQL 语句和运行结果如下:mysql> SELECT * FROM tb_eventtest; +----+-------+---------------------+ | id | user  | createtime          | +----+-------+---------------------+ |  1 | MySQL | 2020-05-21 10:41:39 | |  2 | MySQL | 2020-05-21 10:41:44 | |  3 | MySQL | 2020-05-21 10:41:49 | |  4 | MySQL | 2020-05-21 10:41:54 | +----+-------+---------------------+ 4 rows in set (0.01 sec)从结果可以看出,系统每隔 5 秒插入一条数据,这说明事件创建执行成功了。
  • [技术干货] Mysql的常识
    选择合适的数据类型char与varchar?Char属于固定长度的字符类型,varchar属于可变长度的字符类型所以char处理速度比varchar快得多,但是浪费存储空间(但随着mysql版本的升级varchar的性能也在不断的提升,所以目前varchar被更多的使用)2.text与blob?(1)两者都能保存大文本数据Blob能用来保存二进制数据,比如照片Text只能保存文本数据,如文章(2)text和bolo 字段在进行删除操作时会出现“空洞”现象(表数据文件的大小并没有因为删除数据而减小),可以使用OPTIMIZE TABLE t; 进行优化操作(3)采用的优化操作一般是把blob或text列放到一个单独的表中3.浮点数与定点数?(1)定点数:小数点固定在某个位置上的数据。 就好像 0.0000001 ,0.0001111;(2)浮点数:小数点位置可以浮动的数据。就像数学中的 1222.210^3也可以表示为1.222210^6;(3)在java中,我们知道System.out.print("7.22-7.0=" + (7.22f-7.0f));的结果并不是0.22而是0.219999,因此在程序中尽量避免浮点数的比较,运算。而是通过定点数进行比较和运算BigDecimal b1 = new BigDecimal(Double.toString(v1));(4)数据库中,float,double表示浮点数用decimal或numberic表示定点数所以对于货币等敏感数据,用定点数存储4.日期类型的选择?如果只记录年份,用year如果还要记录时分秒,用datetime如果考虑不同时区,用timestamp字符集(1)第一个字符集ASCII(2)为了处理不同的文字,又出现了几百种字符集。如iso-8859,GBK,GB2312等(3)为了统一编码,国际标准化组织iso制定了国际字符集标准UCS,这种标准采用四字节编码,将代码空间划分位组,面,行,格(4)这种UCS编码遭到了很多美国计算机协会的反对(sun,apple,ibm等)它们组成了unicode的协会,并推出了unicode1.0(二字节)(5)后来为了编码格式的统一,双方展开谈判,将unicode编码并入UCS的0组0字面。把它称作基本多语言文字面(BMP),剩下的两个字节做辅助字面和专用字面(6)其实人们常用到的还是unicode里的字符(99%),但是要用unicode里没有而ucs有的怎么办呢?所以制定了UTF-16,后来UTF-16在使用过程中出现了一系列的问题,所以出现了UTF-8(1至4字节编码)索引的设计和使用0.什么是索引?系统根据某种算法,将已有的数据(和未来新增的数据)单独建立一个文件,文件能够实现快速的匹配数据,并能够快速的找到对应表中的记录1.每种存储引擎(innodb,myidsam等)对每个表至少支持16个索引,myisam和innodb默认创建的都是BTREE索引,memory存储引擎默认使用hash索引2.创建索引:create index 索引名 on 表名 列命3.删除索引drop index 索引名 on 表名4.mysql中提供的索引类型?(1)主键索引(2)唯一索引(3)全文索引:根据文章内部的关键字进行索引(4)普通索引视图1.什么是视图?视图是一种虚拟存在的表。通俗的讲,视图就是一条SELECT语句执行后返回的结果集。2.什么时候用到视图?(1)经常用到的查询或复杂的联合查询(2)涉及到权限管理(比如表中某部分字段含有机密信息,不让低权限的用户看到,可以提供给他们一个适合他们权限的视图3.语句(1)创建:Create or replace view 视图名 as + 查询语句(2)查看:show create view 视图名(3)删除:drop view 视图名4.视图的意义(1)可以节省sql语句(将一条复杂的查询结果通过视图保存)(2)视图操作是怎对查询出来的结果,不会对原数据产生影响,相对安全(3)更好的进行权限控制函数1.什么是函数?将一段代码封装到一个结构中,在需要执行代码的时候调用函数即可(实现了复用)(任何函数都有返回值,因此函数通过select调用)1.函数的分类?(1)系统函数:系统调用好的函数,直接调用即可Select subString(字符串,开始,结束)Select char_length(字符串)(2)自定义函数:创建语法:create function 函数名(形参列表)Begin函数体Return 类型End调用: select 函数名();存储过程1.存储过程是什么?存储过程是没有返回值的函数2.创建过程?Create procedure 过程名字(参数列表)Begin---过程End3.调用过程?(过程没有返回值,不能用select调用。有一个专门的关键字call)Call 过程名();4.删除过程Drop proceddure pro1;5.过程参数过程参数还有自己的类型限定(In out inout)IN参数:仅需要将数据传入存储过程,并不需要返回计算后的该值。OUT参数:不接受外部传入的数据,仅返回计算之后的值。INOUT参数:需要数据传入存储过程经过调用计算后,再传出返回值。
  • [技术干货] Mysql事务并发问题解决方案
    在开发中遇到过这样一个问题一个看视频记录,更新到100就表示看完了,后面再有请求不继续更新了.结果是:                       导致,里面很多数据出现问题.推测是以下的情况才会导致.第一条请求 事务在执行中,还未提交(因为本地有时候比较难再现,于是手动在程序中,第一条记录处理的时候,sleep了几秒,就达到这种效果了)第二条请求 事务已经开始执行,这个时候查到的历史最大值不是100,才会去进行了更新网上看了一下解决方案:悲观锁直接锁行记录这个我在本地测试,确实有效,一个事务开始没结束,第二个事务一个等待,不过会导致处于阻塞状态,因为系统并发,不敢考虑,也就是记录下这个方式.手动模拟:执行第一个事务:-- 视频100BEGIN;   SELECT * FROM `biz_coursestudyhistory` WHERE sid = 5777166;   UPDATE biz_coursestudyhistory set studyStatus = 100,versionNO=versionNO+1 WHERE sid = 1 AND versionNO = 0;   -- commit ; 先不执行,先注解掉,只执行上面的接着执行第二个事务:BEGIN;    UPDATE biz_coursestudyhistory set studyStatus = 90,versionNO=versionNO+1 WHERE sid = 1 AND versionNO = 0;    SELECT * FROM `biz_coursestudyhistory` WHERE sid = 1 FOR UPDATE;    COMMIT;会发现成功不了,一直处于等待状态.查看锁                     确实被锁住了,这里只要执行第一个事务的commit ,第二个事务就会执行.从这里可以看出,行锁可以直接达到理想的数据统一状态,一个事务修改,其他都不能操作,感觉这种比较适合银行这种安全性的项目乐观锁:这种比较简单,并且不会造成阻塞方式就是加上版本号var maxver = select max(version) from table更新的话使用update table set studystatus = xxx,version = version +1 where id =1 and version = maxver写入的话INSERT into table (contentStudyID,courseWareID,studyStatus,studyTime,endTime) SELECT 27047358,3163,100,333,NOW() FROM dual WHERE NOT EXISTS (SELECT 1 FROM table WHERE contentStudyID =27047358 AND courseWareID = 3163  )这种方式,可以在更新或者写入的时候,直接判断库里面存在的数据是否存在,如果不存在则是别其他的线程使用了.修改为这种写法后,使用jmeter进行多线程测试,从最开始的多条记录更新成功,变成只有一个成功,后面的失败.从最开始的插入多条记录,到后来的只能插入一条数据了                               
  • [热门活动] (已结束,兑奖中)【HERO高校联盟年度盛典·线上知识峰会·数据库】玩转MySQL基础实战营+免费试用华为云MySQL,边学边拿
    # HERO高校联盟年度盛典·线上知识峰会 #数据库:玩转MySQL基础实战营+免费试用华为云MySQL,边学边拿奖! 活动时间     2020年9月14日 - 10月10日 活动任务   【任务1】学习课程《玩转MySQL基础实战营》           打开链接 https://education.huaweicloud.com/courses/course-v1:HuaweiX+CBUCNXD014+Self-paced/about,单击"报名课程"/“查看课程”。  【任务2】产品体验《免费试用华为云MySQL》           打开链接 https://activity.huaweicloud.com/free_test/index.html?ggw_hd#individual,然后找到下面云数据库的免费项目,按照要求完成申请:            活动规则及奖励     一、做任务获取积分           以上两个任务,完成任意一个可获得25主场积分,完成两个可获得50主场积分。           注:关于主场积分,请参阅https://developer.huaweicloud.com/hero/thread-76868-1-1.html。           1、【任务1】学习课程《玩转MySQL基础实战营》-完成标准               在本帖中回帖,反馈学习进度且进度为100%(截图为证,截图中可看到自己的华为云账号)。样例如下:                         2、【任务2】产品体验《免费试用华为云MySQL》-完成标准               在本帖中回帖,反馈体验内容(截图为证,截图中可看到自己的华为云账号)。体验内容包括但不限于:               ·  创建数据库实例               ·  创建表(不少于5个列)               ·  创建索引               ·  插入数据(不少于50行)               ·  查询数据    二、互动参与抽奖(若干名)           在活动帖中回帖盖楼,即有机会获得互动奖品(数据线、插座转换器、手机臂包等)。           回帖要求:超过20个字;非无意义灌水文字。    三、分享获取奖励(前100名)           分享活动文案+活动链接至朋友圈或100人以上技术群(微信、QQ、钉钉不限),截图到本帖,审核有效即可获得500码豆奖励,限前100名。           活动文案与活动链接:           【HERO高校联盟年度盛典·线上知识峰会·数据库】玩转MySQL基础实战营,免费试用华为云MySQL,50积分+精彩奖品!请点击:https://developer.huaweicloud.com/hero/forum.php?mod=viewthread&tid=77151&page=1&extra=#pid348347           附:码豆会员中心及相应规则           会员中心入口:https://devcloud.huaweicloud.com/bonususer/home           码豆奖励活动规则:            1)码豆可在DevCloud会员中心兑换实物礼品;            2)码豆奖励将于活动结束后的3个工作日内充值到账,请到会员中心的“查看明细”中查看到账情况;            3)码豆只能用于会员中心的礼品兑换,不得转让,具体规则请到会员中心阅读“码豆规则”;            4)为保证码豆成功发放,请先登录一次会员中心。         
  • [技术干货] MySQL数据库技术与应用:数据查询
    数据查询    数据查询是数据库系统应用的主要内容,也是用户对数据库最频繁、最常见的基本操作请求。数据查询可以根据用户提供的限定条件,从已存在的数据表中检索用户需要的数据。MySQL使用SELECT语句从数据库中检索数据,并将结果集以表格的形式返回给用户。SELECT查询的基本语法select * from 表名;from关键字后面写表名,表示数据来源于是这张表select后面写表中的列名,如果是*表示在结果中显示表中所有列在select后面的列名部分,可以使用as为列起别名,这个别名出现在结果集中如果要查询多个列,之间使用逗号分隔消除重复行在select后面列前使用distinct可以消除重复的行select distinct gender from students;条件使用where子句对表中的数据筛选,结果为true的行会出现在结果集中语法如下:select * from 表名 where 条件;比较运算符等于=大于>大于等于>=小于<小于等于<=不等于!=或<>查询编号大于3的学生select * from students where id>3;查询编号不大于4的科目select * from subjects where id<=4;查询姓名不是“黄蓉”的学生select * from students where sname!='黄蓉';查询没被删除的学生select * from students where isdelete=0;逻辑运算符andornot查询编号大于3的**学select * from students where id>3 and gender=0;查询编号小于4或没被删除的学生select * from students where id<4 or isdelete=0;模糊查询like%表示任意多个任意字符_表示一个任意字符查询姓黄的学生注意:可能出现两个_代表一个汉字的情况;select * from students where sname like '黄%';查询姓黄并且名字是一个字的学生select * from students where sname like '黄_';查询姓黄或叫靖的学生select * from students where sname like '黄%' or sname like '%靖%';范围查询    in表示在一个非连续的范围内    查询编号是1或3或8的学生select * from students where id in(1,3,8);  //括号内的值可以实际不存在,但是没意义between ... and ...表示在一个连续的范围内查询学生是3至8的学生select * from students where id between 3 and 8;查询学生是3至8的男生select * from students where id between 3 and 8 and gender=1;空判断注意:null与''是不同的判空is null查询没有填写地址的学生select * from students where hometown is null;判非空is not null查询填写了地址的学生select * from students where hometown is not null;查询填写了地址的女生select * from students where hometown is not null and gender=0;优先级小括号,not,比较运算符,逻辑运算符and比or先运算,如果同时出现并希望先算or,需要结合()使用聚合    能看到统计的结果看不到原始数据    为了快速得到统计数据,提供了5个聚合函数    count(*)表示计算总行数,括号中写星与列名,结果是相同的    查询学生总数select count(*) from students;max(列)表示求此列的最大值查询女生的编号最大值select max(id) from students where gender=0;min(列)表示求此列的最小值查询未删除的学生最小编号select min(id) from students where isdelete=0;sum(列)表示求此列的和  //数值类型的列求和查询男生的编号之后select sum(id) from students where gender=1;avg(列)表示求此列的平均值   //数值类型的列求平均值查询未删除女生的编号平均值select avg(id) from students where isdelete=0 and gender=0;分组           group by分组的目的还是聚合        按照字段分组,表示此字段相同的数据会被放到一个组中   //筛选        分组后,只能查询出相同的数据列,对于有差异的数据列无法出现在一个结果集中        可以对分组后的数据进行统计,做聚合运算        语法:select 列1,列2,聚合... from 表名 group by 列1,列2,列3...       //将列123都一样放到一组查询男女生总数select gender as 性别,count(*)from studentsgroup by gender;查询各城市人数select hometown as 家乡,count(*)from studentsgroup by hometown;分组后的数据筛选语法:select 列1,列2,聚合... from 表名group by 列1,列2,列3...having 列1,...聚合...having后面的条件运算符与where的相同查询男生总人数方案一select count(*)from studentswhere gender=1; 方案二//优点 可以更为直观的查看筛选结果 select gender as 性别,count(*)from studentsgroup by genderhaving gender=1;对比where与having        where是对from后面指定的表进行数据筛选,属于对原始数据的筛选        having是对group by的结果进行筛选  排序为了方便查看数据,可以对数据进行排序语法:select * from 表名order by 列1 asc|desc,列2 asc|desc,...        将行数据按照列1进行排序,如果某些行列1的值相同时,则按照列2排序,以此类推        默认按照列值从小到大排列        asc从小到大排列,即升序      //ascend         desc从大到小排序,即降序   //descend         查询未删除男生学生信息,按学号降序select * from studentswhere gender=1 and isdelete=0order by id desc;查询未删除科目信息,按名称升序select * from subjectwhere isdelete=0order by stitle;获取部分行    当数据量过大时,在一页中查看数据是一件非常麻烦的事情    语法select * from 表名limit start,count从start开始,获取count条数据start索引从0开始    //从哪儿开始数几个示例:分页    已知:每页显示m条数据,当前显示第n页    求总页数:此段逻辑后面会在python中实现查询总条数p1使用p1除以m得到p2如果整除则p2为总数页如果不整除则p2+1为总页数求第n页的数据select * from studentswhere isdelete=0limit (n-1)*m,m总结完整的select语句select distinct *from 表名where ....group by ... having ...order by ...limit star,count执行顺序为:from 表名where ....group by ...select distinct *having ...order by ...limit star,count实际使用中,只是语句中某些部分的组合,而不是全部
  • [技术干货] 2020-09-01:mysql里什么是检查点、保存点和中间点?
    2020-09-01:mysql里什么是检查点、保存点和中间点?
  • 从存储端高并发之线程池,聊聊GaussDB(for MySQL) 的高扩展性
  • [技术干货] MySQL之表的增删改查
    1. 创建表create table 表名(  列名 数据类型 [约束类型] [comment '备注'], ...,  constraint 约束名 约束类型(列名)    )engine=innodb defalut charset=utf8;12345从其他表查询几列数据生成新的表create table 表名1 as select 列1,列2 from 表名22. 向表中添加数据按列名添加一行数据insert into 表名[(列名1,列名2...)] values(列1数据,列2数据...);从其他表中复制数据insert into 表名1 select 列名 from 表名23. 修改表中的数据按条件修改数据update 表名 set 列名=列值,列2名=列2值...where 选择条件将子查询结果赋值给表中数据update 表名 set 列名=(子查询)4. 删除表中的数据按条件删除指定数据delete from 表名 where 选择条件销毁整张表或约束drop table 表名;drop index 约束名;5. 修改表的结构添加列alter table 表名 add 列名 数据类型;添加约束alter table 表名 add [constraint 约束名] 约束类型(列名);约束名添加语法撤销语法外键约束alter table 表名 add [constraint 约束名] foreign key(外键列) references 主键表名(主键列);alter table 表名 drop foreign key 约束名默认约束alter table 表名 alter 列名 set default ‘默认值’alter table 表名 alter 列名 drop default检查约束alter table 表名 add [CONSTRAINT 约束名] check (列名10)alter table 表名 drop check 约束名唯一约束alter table 表名 add [CONSTRAINT 约束名] unique (列名)alter table 表名 drop index 约束名主键约束alter table 表名 add [CONSTRAINT 约束名] primary key (列名)alter table 表名 drop primary key3. 修改表名alter table 表名 rename 新表名4. 修改列的字段名alter table 表名 change cloumn 列名 新列名 新列数据类型5. 修改列的数据类型alter table 表名 alter column 列名 数据类型;6. 添加一列到表中alter table 表名 add 列名 数据类型;7. 删除表中一列alter table 表名 drop column 列名7. 查看表的结构desc 表名2. 表的查询1. 查询的基本语法select 列名1 [as] [列别名],列名2  from 表1 [as] [表别名]  [left] join 表2 on 连接条件  [left] join 表3 on 连接条件 where 检索条件(不可用统计函数) group by 分组列1,列2  having 检索条件(可用统计函数min,max,sum,avg) order by 排序列 [desc降序]  limit 起始行号,显示行数1234567892. 查询分类专有名词含义选择选择不同行投影选择不同列连接多表联合查询3. 连接分类连接名称语法含义内部连接a join b on …只显示符合连接条件记录外部连接a left join b on …a表显示不符合条件记录自身连接a join a on …a表自身列存在关联全外连接a full outer join b on …ab表都显示不符合条件记录交叉连接a cross join b on …a*b产生笛卡尔积,生成a行*b行记录自然连接a natural join b自动判断连接条件4. 子查询使用子查询的目的数据库连接耗时长,避免多次连接数据库尽可能减少次数提升数据库性能能用连接解决时,不使用子查询无关子查询常用于where/having后用于约束父查询的条件,先执行子查询语句一次,父子查询间字段无关select * from emp where sal > (select avg(sal) from emp)用于select后直接输出列,可以添加别名select ename,(select avg(sal) from emp) as asal from emp相关子查询常用于where后,子查询返回字段与父查询字段相关联,父查询每次要执行子查询中的条件一次select * from emp f where sal > (select avg(sal) from emp where deptno=f.deptno)表示比与自己所在部门的平均工资相比更高的记录被选择嵌套子查询常用于from后,把子查询返回结果看作一个表与父查询的表做连接select * from emp a join (select deptno from emp) b on a.deptno = b.deptno多列查询表示列1,列2分别与子查询返回的第一列,第二列值相同的记录被选择select * from emp where (列1名,列2名) in (子查询)多行查询字段 in(子查询) 与任意返回值相同字段 <或或= any(子查询) 比最小返回值大或比最大返回值小或同in字段 <或或= all(子查询) 比最小返回值小或比最大返回值大或完全相同select * from emp where 列名 in/<=any/<=all (子查询)当子查询出现null时子查询返回null会造成比对时结果全部为null,任意字段与null比对后均返回null(select comm from emp where comm is not null)去除子查询返回结果集中的null值5. 纵向合并union无all:一行记录有all:28行相同记录合并列仅限两列数据类型相同时,mysql环境下不同数据类型也可以合并但不正规select 1,2 from emp union [all]select 1,2 from emp 126. mysql分页函数limit从x+1行开始向下显示d行记录,放在select子句最后使用limit x,d从第3行显示到第8行结束select * from emp limit 2,57. 索引主键自增长用作索引时,删除的记录会被记住索引号,新添加的记录将跳过删除的索引号,为其恢复记录保留表的空间,也可在添加新记录时指定索引号,但在重启mysql服务后删除的索引失效如插入主键值1,2,3,删除2,3行,再添加记录将从4开始添加索引号
  • [Java] mysql性能优化
    为搜索字段创建索引垂直分割分表选择正确的存储引擎避免使用select*,列出需要查询的字段
  • [技术干货] MySQL的基础语句
    创建数据库:create database test1 ;查看数据库:show databases;选择数据库:use mysql;删除数据库:drop database test1;创建表:CREATE  [TEMPORARY]  TABLE  [IF NOT EXISTS] [database_name.] <table_name> (   <column_name>  <data_type>  [[not] null],… )注:TEMPORARY:指明创建临时表  IF NOT EXISTS:如果要创建的表已经存在,强制不显示错误消息  database_name:数据库名  table_name:表名  column_name:列名  data_type:数据类型  查看定义:desc emp;查看创建的表:show create table emp ;更新表名: alter table emp rename users;删除表:drop table emp;修改表字段:alter table emp modify ename varchar(30);增加表字段:alter table emp add column age int(3);修改表字段:alter table emp change age age int(4);删除表字段:alter table emp drop column age;change和modify:前者可以修改列名称,后者不能.  change需要些两次列名称.字段增加修改 add/change/modify/ 添加顺序:1 add 增加在表尾. 2 change/modify 不该表字段位置. 3 修改字段可以带上以下参数进行位置调整(frist/after column_name); alter table emp change age age int(2) after ename; alter table emp change age age int(3) first;插入记录://指定字段, //自增,默认值等字段可以不用列出来,没有默认值的为自动设置为NULL insert into emp (ename,hiredate,sal,deptno) values ('jack','2000-01-01','2000',1); //可以不指定字段,但要一一对应 insert into emp values ('lisa','2010-01-01','8000',2);批量记录:insert into emp values ('jack chen','2011-01-01','18000',2),('andy lao','2013-01-01','18000',2);更新记录:update emp set sal="7000.00" where ename="jack"; update emp e,dept d set e.sal="10000",d.deptname=e.ename where e.deptno=d.deptno and e.ename="lisa";删除记录://请仔细检查where条件,慎重 delete from emp where ename='jack';12查看记录://查看所有字段 select * from emp; //查询不重复记录 select distinct(deptno) from emp ; select distinct(deptno),emp.* from emp ; //条件查询 //比较运算符: > < >= <= <> != ... //逻辑运算符: and or ... select * from emp where sal="18000" and deptno=2;1234567891011排序//desc降序,asc 升序(默认) select * from emp order by deptno ; select * from emp order by deptno asc; select * from emp order by deptno desc,sal desc;限制记录数:select * from emp limit 1; select * from emp limit 100,10; select * from emp order by deptno desc,sal desc limit 1;聚合:函数:count():记录数 / sum(总和); / max():最大值 / min():最小值select count(id) from emp ; select sum(sal) from emp ; select max(sal) from emp ; select min(sal) from emp ;group by分组://分组统计 select count(deptno) as count from emp group by deptno; select count(deptno) as count,deptno from emp group by deptno; select count(deptno) as count,deptno,emp.* from emp group by deptno;having 对分组结果二次过滤:select count(deptno) as count,deptno from emp group by deptno having count > 2;with rollup 对分组结果二次汇总:select count(sal),emp.*  from emp group by sal, deptno with rollup ;表连接:left join :左连接,返回左表中所有的记录以及右表中连接字段相等的记录;right join :右连接,返回右表中所有的记录以及左表中连接字段相等的记录;inner join: 内连接,又叫等值连接,只返回两个表中连接字段相等的行;full join:外连接,返回两个表中的行:left join + right join;cross join:结果是笛卡尔积,就是第一个表的行数乘以第二个表的行数。内连接:只返回两个表中连接字段相等的行select * from emp as e,dept as d where e.deptno=d.deptno; select * from emp as e inner join dept as d on e.deptno=d.deptno;左外连接:包含左表中所有的记录以及右表中连接字段相等的记录select * from emp as e left join dept as d on e.deptno=d.deptno;右外连接:包含右表中所有的记录以及左表中连接字段相等的记录select * from emp as e right join dept as d on e.deptno=d.deptno;子查询://=, != select * from emp where deptno = (select deptno from dept where deptname="技术部"); select * from emp where deptno != (select deptno from dept where deptname="技术部"); //in, not in  //当需要使用里面的结果集的时候必须用in();  select * from emp where deptno in (select deptno from dept where deptname="技术部"); select * from emp where deptno not in (select deptno from dept where deptname="技术部"); //exists , not exists //当需要判断后面的查询结果是否存在时使用exists(); select * from emp where exists (select deptno from dept where deptno > 5); select * from emp where not exists (select deptno from dept where deptno > 5);
总条数:1406 到第 页
上滑加载中