├── LICENSE ├── README.md ├── articles ├── .DS_Store ├── backup.md ├── chinese-data.md ├── code-execution-structure.md ├── collate.md ├── column-null-comment-default.md ├── column-type-data.md ├── column-type-date.md ├── column-type-string.md ├── column-type.md ├── data-operation.md ├── database-variable.md ├── database.md ├── datafile.md ├── duplicate-primary-key.md ├── foreign-key.md ├── function.md ├── increment.md ├── index.md ├── install-mysql.md ├── join-query.md ├── mysql_db.md ├── paradigm.md ├── primarykey.md ├── procedure.md ├── record-length.md ├── relation-db.md ├── relation.md ├── resovle-method.md ├── secure.md ├── select.md ├── sql-data.md ├── sql-database.md ├── sql-operation.md ├── sql-table.md ├── sub-query.md ├── thing-one.md ├── thing-two.md ├── trigger.md ├── union.md ├── uniquekey.md ├── updata-and-delete.md ├── view-one.md ├── view-two.md └── worm-copy.md └── images ├── backup ├── class-sql-location.png ├── class-sql.png ├── class-txt.png ├── create-myisam.png ├── data-location.png ├── data-myclass.png ├── delete-class.png ├── into-outfile.png ├── login-mysql.png ├── more-steps-2.png ├── more-steps.png ├── my_myisam.png ├── outfile-class2.png ├── pointed-single-table-backup.png ├── show-tables.png ├── test-back-2.png ├── test-backup.png └── use-testoo.png ├── chinese-data ├── mysql-command-line-client.png ├── select-from-student.png ├── show-character-set.png └── show-variables.png ├── code-execution-structure ├── insert-orders-loop.png ├── insert-orders.png └── select-goods.png ├── collate ├── create-collate-bin-ci.png ├── order-show.png ├── select-collate-bin-ci.png └── show-collation.png ├── column-null-comment-default ├── create-table-myclass.png ├── create-table-mydefault.png ├── create-table-myfriend.png └── insert-mydefault.png ├── column-type ├── alter-myint.png ├── column-type-info.png ├── create-table-mydate.png ├── create-table-mydecimal.png ├── create-table-myenum.png ├── create-table-myfloat.png ├── create-table-myint.png ├── create-table-myset.png ├── field-type-null-key.png ├── insert-myenum.png ├── insert-myint.png ├── insert-myset.png ├── insert-select-myset.png ├── null-myint.png ├── select-myenum.png ├── select-myset.png ├── two-null-myint.png ├── update-mydate.png └── zerofill-myint.png ├── database-variable ├── select-system-var.png ├── select-var-student-2.png ├── select-var-student-3.png ├── select-var-student-4.png ├── select-var-student.png ├── set-global-var.png ├── set-section-var.png ├── set-varself.png └── show-variables.png ├── datafile └── show-global-variables.png ├── duplicate-primary-key ├── desc-myclass.png ├── insert-error.png ├── insert-myclass.png ├── replace-myclass.png └── select-myclass.png ├── foreign-key ├── create-myforeign2.png ├── create-myforeign3.png ├── create-myforeignal1.png ├── desc-myforeign.png ├── insert-alter-show.png ├── insert-myforeign3.png ├── select-class-myforeign2.png ├── select-insert-class.png ├── select-myforeign3-2.png ├── select-myforeign3.png └── update-class.png ├── function ├── create-addall.png ├── create-addall2.png ├── create-show-love.png ├── drop-function.png ├── select-addall.png ├── select-addall2.png ├── select-char-length.png ├── select-insert.png ├── select-instr.png ├── select-lpad.png ├── select-strcmp.png ├── select-substring.png ├── set-aite-cn.png ├── show-create-function.png └── show-function-status.png ├── increment ├── alter-modify-myauto.png ├── alter-myauot-2.png ├── alter-myauto.png ├── create-table-myauto.png ├── insert-myauto.png ├── modify-myauto.png ├── select-myauto.png ├── set-auto-increment.png ├── show-myauto.png └── show-variables.png ├── install-mysql ├── accounts-and-roles.png ├── apply-server-configuration-2.png ├── apply-server-configuration-3.png ├── apply-server-configuration.png ├── choosing-a-setup-tyep.png ├── installation-2.png ├── installation-3.png ├── installation-complete.png ├── installation.png ├── mysql-client.png ├── plugins-and-extensions.png ├── product-configuration-next.png ├── product-configuration.png ├── type-and-networing.png └── windows-service.png ├── join-query ├── innerjoin-crossjoin.png ├── left-right-join.png ├── leftjoin-like-naturaljoin.png ├── natural-join.png ├── natural-left-join.png ├── on-where-join.png ├── select-student-crossjoin-class.png ├── select-student-innerjoin-class-alias.png └── select-student-innerjoin-class.png ├── primarykey ├── alter-mypri3.png ├── create-table-mypri1.png ├── create-table-mypri2.png ├── create-table-mypri3.png ├── desc-mypri3.png └── insert-mypri3.png ├── procedure ├── call-pro.png ├── call-pro3.png ├── create-pro2.png ├── create-pro3.png ├── create-procedure.png ├── drop-procedure.png ├── set-aite-var.png ├── show-create-procedure.png └── show-procedure.png ├── record-length ├── create-table-myutf8.png ├── myutf8-mygbk.png ├── myutf81-mygbk1.png ├── myutf82-mygbk2.png └── utf8-gbk.png ├── relation ├── table-1.png ├── table-2.png ├── table-3.png ├── table-4.png ├── table-5.png ├── table-6.png ├── table-7.png └── table-8.png ├── resovle-method ├── computer-management.png ├── start-server.png └── test-mysql-client.png ├── secure ├── my-ini.png └── show-variables.png ├── select ├── select-between.png ├── select-by-grade-sex.png ├── select-count-max-min.png ├── select-group-by-sex.png ├── select-group-bysex.png ├── select-having-2.png ├── select-having.png ├── select-limit-2.png ├── select-limit.png ├── select-mycopy.png ├── select-or.png ├── select-order-by-2.png ├── select-order-by.png ├── select-set.png ├── select-sex-count.png ├── select-student-myclass.png ├── select-student.png ├── select-union-select.png ├── select-with-rollup.png └── use-alias.png ├── sql-operation └── set-name-gbk.png ├── sub-query ├── across-sub-query.png ├── column-any-some-all.png ├── column-non-any-some-all.png ├── column-row-element.png ├── column-sub-query.png ├── exists-sub-query.png ├── select-class.png ├── select-student.png └── table-sub-query.png ├── thing-one ├── compare-bankaccount-2.png ├── compare-bankaccount-3.png ├── compare-bankaccount.png ├── create-bankaccount.png ├── start-transaction.png └── update-bankaccount.png ├── thing-two ├── commit.png ├── compare-bankaccount-2.png ├── compare-bankaccount-3.png ├── compare-bankaccount.png ├── rollback.png ├── set-autocommit.png ├── show-variables.png └── test-savepoint.png ├── trigger ├── create-goods.png ├── create-show-triggers.png ├── create-trigger.png ├── drop-triggers.png ├── select-goods.png ├── select-triggers.png ├── show-ceate-triggers.png ├── show-triggers.png └── user-triggers.png ├── union ├── select-student.png ├── select-union-class.png ├── select-union-distinct.png ├── select-union-error.png ├── union-order-2.png └── union-order.png ├── uniquekey ├── alter-myunique3.png ├── create-table-myunique.png ├── create-table-myunique2.png ├── create-table-myunique3.png ├── desc-myunique3.png ├── insert-myunique.png └── show-create-myunique2.png ├── updata-and-delete ├── delete-mycopy.png ├── delete-student.png ├── select-mycopy.png ├── truncate-student.png └── update-mycopy.png ├── view-one ├── alter-myv1.png ├── create-myv1v2v3.png ├── create-myv3.png ├── desc-myv1.png ├── drop-myv4.png ├── select-myv1v2v3.png └── show-create-myv1.png ├── view-two ├── create-myv5.png ├── create-myv6.png ├── delete-myv3.png ├── desc-myv3.png ├── desc-student.png ├── select-myv6.png ├── show-myv2.png └── update-myv5.png └── worm-copy ├── desc-mygbk.png ├── insert-mycopy.png └── select-mycollate.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Charies Gavin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程 2 | 3 | ![author](https://img.shields.io/badge/author-chariesgavin-blueviolet.svg)![issues](https://img.shields.io/github/issues/guobinhit/mysql-tutorial.svg)![stars](https://img.shields.io/github/stars/guobinhit/mysql-tutorial.svg)![forks](https://img.shields.io/github/forks/guobinhit/mysql-tutorial.svg)![license](https://img.shields.io/github/license/guobinhit/mysql-tutorial.svg) 4 | 5 |   数据库(Database)是按照数据结构来组织、存储和管理数据的仓库,它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代以后,数据管理不再仅仅是存储和管理数据,而转变成用户所需要的各种数据管理的方式。数据库有很多种类型,从最简单的存储有各种数据的表格到能够进行海量数据存储的大型数据库系统都在各个方面得到了广泛的应用。在这里,作者将详细讲述 MySQL 数据库的相关知识,以供大家参考。当然,也需要在此声明:**如果文章中出现了错误,请大家帮忙斧正,深感荣幸。** 6 | 7 | ## 索引 8 | 9 | - [基础教程](#基础教程) 10 | - [教程相关](#教程相关) 11 | 12 | 13 | ## 基础教程 14 | 15 | - 数据库 16 | - 第 1 篇:[数据库](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/database.md) 17 | - 第 2 篇:[关系型数据库](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/relation-db.md) 18 | - MySQL数据库 19 | - 第 3 篇:[MySQL 数据库](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/mysql_db.md) 20 | - 第 4 篇:[SQL 基本操作](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/sql-operation.md) 21 | - 第 5 篇:[中文数据问题](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/chinese-data.md) 22 | - 第 6 篇:[校对集问题](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/collate.md) 23 | - 第 7 篇:[列类型](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/column-type.md) 24 | - 第 8 篇:[记录长度](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/record-length.md) 25 | - 列属性 26 | - 第 9 篇:[列属性 之 空属性、列描述和默认值](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/column-null-comment-default.md) 27 | - 第 10 篇:[列属性 之 主键](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/primarykey.md) 28 | - 第 11 篇:[列属性 之 自动增长](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/increment.md) 29 | - 第 12 篇:[列属性 之 唯一键](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/uniquekey.md) 30 | - 索引、关系及范式 31 | - 第 13 篇:[索引](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/index.md) 32 | - 第 14 篇:[关系](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/relation.md) 33 | - 第 15 篇:[范式](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/paradigm.md) 34 | - 高级操作 35 | - 第 16 篇:[数据的高级操作 之 主键冲突](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/duplicate-primary-key.md) 36 | - 第 17 篇:[数据的高级操作 之 蠕虫复制](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/worm-copy.md) 37 | - 第 18 篇:[数据的高级操作 之 更新 & 删除](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/updata-and-delete.md) 38 | - 第 19 篇:[数据的高级操作 之 查询](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/select.md) 39 | - 查询 40 | - 第 20 篇:[连接查询](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/join-query.md) 41 | - 第 21 篇:[外键](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/foreign-key.md) 42 | - 第 22 篇:[联合查询](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/union.md) 43 | - 第 23 篇:[子查询](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/sub-query.md) 44 | - 视图 45 | - 第 24 篇:[视图(上)](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/view-one.md) 46 | - 第 25 篇:[视图(下)](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/view-two.md) 47 | - 备份及还原 48 | - 第 26 篇:[数据备份与还原](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/backup.md) 49 | - 事物 50 | - 第 27 篇:[事务(上)](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/thing-one.md) 51 | - 第 28 篇:[事务(下)](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/thing-two.md) 52 | - 数据库变量 53 | - 第 29 篇:[数据库变量](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/database-variable.md) 54 | - 触发器 55 | - 第 30 篇:[触发器](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/trigger.md) 56 | - 代码执行结构 57 | - 第 31 篇:[代码执行结构](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/code-execution-structure.md) 58 | - 函数 59 | - 第 32 篇:[函数](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/function.md) 60 | - 存储结构 61 | - 第 33 篇:[存储结构](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/procedure.md) 62 | 63 | 64 | ## 教程相关 65 | 66 | - 第 1 篇:[详述 MySQL 数据库的安装及配置](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/install-mysql.md) 67 | - 第 2 篇:[详述 MySQL 数据库输入密码后闪退的问题及解决方案](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/resovle-method.md) 68 | - 第 3 篇:[详述查看 MySQL 数据文件存储位置的方法](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/datafile.md) 69 | - 第 4 篇:[详述 MySQL 导出数据遇到 secure-file-priv 的问题](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/secure.md) 70 | 71 | 72 | ---------- 73 | 此外,附上一句格言,望共勉:**好学若饥,谦卑若愚。** 74 | -------------------------------------------------------------------------------- /articles/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/articles/.DS_Store -------------------------------------------------------------------------------- /articles/chinese-data.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(五)「中文数据问题」 2 | 3 | 中文数据问题 4 | ====== 5 | 6 | **中文数据问题的本质就是字符集的问题。** 7 | 8 | 由于计算机仅识别二进制数据,而且人类则更倾向于识别字符(符号),因此就需要一个二进制与字符的对应关系,也就是**字符集**。 9 | 10 | 在咱们通过 MySQL 数据库的客户端向服务器插入中文数据的时候,有可能失败,原因则可能是客户端和服务器的字符集设置不同导致的,例如: 11 | 12 | - 客户端的字符集为`gbk`,则一个中文字符,对应两个字节; 13 | - 服务器的字符集为`utf8`,则一个中文字符,对应三个字节。 14 | 15 | 这样显然会在编码转换的过程中出现问题,从而导致插入中文数据失败。 16 | 17 | 由于所有的数据库服务器表现的一些特性都是通过服务器端的变量来保持的,因此系统会先读取自己的变量,看看具体的表现形式。这样的话,咱们就可以通过以下语句查看服务器到底识别哪些字符集: 18 | 19 | ``` 20 | -- 查看服务器识别的全部字符集 21 | show character set; 22 | ``` 23 | 24 | ![show-character-set](https://github.com/guobinhit/mysql-tutorial/blob/master/images/chinese-data/show-character-set.png) 25 | 26 | 通过以上查询,咱们会发现:**服务器是万能的,其支持所有字符集。** 27 | 28 | 既然服务器支持这么多字符集,总会有一种是服务器默认的和客户端打交道的字符集。因此,咱们可以通过以下语句查看服务器默认的对外处理的字符集: 29 | 30 | ``` 31 | -- 查看服务器默认的对外处理的字符集 32 | show variables like 'character_set%'; 33 | ``` 34 | ![show-variables](https://github.com/guobinhit/mysql-tutorial/blob/master/images/chinese-data/show-variables.png) 35 | 36 | - 标注1:服务器默认的客户端传来的数据字符集为`utf8`; 37 | - 标注2:连接层字符集为`utf8`; 38 | - 标注3:当前数据库的字符集为`utf8`; 39 | - 标注4:服务器默认的对外处理的字符集`utf8`. 40 | 41 | 通过以上查询,咱们会发现:**服务器默认的对外处理的字符集是`utf8`**. 42 | 43 | 那么反过来,咱们在通过客户端的属性查看客户端支持的字符集: 44 | 45 | ![mysql-command-line-client](https://github.com/guobinhit/mysql-tutorial/blob/master/images/chinese-data/mysql-command-line-client.png) 46 | 47 | 显然,咱们已经找到了问题的根源,确实是:**客户端支持的字符集为`gbk`,而服务器默认的对外处理的字符集为`utf8`,因此产生矛盾。** 48 | 49 | 既然问题已经找到了,那么解决方案就是:**修改服务器默认接收的字符集为`gbk`**. 50 | 51 | ``` 52 | -- 修改服务器默认接收的字符集为 GBK(不区分大小写) 53 | set character_set_client = gbk; 54 | ``` 55 | 56 | 这样的话,咱们再插入中文数据的时候,就会插入成功啦!But,在咱们查看数据的时候,又发现了一个问题,就是之前咱们插入的中文数据显示乱码啦!不过这也正常,因为查询的时候,数据的来源是服务器(`utf8`),解析数据的是客户端,而客户端仅识别`gbk`格式的数据,显示乱码也就在意料之中啦! 57 | 58 | 因此,解决方案就是:**修改服务器给客户端的数据字符集为`gbk`**. 59 | 60 | ``` 61 | -- 修改服务器给客户端的数据字符集为 GBK(不区分大小写) 62 | set character_set_results = gbk; 63 | ``` 64 | 65 | ![select-from-student](https://github.com/guobinhit/mysql-tutorial/blob/master/images/chinese-data/select-from-student.png) 66 | 67 | 如上图所示,向服务器插入中文数据的问题已经解决啦! 68 | 69 | ---------- 70 | 此外,咱们之前使用的 SQL 语句: 71 | 72 | ``` 73 | -- 修改的只是会话级别,即当前客户端当次连接有效,关闭后失效 74 | set 变量 = 值; 75 | ``` 76 | 这样的话,每当咱们重启客户端的时候,都要依次重新进行设置,比较麻烦,因此咱们可以使用快捷的设置方式,即: 77 | 78 | ``` 79 | set names 字符集; 80 | ``` 81 | 82 | 例如, 83 | 84 | ``` 85 | /** 86 | * 恒等于 set character_set_client = gbk; 87 | * 恒等于 set character_set_results = gbk; 88 | * 恒等于 set character_set_connection = gbk; 89 | */ 90 | set names gbk; 91 | ``` 92 | 93 | 表示上述一条语句,将同时改变三个变量的值。其中,`connection`为连接层,是字符集转换的中间者,如果其和`client`和`results`的字符集一致,则效率更高,不一致也没有关系。 94 | 95 | 96 | ---------- 97 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 98 | -------------------------------------------------------------------------------- /articles/code-execution-structure.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(三十一)「代码执行结构」 2 | 3 | ## 代码执行结构 4 | 5 | 在 MySQL 编程中,代码的执行结构有三种,分别为: 6 | 7 | - 顺序结构; 8 | - 分支结构; 9 | - 循环结构。 10 | 11 | 顺序结构,自不必多说,在本文中,我们着重了解分支结构和循环结构。 12 | 13 | ### 分支结构 14 | 15 | **分支结构**:事先准备多个代码块,通过判断条件是否满足,执行对应的代码。 16 | 17 | 在 MySQL 中,只有`if`分支结构,其基本语法为: 18 | 19 | ``` 20 | if 条件判断 then 21 | -- 满足条件时,要执行的代码 22 | else -- 可以没有 else 语句 23 | -- 不满足条件时,要执行的代码 24 | end if; 25 | ``` 26 | 接下来,我们利用触发器和`if`分支,完成这样的需求: 27 | 28 | - 在生成订单前,判断商品的库存是否满足,如果满足,则插入订单;否则,插入失败。 29 | 30 | 依次执行如下 SQL 语句,进行测试: 31 | 32 | ``` 33 | -- 查看商品表 34 | select * from goods; 35 | -- 查看订单表 36 | select * from orders; 37 | -- 修改语句结束符 38 | delimiter $$ 39 | -- 创建触发器 40 | create trigger before_order before insert on orders for each row 41 | begin 42 | -- 判断商品库存是否满足订单 43 | -- 通过商品表获取商品库存量 44 | select inventory from goods where id = NEW.goods_id into @inventory; 45 | -- 比较库存 46 | if @inventory < NEW.goods_number then 47 | -- 库存不够,由于触发器不能阻止事件发生,因此我们只能暴力报错 48 | insert into XXX values(XXX); 49 | end if; 50 | end 51 | $$ 52 | -- 恢复语句结束符 53 | delimiter ; 54 | ``` 55 | 56 | ![select-goods](https://github.com/guobinhit/mysql-tutorial/blob/master/images/code-execution-structure/select-goods.png) 57 | 58 | ``` 59 | -- 插入订单 60 | insert into orders values(null, 1, 1000); 61 | -- 查看商品表 62 | select * from goods; 63 | -- 查看订单表 64 | select * from orders; 65 | ``` 66 | 67 | ![insert-orders](https://github.com/guobinhit/mysql-tutorial/blob/master/images/code-execution-structure/insert-orders.png) 68 | 69 | ``` 70 | -- 插入订单 71 | insert into orders values(null, 1, 100); 72 | -- 查看商品表 73 | select * from goods; 74 | -- 查看订单表 75 | select * from orders; 76 | ``` 77 | 78 | ![insert-orders-loop](https://github.com/guobinhit/mysql-tutorial/blob/master/images/code-execution-structure/insert-orders-loop.png) 79 | 80 | 如上图所示,虽然在报错的时候,没有给出友好的提示信息,但我们已经实现了该需求。 81 | 82 | ### 循环结构 83 | 84 | **循环结构**:表示某段代码在指定条件下进行重复执行动作。 85 | 86 | 在 MySQL 中,没有`for`循环,仅有`while`循环、`loop`循环和`repeat`循环,呃,还有一种非标准的`goto`循环,在此我们仅介绍`while`循环,其基本语法为: 87 | 88 | ``` 89 | while 条件判断 do 90 | -- 满足条件时要执行的代码 91 | -- 变更循环条件 92 | end while; 93 | ``` 94 | 在使用循环结构的时候,我们经常需要对循环进行控制,即在循环结构内部进行判断和控制。虽然在 MySQL 中没有`continue`和`break`,但是有其替代关键字: 95 | 96 | - `iterate`:迭代,类似于`continue`,表示结束本次循环,不执行后续步骤,直接开始下一次循环; 97 | - `leave`:离开,类似于`break`,直接结束整个循环。 98 | 99 | 上述两个关键字的使用方法为, 100 | 101 | - **基本语法**:`iterate/leave + 循环名称;` 102 | 103 | 因此,在我们定义循环结构的时候,就需要进行略微的修改了,具体形式如下: 104 | 105 | ``` 106 | 循环名称: while 条件判断 do 107 | -- 满足条件时要执行的代码 108 | -- 变更循环条件 109 | iterate/leave 循环名称; -- 控制循环语句 110 | end while; 111 | ``` 112 | 113 | 由于触发器只能执行简单的一次触发动作,因此不适合演示循环结构。循环结构需要结合`函数`进行使用,所以在介绍函数的时候,我们再来体验循环结构的魅力。 114 | 115 | ---------- 116 | 117 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 118 | 119 | 120 | ---------- 121 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 122 | -------------------------------------------------------------------------------- /articles/collate.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(六)「校对集问题」 2 | 3 | 校对集问题 4 | ===== 5 | 6 | **校对集,其实就是数据的比较方式。** 7 | 8 | 校对集,共有三种,分别为: 9 | 10 | - `_bin`:binary,二进制比较,区分大小写; 11 | - `_cs`:case sensitive,大小写敏感,区分大小写; 12 | - `_ci`:case insensitive,大小写不敏感,不区分大小写。 13 | 14 | 查看(全部)校对集 --> 基本语法:`show collation;` 15 | 16 | ![show-collation](https://github.com/guobinhit/mysql-tutorial/blob/master/images/collate/show-collation.png) 17 | 18 | 如上图所示,MySQL 数据库支持百多种校对集。 19 | 20 | 接下来,咱们在一起看看校对集的应用,因为只有当数据进行比较的时候,校对集才会生效。在这里,咱们用`utf8`的`_bin`和`_ci`两种校对集进行比较: 21 | 22 | ``` 23 | -- 创建两张使用不同校对集的表 24 | create table my_collate_bin( 25 | name char(10) 26 | )charset utf8 collate utf8_bin; 27 | 28 | create table my_collate_ci( 29 | name char(10) 30 | )charset utf8 collate utf8_general_ci; 31 | 32 | ``` 33 | 34 | ![create-collate-bin-ci](https://github.com/guobinhit/mysql-tutorial/blob/master/images/collate/create-collate-bin-ci.png) 35 | 36 | 如上图所示,咱们创建了两张表,分别为`my_collate_bin`和`my_collate_ci`,其校对集分别为`_bin`和`_ci`. 然后,分别向这两张表中添加数据: 37 | 38 | ``` 39 | -- 向表中添加数据 40 | insert into my_collate_bin values ('a'),('A'),('B'),('b'); 41 | insert into my_collate_ci values ('a'),('A'),('B'),('b'); 42 | ``` 43 | 44 | 再分别查看两张表中的数据: 45 | 46 | ``` 47 | -- 查看表中的数据 48 | select * from my_collate_bin; 49 | select * from my_collate_ci; 50 | ``` 51 | ![select-collate-bin-ci](https://github.com/guobinhit/mysql-tutorial/blob/master/images/collate/select-collate-bin-ci.png) 52 | 53 | 下面,咱们根据表中的某个字段(在这里`my_collate_bin`和`my_collate_ci`都仅有一个字段)进行排序,其基本语法为: 54 | 55 | ``` 56 | order by + 字段名 + [asc/desc]; 57 | ``` 58 | 其中,`asc`表示升序,`desc`表示降序,默认为升序。执行如下 SQL 语句: 59 | 60 | ``` 61 | -- 排序比较 62 | select * from my_collate_bin order by name; 63 | select * from my_collate_ci order by name; 64 | ``` 65 | 66 | ![order-show](https://github.com/guobinhit/mysql-tutorial/blob/master/images/collate/order-show.png) 67 | 68 | 如上图所示,显然校对集生效啦! 69 | 70 | 此外,咱们需要特别注意的是: **校对集必须在没有数据之前声明好,如果有了数据之后,再进行校对集的修改,则修改无效。** 71 | 72 | 73 | ---------- 74 | 75 | **温馨提示**:用符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 76 | 77 | ---------- 78 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /articles/column-null-comment-default.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(九)「列属性 之 空属性、列描述和默认值」 2 | 3 | ## 列属性 4 | 5 | 列属性:实际上,**真正约束字段的是数据类型,但是数据类型的约束比较单一,因此就需要额外的一些约束来保证数据的有效性,这就是列属性。** 6 | 7 | 列属性有很多,例如:`null`、`not null`、`default`、`primary key`、`unique key`、`auto_increment`和`comment`等。 8 | 9 | ### 空属性 10 | 11 | 空属性有两个值,分别为:`null`和`not null`. 12 | 13 | 虽然默认数据库的字段基本都为空,但是**实际上在真正开发的时候,要尽可能的保证数据不为空,因为空数据没有意义,也没办法参与运算**。 14 | 15 | 执行如下 SQL 语句,进行演示: 16 | 17 | ``` 18 | -- 空属性演示 19 | create table my_class( 20 | grade varchar(20) not null, 21 | room varchar(20) null -- 显式声明为空,实际上,默认就为空 22 | )charset utf8; 23 | ``` 24 | 25 | ![create-table-myclass](https://github.com/guobinhit/mysql-tutorial/blob/master/images/column-null-comment-default/create-table-myclass.png) 26 | 27 | ### 列描述 28 | 29 | 列描述:`comment`,表示描述,没有实际含义,**是专门用来描述字段的,其会随着表创建语句自动保存,用来给程序员(数据库管理员)了解数据库使用。** 30 | 31 | 执行如下 SQL 语句,进行演示: 32 | 33 | ``` 34 | -- 列描述演示 35 | create table my_friend( 36 | name varchar(20) not null comment '姓名', 37 | age tinyint not null comment '年龄' 38 | )charset utf8; 39 | ``` 40 | ![create-table-myfriend](https://github.com/guobinhit/mysql-tutorial/blob/master/images/column-null-comment-default/create-table-myfriend.png) 41 | 42 | ### 默认值 43 | 44 | 默认值:`default`,**某一数据会经常性出现某个具体的值,因此可以在开始的时候就指定好,而在需要真实数据的时候,用户可以选择性的使用默认值。** 45 | 46 | 执行如下 SQL 语句,进行演示: 47 | 48 | ``` 49 | -- 默认值演示 50 | create table my_default( 51 | name varchar(20) not null, 52 | age tinyint unsigned default 0, 53 | gender enum('男','女') default '男' 54 | )charset utf8; 55 | ``` 56 | 57 | ![create-table-mydefault](https://github.com/guobinhit/mysql-tutorial/blob/master/images/column-null-comment-default/create-table-mydefault.png) 58 | 59 | 如上图所示,在列属性`Default`中已经展示了`age`和`gender`字段的默认值,这说明咱们设置成功啦!接下来,咱们再演示如何使用默认值: 60 | 61 | ``` 62 | -- 演示默认值的使用(即不该对应的字段赋值) 63 | insert into my_default (name) values ('Charies'); 64 | insert into my_default values ('Guo',18,default); 65 | ``` 66 | 67 | ![insert-mydefault](https://github.com/guobinhit/mysql-tutorial/blob/master/images/column-null-comment-default/insert-mydefault.png) 68 | 69 | 观察上面的 SQL 语句及执行结果,相信大家已经知道如何使用默认值啦,即不给设置默认值的字段赋值或者用`default`代替相应的字段值。 70 | 71 | 72 | ---------- 73 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 74 | -------------------------------------------------------------------------------- /articles/column-type-data.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(九)「列类型 之 数值型」 2 | 3 | 列类型(数据类型) 4 | ========= 5 | 所谓的列类型,其实就是指数据类型,即对数据进行统一的分类,从系统的角度出发是为了能够使用统一的方式进行管理,更好的利用有限的空间。 6 | 7 | 在 SQL 中,将数据类型分成了三大类,分别为:**数值型、字符串型和日期时间型。** 8 | 9 | ![1](http://img.blog.csdn.net/20170505201016682) 10 | 11 | 对于数值型数据,可以进一步将其划分为**整数型**和**小数型**。 12 | 13 | 整数型 14 | --- 15 | 16 | 在 SQL 中,由于要考虑节省磁盘空间的问题,因此系统又将整型细分成五类,分别为: 17 | 18 | - `tinyint`:迷你整型,使用 1 个字节存储数据(常用); 19 | - `smallint`:小整型,使用 2 个字节存储数据; 20 | - `mediumint`:中整型,使用 3 个字节存储数据; 21 | - `int`:标准整型,使用 4 个字节存储数据(常用); 22 | - `bigint`:大整型,使用 8 个字节存储数据。 23 | 24 | 接下来,输入如下 SQL 语句进行测试: 25 | 26 | ``` 27 | -- 创建整型表 28 | create table my_int( 29 | int_1 tinyint, 30 | int_2 smallint, 31 | int_3 int, 32 | int_4 bigint 33 | )charset utf8; 34 | ``` 35 | 36 | ![2](http://img.blog.csdn.net/20170505214100825) 37 | 38 | 如上图所示,咱们已经成功创建`my_int`表,再插入数据: 39 | 40 | ``` 41 | -- 插入数据 42 | insert into my_int values (1,2,3,4); 43 | insert into my_int values ('a','b','c','d'); 44 | insert into my_int values (255,2,3,4); 45 | ``` 46 | 47 | ![3](http://img.blog.csdn.net/20170505214735859) 48 | 49 | 如上图所示,通过列类型,咱们可以限定插入数据的类型以及长度范围。 50 | 51 | 至于为什么在对`int_1`赋值时,报出超出范围的错误,则是因为在 SQL 中数值类型默认是有符号位的,即分正负。如果需要使用无符号的数据,这就需要咱们自己对数据类型进行声明啦,即在声明数据类型时,追加`unsigned`关键字。例如: 52 | 53 | ``` 54 | -- 在 my_int 表中,添加 int_5 字段,设置其数据类型为 tinyint unsigned 55 | alter table my_int add int_5 tinyint unsigned; 56 | ``` 57 | ![4](http://img.blog.csdn.net/20170505215530129) 58 | 59 | 如上图所示,添加`int_5`字段成功,继续插入数据: 60 | 61 | ``` 62 | -- 插入数据 63 | insert into my_int values (1,2,3,4,255); 64 | ``` 65 | 66 | ![5](http://img.blog.csdn.net/20170505215905568) 67 | 68 | 如上图所示,当咱们将`tinyint`限定为`unsigned`之后,已经可以插入`0~255`之间的任何整数啦!但是,回过头来,让咱们仔细看看下面这张图: 69 | 70 | ![6](http://img.blog.csdn.net/20170505220452057) 71 | 72 | 通过观察上面这张图,咱们会发现:**每个字段的数据类型后面都会跟着一对括号,并且里面含有数字。**这些数字啊,其实并没有什么特别的含义,只是表示数据的显示宽度。实际上,咱们可以修改显示的宽度,但是这种修改并不会改变数据本身的大小。 73 | 74 | **显示宽度的意义**:在于当数据不够显示宽度的时候,会自动让数据变成对应的显示宽度,通常需要搭配一个前导`0`来增加宽度,其不改变数据值的大小,即用`zerofill`进行零填充,并且零填充会导致数值自动变成无符号。 75 | 76 | 下面,执行如下 SQL 语句: 77 | 78 | ``` 79 | -- 在 my_int 表中,添加 int_6 字段,设置其数据类型为 tinyint zerofill 80 | alter table my_int add int_6(3) tinyint zerofill; 81 | ``` 82 | 83 | ![7](http://img.blog.csdn.net/20170505221652339) 84 | 85 | 再插入数据,进行测试: 86 | 87 | ``` 88 | -- 插入数据 89 | insert into my_int values (1,2,3,4,5,6); 90 | ``` 91 | 92 | ![8](http://img.blog.csdn.net/20170505222047969) 93 | 94 | 如上图所示,**零填充的意义**:在于保证数据的格式。 95 | 96 | 小数型 97 | --- 98 | 小数型,即**带有小数点或者范围超出整型的数值类型**。 99 | 100 | 在 SQL 中,将小数型细分为**浮点型**和**定点型**两种,其中: 101 | 102 | - 浮点型:小数点浮动,精度有限,容易丢失精度; 103 | - 定点型:小数点固定,精度固定,不会丢失精度。 104 | 105 | **第 1 种**:浮点型 106 | 107 | 浮点型数据是一种精度型数据,因为超出指定范围之后,其会丢失精度,自动进行四舍五入操作。理论上,浮点型分为两种精度: 108 | 109 | - `float`:单精度,占用 4 个字节存储数据,精度范围大概为 7 位左右; 110 | - `double`:双精度,占用 8 个字节存储数据,精度范围大概为 15 位左右。 111 | 112 | **浮点型的使用方式**:如果直接用`float`,则表示没有小数部分;如果用`float(M,D)`,其中`M`代表总长度,`D`代表小数部分长度,`M-D`则为整数部分长度。 113 | 114 | 执行如下 SQL 语句创建浮点数表,进行测试: 115 | 116 | ``` 117 | -- 创建浮点数表 118 | create table my_float( 119 | f1 float, 120 | f2 float(10,2), 121 | f3 float(6,2) 122 | )charset utf8; 123 | ``` 124 | 在咱们向浮点数表`my_float`插入数据的时候,可以直接插入小数,也可以插入用科学计数法表示的数据。此外,插入浮点型数据时,整数部分是不能超出长度范围的,但是小数部分是可以超出长度范围的,系统会自动进行四舍五入的操作。特别是,如果浮点数是因为系统进位(四舍五入)导致整数部分超出指定的长度,那么系统是允许成立的。 125 | 126 | ``` 127 | -- 插入测试数据 128 | insert into my_float values (2.15e4,20.15,9999.99); 129 | insert into my_float values (20151120,123456789.99,9999.99); 130 | insert into my_float values (5211314,123456.99,99.99999); 131 | ``` 132 | 133 | ![1](http://img.blog.csdn.net/20170506102816519) 134 | 135 | 如上图所示,咱们的结论得到了验证。 136 | 137 | **第 2 种**:定点型 138 | 139 | 定点型数据,绝对的保证整数部分不会被四舍五入,也就是说不会丢失精度,但小数部分有可能丢失精度,虽然理论上小数部分也不会丢失精度。 140 | 141 | 执行如下 SQL 语句创建定点数表,以浮点数做对比,进行测试: 142 | 143 | ``` 144 | -- 创建定点数表 145 | create table my_decimal( 146 | f1 float(10,2), 147 | d1 decimal(10,2) 148 | )charset utf8; 149 | ``` 150 | 当咱们插入数据的时候,定点数的整数部分一定不能超出长度范围(进位也不可以),小数部分的长度则可以随意超出,没有限制,系统会自动进行四舍五入的操作: 151 | 152 | ``` 153 | -- 插入测试数据 154 | insert into my_decimal values (99999999.99,99999999.99); 155 | insert into my_decimal values (123456789.99,2015.1314); 156 | insert into my_decimal values (123456.99,2015.1314); 157 | ``` 158 | 159 | ![2](http://img.blog.csdn.net/20170506105942273) 160 | 161 | 如上图所示,咱们的结论同样得到了验证。 162 | 163 | 164 | ---------- 165 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /articles/column-type-date.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十)「列类型 之 日期时间型」 2 | 3 | 列类型(数据类型) 4 | ========= 5 | 所谓的列类型,其实就是指数据类型,即对数据进行统一的分类,从系统的角度出发是为了能够使用统一的方式进行管理,更好的利用有限的空间。 6 | 7 | 在 SQL 中,将数据类型分成了三大类,分别为:**数值型、字符串型和日期时间型。** 8 | 9 | ![1](http://img.blog.csdn.net/20170505201016682) 10 | 11 | 日期时间型 12 | --- 13 | 14 | 日期时间型数据,顾名思义,就是用来表示日期和时间的数据类型,共有五种类型,分别为: 15 | 16 | - `datetime`:日期时间,其格式为`yyyy-MM-dd HH:mm:ss`,表示的范围是从 1000 年到 9999 年,有零值,即`0000-00-00 0000:00`; 17 | - `date`:日期,就是`datetime`的`date`部分; 18 | - `time`:时间,或者说是时间段,为指定的某个时间区间之间,包含正负时间; 19 | - `timestamp`:时间戳,但并不是真正意义上的时间戳,其是从`1970`年开始计算的,格式和`datetime`一致; 20 | - `year`:年份,共有两种格式,分别为`year(2)`和`year(4)`. 21 | 22 | 执行如下 SQL 语句创建日期时间表,进行测试: 23 | 24 | ``` 25 | -- 创建日期时间表 26 | create table my_date( 27 | d1 datetime, 28 | d2 date, 29 | d3 time, 30 | d4 timestamp, 31 | d5 year 32 | )charset utf8; 33 | ``` 34 | 35 | 当咱们插入数据时,日期时间型中的`time`,可以为负数,甚至可以是很大的负数;`year`,可以使用 2 位数据插入,也可以使用 4 位数据插入;`timestamp`,只要当前所在的记录被更新,该字段就会自动更新为当前时间,且**时间戳类型默认为非空的**。 36 | 37 | ``` 38 | -- 插入测试数据 39 | insert into my_date values ('2017-05-06 13:15:00','2017-05-06','13:15:00','2017-05-06 13:15:00',2017); 40 | insert into my_date values ('2017-05-06 13:15:00','2017-05-06','-113:15:00','2017-05-06 13:15:00',69); 41 | insert into my_date values ('2017-05-06 13:15:00','2017-05-06','-2 13:15:00','2017-05-06 13:15:00',70); 42 | ``` 43 | 44 | ![3](http://img.blog.csdn.net/20170506132014635) 45 | 46 | 如上图所示,以上 3 条记录已经插入成功,接下来,咱们再来验证更新记录时,时间戳类型的字段`d4`是否会自动更新: 47 | 48 | ``` 49 | -- 更新记录,验证时间戳类型的字段是否会自动更新 50 | update my_date set d1 = '2017-05-06 13:24:00' where d5 = 1970; 51 | ``` 52 | 53 | ![5](http://img.blog.csdn.net/20170506132904083) 54 | 55 | 如上图所示,显然咱们的结论全部得到了验证。 56 | 57 | ---------- 58 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 59 | -------------------------------------------------------------------------------- /articles/column-type-string.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十一)「列类型 之 字符串型」 2 | 3 | 列类型(数据类型) 4 | ========= 5 | 所谓的列类型,其实就是指数据类型,即对数据进行统一的分类,从系统的角度出发是为了能够使用统一的方式进行管理,更好的利用有限的空间。 6 | 7 | 在 SQL 中,将数据类型分成了三大类,分别为:**数值型、字符串型和日期时间型。** 8 | 9 | ![1](http://img.blog.csdn.net/20170505201016682) 10 | 11 | 字符串型 12 | --- 13 | 14 | 在 SQL 中,将字符串类型分成了 6 类,分别为:`char`、`varchar`、`text`、`blob`、`enum`和`set`. 15 | 16 | **第 1 类:定长字符串** 17 | 18 | 定长字符串:`char`,即磁盘(二维表)在定义结构的时候就已经确定了最终数据的存储长度。 19 | 20 | - `char(L)`:L 表示 Length,即可以存储的长度,单位为字符,最大长度为 255; 21 | - `char(4)`:表示在 UTF8 环境下,需要 4*3=12 个字节。 22 | 23 | **第 2 类:变长字符串** 24 | 25 | 变长字符串:`varchar`,即在分配存储空间的时候,按照最大的空间分配,但是实际用了多少,则是根据具体的数据来确定。 26 | 27 | - `varchar(L)`:L 表示 Length,理论长度是 65536,但是会多出 1 到 2 个字节来确定存储的实际长度; 28 | - `varchar(10)`:例如存储 10 个汉字,在 UTF8 环境下,需要 10*3+1=31 个字节。 29 | 30 | 实际上,如果存储长度超过 255 个字符,则既不用定长字符串也不用变长字符串,而是用文本字符串`text`. 31 | 32 | 如何选择定长字符串或者是变长字符串呢? 33 | 34 | - 定长字符串对磁盘空间比较浪费,但是效率高:如果数据基本上确定长度都一样,就使用定长字符串,例如身份证、电话号码等; 35 | - 变长字符串对磁盘空间比较节省,但是效率低:如果数据不能确定长度(不同的数据有变化),就使用变长字符串,例如地址、姓名等。 36 | 37 | **第 3 类:文本字符串** 38 | 39 | 如果数据量非常大,通常说超过 255 个字符就会使用文本字符串。 40 | 41 | 文本字符串根据存储的格式进行分类,可以分为: 42 | 43 | - `text`:存储文字; 44 | - `blob`:存储二进制数据(其实际上都是存储路径),通常不用。 45 | 46 | **第 4 类:枚举字符串** 47 | 48 | 枚举字符串:`enum`,需要事先将所有可能出现的结果都设计好,实际上存储的数据必须是规定好的数据中的一个。 49 | 50 | 枚举字符串的使用方式: 51 | 52 | - 定义:`enum('元素1','元素2','元素3'...)`,例如`enum('男','女','保密')`; 53 | - 使用:存储的数据,只能是事先定义好的数据。 54 | 55 | 执行如下 SQL 语句创建枚举表,进行测试: 56 | 57 | ``` 58 | -- 创建枚举表 59 | create table my_enum( 60 | gender enum('男','女','保密') 61 | )charset utf8; 62 | ``` 63 | 64 | ![2](http://img.blog.csdn.net/20170521214843424) 65 | 66 | 再执行如下 SQL 语句,向表`my_enum`中插入测试数据: 67 | 68 | ``` 69 | -- 插入测试数据 70 | insert into my_enum values ('男'),('女'),('保密'); 71 | insert into my_enum values ('male'); 72 | ``` 73 | ![3](http://img.blog.csdn.net/20170521215211842) 74 | 75 | 通过上面的测试,咱们可以发现使用枚举字符串有一个好处,那就是:**规范数据格式,插入表中的数据只能是事先定义好的某个数据。** 76 | 77 | 此外,枚举字符串还有一个作用,那就是:**节省存储空间(枚举数据通常都有一个别名),枚举实际上存储的是数值而不是字符串本身。** 78 | 79 | 在 MySQL 中,系统是有自动转换数据格式的功能的。在这里,咱们可以证明枚举字段存储的是数值,具体方法为:将数据取出来`+0`,如果是字符串最终结果永远为`0`,否则就是其他值。 80 | 81 | ``` 82 | -- 验证枚举字段实际存储的格式 83 | select gender + 0,gender from my_enum; 84 | ``` 85 | 86 | ![4](http://img.blog.csdn.net/20170521220113393) 87 | 88 | 观察上述结果,咱们可以找出枚举元素的实际规律,即按照元素出现的顺序,从`1`开始编号。接下来,咱们再来了解**枚举的原理**: 89 | 90 | - 枚举在进行数据规范(定义)的时候,系统会自动建立一个数字与枚举元素的对应关系(放在日志中);在进行数据插入的时候,系统自动将字符串转换为对应的数值进行存储;在进行数据提取的时候,系统自动将数值转换成对应的字符串进行显示。 91 | 92 | 通过阅读以上枚举的原理,咱们可以知道:**使用枚举的效率并不高(低于其他类型的数据),但能规范数据和节省存储空间。** 93 | 94 | **第 5 类:集合字符串** 95 | 96 | 集合字符串:`set`,跟枚举类似,实际存储的是数值而不是字符串。 97 | 98 | 集合字符串的使用方式: 99 | 100 | - 定义:`set`,元素列表; 101 | - 使用:可以使用元素列表中的多个元素,用逗号分隔。 102 | 103 | 执行如下 SQL 语句创建枚举表,进行测试: 104 | 105 | ``` 106 | -- 创建集合表 107 | create table my_set( 108 | hobby set('音乐','电影','旅行','美食','摄影','运动','宠物') 109 | )charset utf8; 110 | ``` 111 | 112 | ![5](http://img.blog.csdn.net/20170521223557192) 113 | 114 | 再执行如下 SQL 语句,向表`my_set`中插入测试数据: 115 | ``` 116 | -- 插入测试数据 117 | insert into my_set values ('电影,美食,宠物'); 118 | insert into my_set values (3); 119 | ``` 120 | 121 | ![6](http://img.blog.csdn.net/20170521223912147) 122 | 123 | 再执行如下 SQL 语句,查看表`my_set`中的数据: 124 | 125 | ``` 126 | -- 查看数据 127 | select hobby + 0,hobby from my_set; 128 | ``` 129 | 130 | ![7](http://img.blog.csdn.net/20170521224106226) 131 | 132 | 观察上面的结果,相信大部分童鞋也懵啦!对于`3`还好理解,`3=2+1`,对应于集合中数据的编号,也正是`音乐`和`电影`;但是`74`是什么鬼啊?在此,咱们不妨将集合(`'音乐','电影','旅行','美食','摄影','运动','宠物'`)中的元素选中的记为`1`,没有选中的记为`0`,表示成二进制,也就是: 133 | 134 | - `0101001` 135 | 136 | 再将上面的二进制反过来: 137 | 138 | - `1001010` 139 | 140 | 不妨算算,上述二进制对应的十进制数,即为`74`. 141 | 142 | 到这里,相信大家已经恍然大悟啦,原来:**集合字符串中每一个元素都对应一个二进制位,其中被选中的为`1`,未选中的为`0`,最后在反过来,这个二进制数对应的十进制数即为其数据库中实际存储的是数值。** 143 | 144 | 此外,集合字符串中插入元素的顺序并没有影响,最终系统都会自动去匹配集合的顺序,即: 145 | 146 | ``` 147 | -- 插入测试数据 148 | insert into my_set values ('电影,美食,旅行'); 149 | insert into my_set values ('旅行,电影,美食'); 150 | ``` 151 | 152 | 上述两个 SQL 语句会产生相同的结果: 153 | 154 | ![8](http://img.blog.csdn.net/20170521230456356) 155 | 156 | 如上图所示,显然咱们的结论得到了验证。 157 | 158 | 最后,集合的原理同枚举类似,因此可以的到相同的结论,即:**使用集合的效率并不高(低于其他类型的数据),但能规范数据和节省存储空间。** 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | ---------- 168 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 169 | -------------------------------------------------------------------------------- /articles/database-variable.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二十九)「数据库变量」 2 | 3 | ## 变量 4 | 5 | 在 MySQL 数据库中,变量有两种,分别为:**系统变量**和**自定义变量**。 6 | 7 | 根据变量的作用范围,又分为: 8 | 9 | - **会话级别变量**:仅对当前客户端当次连接有效; 10 | - **全局级别变量**:对所有客户端的任一次连接都有效。 11 | 12 | ### 系统变量 13 | 14 | 系统变量,顾名思义,是系统设置好的变量(皆为全局级别变量),也是用来控制服务器表现的,如`autocommit`、`wait_timeout`等。 15 | 16 | 大多数的时候,我们并不需要使用系统变量,但我们仍然需要了解有这么回事,在必须要的时候,它可以帮助我们完成特殊的需求。 17 | 18 | 首先,查看系统变量,语法为: 19 | 20 | - **基本语法**:`show variables;` 21 | 22 | 执行如下 SQL 语句,进行测试: 23 | 24 | ``` 25 | -- 查看系统变量 26 | show variables; 27 | ``` 28 | 29 | ![show-variables](https://github.com/guobinhit/mysql-tutorial/blob/master/images/database-variable/show-variables.png) 30 | 31 | 如上图所示,显示了 MySQL 在本服务器上共含有 506 个系统变量。更近一步,我们可以查看具体的系统变量的值,语法为: 32 | 33 | - **基本语法**:`select + @@变量名 + [, @@变量名, ... , @@变量名];` 34 | 35 | 执行如下 SQL 语句,进行测试: 36 | 37 | ``` 38 | -- 查看具体的系统变量的值 39 | select @@autocommit,@@version,@@version_compile_os,@@wait_timeout; 40 | ``` 41 | 42 | ![select-system-var](https://github.com/guobinhit/mysql-tutorial/blob/master/images/database-variable/select-system-var.png) 43 | 44 | 如上图所示,我们查到了具体的变量的值。此外,**任何一个有内容返回的查询操作都是用`select`来完成的**。 45 | 46 | 接下来,我们尝试修改系统变量,先修改会话级别变量,再修改全局级别变量。 47 | 48 | 对于修改会话级别变量,有两种方法,语法分别为: 49 | 50 | - **基本语法 1**:`set 变量名 = 值;` 51 | - **基本语法 2**:`set @@变量名 = 值;` 52 | 53 | 执行如下 SQL 语句,进行测试: 54 | 55 | ``` 56 | -- 设置会话级别变量 57 | set autocommit = 0; 58 | set @@wait_timeout = 20000; 59 | 60 | -- 查看系统变量 61 | select @@autocommit, @@wait_timeout; 62 | ``` 63 | 64 | ![set-section-var](https://github.com/guobinhit/mysql-tutorial/blob/master/images/database-variable/set-section-var.png) 65 | 66 | 如上图所示,我们修改了`autocommit`和`wait_timeout`的值,但仅作用于会话级别,即只有当前当次连接有效,当再次打开一个新窗口的时候,我们会发现所有的变量值都恢复如初。 67 | 68 | 对于修改全局级别变量,语法为: 69 | 70 | - **基本语法**:`set global 变量名 = 值;` 71 | 72 | 执行如下 SQL 语句,进行测试: 73 | 74 | ``` 75 | -- 设置全局级别变量 76 | set global autocommit = 0; 77 | 78 | -- 查看系统变量 79 | select @@autocommit; 80 | ``` 81 | 82 | ![set-global-var](https://github.com/guobinhit/mysql-tutorial/blob/master/images/database-variable/set-global-var.png) 83 | 84 | 如上图所示,当我们修改全局变量的时候,其效果对所有客户端的任一次连接都有效。But,如果某一个客户端在我们修改全局变量之前已经连上了服务器并且没有退出的话,那么我们的修改对其当前当次连接无效,需要重新登录才能生效。 85 | 86 | ## 自定义变量 87 | 88 | 自定义变量,顾名思义,是用户自己定义的变量,并且都是会话级别的变量。 89 | 90 | 系统为了区别系统变量与自定义变量,规定**用户自定义的变量必须使用一个`@`符号**。设置自定义变量的语法为: 91 | 92 | - **基本语法**:`set @变量名 = 值;` 93 | 94 | 执行如下 SQL 语句,进行测试: 95 | 96 | ``` 97 | -- 设置自定义变量 98 | set @name = 'binguo'; 99 | 100 | -- 查看自定义变量 101 | select @name; 102 | ``` 103 | 104 | ![set-varself](https://github.com/guobinhit/mysql-tutorial/blob/master/images/database-variable/set-varself.png) 105 | 106 | 观察上图,我们会发现查看自定义变量和系统变量有些细微的区别,那就是:查看系统变量时,`select`后面是跟着`@@`的,而查看自定义变量时,`select`后面是跟着`@`的。在这里,我们需要注意:**在 MySQL 中,很多地方会默认将`=`处理为比较符号,因此 MySQL 还提供了另外一种赋值符号`:=`,即冒号与等号拼接而成的符号**。 107 | 108 | 此外,MySQL 允许我们从数据表中获取数据,然后直接赋值给变量,共有两种方式,分别为: 109 | 110 | **第 1 种**:边赋值,边查看结果。语法为 111 | 112 | - **基本语法**:`select @变量名 := 字段名 from 表名;` 113 | 114 | 执行如下 SQL 语句,进行测试: 115 | 116 | ``` 117 | -- 从数据表中获取数据,然后直接为自定义变量赋值 118 | select @name = name from student; 119 | 120 | -- 查看自定义变量 121 | select @name; 122 | ``` 123 | 124 | ![select-var-student](https://github.com/guobinhit/mysql-tutorial/blob/master/images/database-variable/select-var-student.png) 125 | 126 | 如上图所示,呃,这是什么鬼?好吧,细心的同学估计已经发现了,在上面的`select`语句中,我们误将`:=`写为`=`啦,然后 MySQL 将`=`处理为比较符号,并且在`student`表中没有发现与`binguo`匹配的名字,因此显示的结果皆为`0`,如果匹配成功,则会显示`1`。下面,我们修改赋值符号,重新进行测试: 127 | 128 | ``` 129 | -- 从数据表中获取数据,然后直接为自定义变量赋值 130 | select @name := name from student; 131 | 132 | -- 查看自定义变量 133 | select @name; 134 | ``` 135 | 136 | ![select-var-student-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/database-variable/select-var-student-2.png) 137 | 138 | 如上图所示,我们会发现上述`select`语句的作用为:从`student`表读取数据,然后依次赋值给自定义变量`@name`,并且先赋的值会被覆盖,仅保留最后一个赋值结果。 139 | 140 | **第 2 种**:只赋值,不查看结果。语法为 141 | 142 | - **基本语法**:`select + 字段列表 + from + 表名 + into + 变量列表;` 143 | 144 | 执行如下 SQL 语句,进行测试: 145 | 146 | ``` 147 | -- 从数据表中获取数据,然后直接为自定义变量赋值 148 | select name from student into @name; 149 | 150 | -- 查看自定义变量 151 | select @name; 152 | 153 | -- 查看 student 表数据 154 | select * from student; 155 | ``` 156 | 157 | ![select-var-student-3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/database-variable/select-var-student-3.png) 158 | 159 | 160 | 如上图所示,显然`EEROR`,内容为:返回结果包含的内容超过一列。实际上,在未加限制条件的情况下,我们直接从表中捞取数据,是捞取全部数据,因此忽略上述 SQL 语句中的`into @name`,其返回的结果为表中的全部`name`值,自然是超过一个了。在这种情况下,系统会报错,却将捞取数据的第一个值赋值给了`@name`,也就是说,在捞取数据超过一条记录的时候,系统会默认将第一个值赋值给自定义变量。 161 | 162 | 虽然上述 SQL 语句修改了`@name`的值,但却是一种错误的赋值方式,也是不可控的,其结果往往并不是我们想要的。对于上述的赋值方式,MySQL 的要求比较严格,规定每次只能获取一条记录。因此正确的做法是,加上一个`where`条件,将查询的结果限制为一条,例如 163 | 164 | ``` 165 | -- 从数据表中获取数据,然后直接为自定义变量赋值 166 | select name from student where id = 2 into @name; 167 | 168 | -- 查看自定义变量 169 | select @name; 170 | ``` 171 | 172 | ![select-var-student-4](https://github.com/guobinhit/mysql-tutorial/blob/master/images/database-variable/select-var-student-4.png) 173 | 174 | 如上图所示,我们获取数据并赋值成功。 175 | 176 | 最后,在强调一点:**自定义变量都是会话级别,只要是当前用户当次连接,都会受到影响,不区分数据库**。 177 | 178 | 179 | ---------- 180 | 181 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 182 | 183 | 184 | ---------- 185 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 186 | -------------------------------------------------------------------------------- /articles/database.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(一)「数据库」 2 | 3 | 数据库 4 | === 5 | 6 | 1 定义 7 | -------- 8 | 9 | 数据库,可以简单的解释为:**高效的存储和处理数据的介质(主要分为磁盘和内存两种)**。 10 | 11 | 2 分类 12 | ---- 13 | 14 | 根据数据库存储介质的不同,可以将其分为两类,即:关系型数据库(SQL)和非关系型数据库(NoSQL,Not Only SQL)。 15 | 16 | 3 举例 17 | ---- 18 | 19 | 关系型数据库: 20 | 21 | - 大型:Oracle、DB2 等; 22 | - 中型:SQL Server、MySQL 等; 23 | - 小型:Access 等。 24 | 25 | 非关系型数据库: 26 | 27 | - Memcached、MongoDB 和 Redis 等。 28 | 29 | 4 区别 30 | ---- 31 | 32 | 关系型数据库: 33 | 34 | - 安全,其将数据保存到磁盘之中,基本不可能出现丢失数据的情况; 35 | - 比较浪费空间,因为其用二维表的形式存储数据。 36 | 37 | 非关系型数据库: 38 | 39 | - 存储数据的效率比较高; 40 | - 不是特别安全,突然断电时会导致数据丢失。 41 | 42 | ---------- 43 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 44 | -------------------------------------------------------------------------------- /articles/datafile.md: -------------------------------------------------------------------------------- 1 | # 详述查看 MySQL 数据文件存储位置的方法 2 | 3 | 我们可能会有一个疑惑,那就是:**当我们在本地(自己的电脑)安装完 MySQL 之后,也创建了很多的数据库啊、表啊,也存储了很多的数据啊,但是这些内容都存储到哪里了呢**?特别是,当我们需要直接操作这些数据文件的时候,翻遍了整个电脑,却找不到 MySQL 的数据文件到底在哪里,这就有些坑爹啦! 4 | 5 | 在这里,教给大家一个非常简单的能够立即定位到 MySQL 数据文件的存储位置方法,即在 MySQL 客户端键入如下命令: 6 | 7 | - `show global variables like "%datadir%";` 8 | 9 | ![show-global-variables](https://github.com/guobinhit/mysql-tutorial/blob/master/images/datafile/show-global-variables.png) 10 | 11 | 如上图所示,MySQL 的数据文件就存放在`Data`目录。至于接下来想查看具体的数据库还是表,这就看大家的心情啦! 12 | 13 | 不过大家可能还会有一个疑问,那就是我们都查到 MySQL 的数据文件在`C`盘的`ProgramData`目录下了,但是翻遍了整个`C`盘却仍然没有找到`ProgramData`文件夹,这是为什么?答案就是:**在默认情况下,`ProgramData`文件夹是隐藏的**。 14 | 15 | 至于如何显示隐藏的文件夹,相信大家都已经玩的很溜啊!`/一脸坏笑`。 16 | 17 | 18 | ---------- 19 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 20 | -------------------------------------------------------------------------------- /articles/duplicate-primary-key.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十六)「数据的高级操作 之 主键冲突」 2 | 3 | ## 数据的高级操作 4 | 5 | 数据的操作,无外乎**增删改查**。 6 | 7 | 新增数据的基本语法为: 8 | 9 | - `insert into + 表名 + [(字段列表)] + values (值列表);` 10 | 11 | 在数据插入的时候,假设主键对应的值已经存在,则插入失败!这就是主键冲突。 12 | 13 | ### 主键冲突 14 | 15 | 当主键存在冲突(duplicate key)的时候,可以选择性的进行处理,即更新或替换。 16 | 17 | 下面,以表`my_class`为例,进行测试: 18 | 19 | ![desc-myclass](https://github.com/guobinhit/mysql-tutorial/blob/master/images/duplicate-primary-key/desc-myclass.png) 20 | 21 | 其中,`grade`为主键。 22 | 23 | **第一种情况:主键冲突,进行更新操作。** 24 | 25 | - 基本语法:`insert into + 表名 + [(字段列表:包含主键)] + values (值列表) on duplicate key update 字段 = 新值;` 26 | 27 | 执行如下 SQL 语句,进行测试: 28 | 29 | ``` 30 | -- 测试主键冲突的 SQL 语句 31 | insert into my_class values ('PM3527','B315'); 32 | ``` 33 | 34 | ![insert-myclass](https://github.com/guobinhit/mysql-tutorial/blob/master/images/duplicate-primary-key/insert-myclass.png) 35 | 36 | 如上图所示,当主键已经存在的时候,产生主键冲突。再执行如下 SQL 语言,解决主键冲突的问题: 37 | 38 | ``` 39 | -- 当主键冲突的时候,进行更新操作 40 | insert into my_class values ('PM3527','B315') 41 | -- 冲突处理 42 | on duplicate key update 43 | -- 更新主键值 44 | room = 'B315'; 45 | ``` 46 | 47 | ![select-myclass](https://github.com/guobinhit/mysql-tutorial/blob/master/images/duplicate-primary-key/select-myclass.png) 48 | 49 | **第二种情况:主键冲突,选择替换操作。** 50 | 51 | - 基本语法:`replace insert into + 表名 + [(字段列表:包含主键)] + values (值列表);` 52 | 53 | 执行如下 SQL 语句,进行测试: 54 | 55 | ``` 56 | -- 测试主键冲突的 SQL 语句 57 | insert into my_class values ('PM3528','B215'); 58 | ``` 59 | 60 | ![insert-error](https://github.com/guobinhit/mysql-tutorial/blob/master/images/duplicate-primary-key/insert-error.png) 61 | 62 | 如上图所示,当主键已经存在的时候,产生主键冲突。再执行如下 SQL 语言,解决主键冲突的问题: 63 | 64 | ``` 65 | -- 当主键冲突的时候,进行替换操作 66 | replace into my_class values ('PM3528','B215'); 67 | ``` 68 | 69 | ![replace-myclass](https://github.com/guobinhit/mysql-tutorial/blob/master/images/duplicate-primary-key/replace-myclass.png) 70 | 71 | 通过以上两种情况的演示,当再发生主键冲突的时候,咱们已经可以从容应对并解决啦! 72 | 73 | 74 | ---------- 75 | 76 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 77 | 78 | 79 | ---------- 80 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 81 | -------------------------------------------------------------------------------- /articles/foreign-key.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二十一)「外键」 2 | 3 | ## 外键 4 | 5 | **外键**:`foreign key`,外面的键,即不在自己表中的键。如果一张表中有一个非主键的字段指向另外一张表的主键,那么将该字段称之为外键。每张表中,可以有多个外键。 6 | 7 | ### 新增外键 8 | 9 | 外键既可以在创建表的时候增加,也可以在创建表之后增加(但是要考虑数据的问题)。 10 | 11 | **第 1 种:在创建表的时候,增加外键** 12 | 13 | - **基本语法**:`foreign key(外键字段) + references + 外部表名(主键字段);` 14 | 15 | 执行如下 SQL 语句,进行测试: 16 | 17 | ``` 18 | -- 创建外键 19 | create table my_foreign1( 20 | id int primary key auto_increment, 21 | name varchar(20) not null comment '学生姓名', 22 | c_id int comment '班级表ID', 23 | -- 增加外键 24 | foreign key(c_id) references class(id) 25 | )charset utf8; 26 | ``` 27 | 28 | ![create-myforeignal1](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/create-myforeignal1.png) 29 | 30 | 观察上图可知,字段`c_id`的`key`显示为`MUL`,表示多个键的意思。这是因为外键要求字段本身是一个索引(普通索引)如果字段本身没有索引,外键就会先创建一个索引,然后才创建外键本身。此外,`CONSTRAINT`后面的`my_foreign_ibfk_1`表示外键的名字。 31 | 32 | **第 2 种:在创建表之后,增加外键** 33 | 34 | - **基本语法**:`alter table + 表名 + add[constraint + 外键名字] + foreign key(外键字段) + references + 外部表名(主键字段);` 35 | 36 | 执行如下 SQL 语句,进行测试: 37 | 38 | ``` 39 | -- 创建外键 40 | create table my_foreign2( 41 | id int primary key auto_increment, 42 | name varchar(20) not null comment '学生姓名', 43 | c_id int comment '班级表ID' 44 | )charset utf8; 45 | 46 | -- 增加外键 47 | alter table my_foreign2 add 48 | -- 指定外键名 49 | constraint test_foreign 50 | -- 指定外键字段 51 | foreign key(c_id) 52 | -- 引用外部表主键 53 | references class(id); 54 | ``` 55 | 56 | ![create-myforeign2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/create-myforeign2.png) 57 | 58 | 如上图所示,显然咱们已经增加外键成功啦! 59 | 60 | 61 | 62 | ### 修改外键 & 删除外键 63 | 64 | 外键不能修改,只能先删除后增加。 65 | 66 | - **基本语法**:`alter table + 表名 + drop foreign key + 外键名字;` 67 | 68 | 执行如下 SQL 语句,进行测试: 69 | 70 | ``` 71 | -- 删除外键 72 | alter table my_foreign1 drop foreign key my_foreign1_ibfk_1; 73 | ``` 74 | 75 | ![desc-myforeign](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/desc-myforeign.png) 76 | 77 | 观察上图可知,删除外键不能通过查看表结构来体现,而是应该通过创建表的语句来查看。 78 | 79 | ### 外键作用 80 | 81 | 首先,给出父表和子表的定义: 82 | 83 | - **父表**,指外键所指向的表; 84 | - **子表**,指相对于父表,拥有外键的表。 85 | 86 | 外键默认的作用有两个,分别对子表和父表进行约束。 87 | 88 | **第 1 种:约束子表** 89 | 90 | 在子表进行数据的写操作(增和改)的时候,如果对应的外键字段在父表找不到对应的匹配,那么操作就会失败。 91 | 92 | 执行如下 SQL 语句,进行测试: 93 | 94 | ``` 95 | -- 插入数据,外键字段在父表不存在 96 | insert into my_foreign2 values(null,'Charies','6'); 97 | 98 | -- 插入数据,外键字段在父表存在 99 | insert into my_foreign2 values(null,'Charies','1'); 100 | ``` 101 | 102 | ![select-class-myforeign2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/select-class-myforeign2.png) 103 | 104 | 如上图所示,在我们向子表`my_foreign2`插入外键字段为`6`的时候,提示插入失败,原因就是在父表`class`中,没有`ID`为`6`的记录。而在我们向子表`my_foreign2`插入外键字段为`1`的时候,提示成功,原因就是在父表`class`中,有`ID`为`1`的记录。 105 | 106 | **第 2 种:约束父表** 107 | 108 | 在父表进行数据的写操作(删和改,且涉及主键)的时候,如果对应的主键字段在子表已经被数据引用,那么操作就会失败。 109 | 110 | 执行如下 SQL 语句,进行测试: 111 | 112 | ``` 113 | -- 更新父表记录 114 | update class set id = 5 where id = 1; 115 | update class set id = 5 where id = 3; 116 | ``` 117 | 118 | ![update-class](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/update-class.png) 119 | 120 | 如上图所示,在我们修改父表`class`中`ID`为`1`的时候,提示修改失败,原因就是在子表`my_foreign2`中已经引用了该值的主键字段。而在我们修改父表`class`中`ID`为`3`的时候,提示修改成功,原因就是在子表`my_foreign2`中并没有引用该值的主键字段。 121 | 122 | ### 外键条件 123 | 124 | 在我们使用外键的时候,应该遵循如下条件: 125 | 126 | - 外键要存在,首先必须保证表的引擎是 InnoDB(默认的存储引擎),如果不是 InnoDB 存储引擎,那么外键可以创建成功,但没有约束作用; 127 | - 外键字段的字段类型(列类型),必须与父表的主键类型完全一致; 128 | - 每张表中的外键名称不能重复; 129 | - 增加外键的字段,如果数据已经存在,那么要保证数据与父表中的主键对应。 130 | 131 | 下面以最后一个条件为例,执行如下 SQL 语句,进行测试: 132 | 133 | ``` 134 | -- 新增数据 135 | insert into my_foreign1 valuse(1,'Gavin',3); 136 | 137 | -- 增加外键 138 | alter table my_foreign1 add foreign key(c_id) references class(id); 139 | ``` 140 | 141 | ![select-insert-class](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/select-insert-class.png) 142 | 143 | 如上图所示,在新增外键的时候,如果子表中(想要新增外键的字段)的数据已经存在,而父表中又没有与子表中(想要新增外键的字段)的数据相匹配的主键的话,那么操作就会失败;反之,则会成功。 144 | 145 | 执行如下 SQL 语句,进行测试: 146 | 147 | ``` 148 | -- 新增数据 149 | insert into class valuse(3,'PM3.4','A115'); 150 | 151 | -- 增加外键 152 | alter table my_foreign1 add foreign key(c_id) references class(id); 153 | ``` 154 | 155 | ![insert-alter-show](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/insert-alter-show.png) 156 | 157 | 如上图所示,显然当父表中存在与子表中(想要新增外键的字段)的数据相匹配的主键的话,增加主键的操作就会成功。 158 | 159 | ### 外键约束 160 | 161 | 所谓外键约束,就是指外键的作用。之前所讲的外键的作用都是默认的作用,实际上,可以通过对外键的需求,进行定制操作。 162 | 163 | 外键约束有三种模式,分别为: 164 | 165 | - `district`:严格模式(默认),父表不能删除或更新一个已经被子表数据引用的记录; 166 | - `cascade`:级联模式,父表的操作,对应子表关联的数据也跟着被删除; 167 | - `set null`:置空模式,父表的操作之后,子表对应的数据(外键字段)被置空。 168 | 169 | 在此需要注意:**以上三种模式,都是对父表的约束**。 170 | 171 | - **基本语法**:`foreign key(外键字段) + references + 父表(主键字段) + [on delete + 模式 + on update + 模式];` 172 | 173 | 通常一个合理的做法(约束模式)是:删除的时候, 子表被置空;更新的时候,子表进行级联操作。 174 | 175 | 执行如下 SQL 语句,进行测试: 176 | 177 | ``` 178 | -- 创建外键,指定模式:删除置空,更新级联 179 | create table my_foreign3( 180 | id int primary key auto_increment, 181 | name varchar(20) not null, 182 | c_id int, 183 | -- 增加外键 184 | foreign key(c_id) 185 | -- 引用父表 186 | references class(id) 187 | -- 指定删除模式 188 | on delete set null 189 | -- 指定更新模式 190 | on update cascade 191 | )charset utf8; 192 | ``` 193 | 194 | ![create-myforeign3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/create-myforeign3.png) 195 | 196 | 如上图所示,在我们指定外键的约束模式之后,通过查看表的创建语句,可以看到具体的约束语句。 197 | 198 | 接下来,执行如下 SQL 语句,继续进行测试: 199 | 200 | ``` 201 | -- 插入数据 202 | insert into my_foreign3 values(null,'Jobs',1), 203 | (null,'Bill',1), 204 | (null,'Mark',1), 205 | (null,'Swift',2), 206 | (null,'Sellen',1); 207 | ``` 208 | ![insert-myforeign3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/insert-myforeign3.png) 209 | 210 | 如上图所示,我们向表`my_foreign3`中插入了 5 条记录。接下来,我们就可以测试外键的级联模式和置空模式啦!呃,对啦,前提是我们需要把与父表`class`相关联的除`my_foreign3`之外的其他子表,也就是`my_foreign1`和`my_foreign2`的外键删除掉,否则的话,由于这两个子表的外键使用了严格模式,会干扰我们接下来的测试。 211 | 212 | 在我们删除表`my_foreign1`和`my_foreign2`的外键之后,执行如下 SQL 语句,测试级联模式: 213 | 214 | ``` 215 | -- 更新父表主键 216 | update class set id = 8 where id = 1; 217 | ``` 218 | 219 | ![select-myforeign3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/select-myforeign3.png) 220 | 221 | 执行如下 SQL 语句,测试置空模式: 222 | 223 | ``` 224 | -- 删除父表主键 225 | delete from class where id = 2; 226 | ``` 227 | 228 | ![select-myforeign3-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/foreign-key/select-myforeign3-2.png) 229 | 230 | 通过以上测试,我们已经验证了级联模式和置空模式的效果。其实,在我们进行删除置空操作的时候,有一个前提,那就是:**子表的外键字段必须允许为空,否则的话,操作是无法成功的**。 231 | 232 | 至此,我们已经把外键的相关操作都演示了一遍。在这里,我们会发现外键的功能非常强大,能够进行各种的约束,也正是由于外键这种约束的强大,其降低了开发语言对数据的可控性,因此在实际的开发中,很少使用外键来处理数据。 233 | 234 | 235 | ---------- 236 | 237 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 238 | 239 | 240 | ---------- 241 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 242 | -------------------------------------------------------------------------------- /articles/function.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(三十二)「函数」 2 | 3 | # 函数 4 | 5 | **函数**,就是将一段代码封装到一个结构中,在需要执行该段代码的时候,直接调用该结构(函数)执行即可。此操作,实现了代码的复用。在 MySQL 中,函数有两种,分别为:系统函数和自定义函数。 6 | 7 | ## 系统函数 8 | 9 | 顾名思义,系统函数就是系统定义好的函数,在需要的时候,我们直接调用即可。 10 | 11 | 任何函数都有返回值(对于空函数,我们就认为其返回值为`空`),而且在 MySQL 中任何有返回值的操作都是通过`select`来操作的,因此 MySQL 的函数调用就是通过`select`来实现的。 12 | 13 | 在 MySQL 中,字符是字符串操作中最常见的基本单位。此外,如果对中文的截取是按字节进行的话,很容易造成乱码的问题。 14 | 15 | 下面,我们介绍一些常见的、对字符进行操作的系统函数:首先,执行如下语句,定义一些变量, 16 | 17 | ``` 18 | set @cn = '你好世界'; 19 | set @en = 'hello world'; 20 | set @one = 'charies'; 21 | set @two = 'gavin'; 22 | set @three = 'Gavin'; 23 | 24 | select @cn, @en, @one, @two, @three; 25 | ``` 26 | 27 | ![set-aite-cn](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/set-aite-cn.png) 28 | 29 | 然后,调用系统函数进行测试: 30 | 31 | - `substring`,截取字符串,单位为字符; 32 | 33 | ![select-substring](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/select-substring.png) 34 | 35 | 如上图所示,在 MySQL 中字符串的位置是从`1`开始,`0`含有特殊的意义。 36 | 37 | 38 | - `char_length`,获取字符长度; 39 | - `length`,获取字节长度; 40 | 41 | ![select-char-length](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/select-char-length.png) 42 | 43 | - `instr`,判断字符串中某个子串是否存在,存在则返回具体的位置,不存在则返回`0`; 44 | 45 | ![select-instr](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/select-instr.png) 46 | 47 | - `lpad`,左填充,将字符串按照某个指定的填充方式,填充到指定(字符)长度; 48 | 49 | ![select-lpad](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/select-lpad.png) 50 | 51 | 如上图所示,在对`@en`进行填充的时候,填充结果为`hellohellhello world`,其中第二个`hello`并没有填充全,这是因为系统函数`lpad`的第二个参数限定的了变量`@en`的具体长度,如示例中我们设置其为`20`,而原`@en`的长度为`11`,因此只能向`@en`中在填充`9`个字符。 52 | 53 | - `insert`,找到目标位置,将指定长度的字符串替换为目标字符串; 54 | 55 | ![select-insert](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/select-insert.png) 56 | 57 | 如上图所示,`insert`函数并没有修改变量自身的值,只是对变量的值进行加工而已。 58 | 59 | - `strcmp`,比较字符串的大小; 60 | 61 | ![select-strcmp](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/select-strcmp.png) 62 | 63 | 如上图所示,在用`strcmp`函数对字符串进行比较的时候不区分大小写(默认校对集),并用`0`表示两个字符串相等;用`-1`表示第一个参数的字符串小于第二个参数的字符串;用`1`表示第一个参数的字符串大于第二个参数的字符串。 64 | 65 | ## 自定义函数 66 | 67 | 对于任意一个函数,其都包含如下要素: 68 | 69 | - 函数名; 70 | - 参数类别(可以为空); 71 | - 返回值; 72 | - 函数体(作用域)。 73 | 74 | 根据上面这些函数要素,我们就来尝试创建自定义函数。 75 | 76 | ### 创建函数 77 | 78 | ``` 79 | -- 基本语法 80 | create function 函数名([参数列表]) returns 数据类型 81 | begin 82 | -- 函数体 83 | -- 返回值,类型为 returns 指定的数据类型 84 | end 85 | ``` 86 | 如果我们定义的函数的函数体内仅含有返回值,则可以省略`begin`和`end`。此外,自定义函数和系统函数的调用方式相同。执行如下语句,进行测试: 87 | 88 | ``` 89 | -- 自定义函数 90 | create function showLove() returns int 91 | return 521; 92 | -- 调用自定义函数 93 | select showLove(); 94 | ``` 95 | ![create-show-love](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/create-show-love.png) 96 | 97 | ### 查看函数 98 | 99 | 查看函数,基本语法为: 100 | 101 | - `show function status + [like 'pattern'];` 102 | 103 | ![show-function-status](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/show-function-status.png) 104 | 105 | 如上图所示,我们可以看到`showLove`函数是属于`test`数据库的,这引出了函数的一个性质,即**函数是属于具体数据库的,在一个数据库定义的函数不能在其定义的数据库外使用,但是可以查看**。 106 | 107 | 查看函数的创建语句,基本语法为: 108 | 109 | - `show create function + 函数名;` 110 | 111 | ![show-create-function](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/show-create-function.png) 112 | 113 | ### 修改函数 & 删除函数 114 | 115 | 函数只能先删除后新增,不能修改。删除函数的基本语法为: 116 | 117 | - `drop function + 函数名;` 118 | 119 | 执行如下语句,进行测试: 120 | 121 | ``` 122 | -- 删除函数 123 | drop function showLove; 124 | -- 查看函数 125 | show function status like 'showLove'\G; 126 | ``` 127 | 128 | ![drop-function](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/drop-function.png) 129 | 130 | ### 函数参数 131 | 132 | 对于函数的参数,一共有两种,分别为形参和实参,其中,形参可以理解为定义函数时使用的参数,且形参必须指定数据类型;实参可以理解为在调用函数时传入的值或变量。因此,函数定义的具体形式应该为: 133 | 134 | - `function 函数名(形参名字 形参类型) returns 返回数据类型` 135 | 136 | 下面,我们定义一个函数,完成一个简单的需求,即求`1`到指定数值的和。代码如下: 137 | 138 | ``` 139 | delimiter $$ 140 | create function addAll(num int) returns int 141 | begin 142 | -- 定义条件变量 143 | set @i = 1; 144 | set @res = 0; -- 保存求和结果 145 | -- 循环求和 146 | while @i <= num do 147 | -- 任何变量想要修改值都必须使用 set 关键字,且 MySQL 中没有 += 或者 ++ 运算符 148 | set @res = @res + @i; 149 | -- 修改循环变量 150 | set @i = @i + 1; 151 | end while; 152 | -- 返回求和结果 153 | return @res; 154 | end 155 | $$ 156 | delimiter ; 157 | ``` 158 | 159 | ![create-addall2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/create-addall2.png) 160 | 161 | 如上图所示,函数已经定义成功。接下来,执行如下语句,进行测试: 162 | 163 | ``` 164 | -- 调用函数求和 165 | select addAll(100); 166 | 167 | -- 查询自定义变量 @res 和 @i 168 | select @res, @i; 169 | ``` 170 | ![select-addall](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/select-addall.png) 171 | 172 | 如上图所示,求和函数`addAll`已经正确执行。此外,我们发现在函数内部使用`@`符号定义的变量`@res`和`@i`在函数外部也是可以查看使用的,这说明:**使用`@`符号定义的变量为全局变量**。 173 | 174 | ### 变量作用域 175 | 176 | 在 MySQL 中,变量的作用域有两种,分别为全局和局部,其中,全局变量可以在任何地方使用;局部变量只能在函数内部使用。 177 | 178 | - 全局变量:使用`set`关键字定义,用`@`符号标识; 179 | - 局部变量:使用`declare`关键字声明,且所用的局部变量必须在函数体开始之前进行声明。 180 | 181 | 接下来,我们利用局部变量定义一个函数,完成一个简单的需求,即求`1`到指定数值的和,要求`10`的倍数不加。代码如下: 182 | 183 | ``` 184 | delimiter $$ 185 | create function addAll2(num int) returns int 186 | begin 187 | -- 声明变量,包含循环变量和结果变量 188 | declare i int default 1; -- 定义局部变量可以含有属性 189 | declare res int default 0; 190 | -- 循环求和 191 | mywhile:while i <= num do 192 | -- 条件判断 193 | if i % 10 = 0 then 194 | -- 修改循环变量 195 | set i = i + 1; 196 | -- 重新循环 197 | iterate mywhile; 198 | end if; 199 | -- 修改结果变量 200 | set res = res + i; 201 | -- 修改循环变量 202 | set i = i + 1; 203 | end while; 204 | -- 返回求和结果 205 | return res; 206 | end 207 | $$ 208 | delimiter ; 209 | ``` 210 | 211 | ![create-addall2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/create-addall2.png) 212 | 213 | 如上图所示,函数已经定义成功。接下来,执行如下语句,进行测试: 214 | 215 | ``` 216 | -- 调用函数求和 217 | select addAll(100), addAll2(100); 218 | ``` 219 | ![select-addall2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/function/select-addall2.png) 220 | 221 | 如上图所示,函数已经正确执行。 222 | 223 | ---------- 224 | 225 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 226 | 227 | 228 | ---------- 229 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 230 | -------------------------------------------------------------------------------- /articles/increment.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十一)「列属性 之 自动增长」 2 | ## 自动增长 3 | 4 | 自动增长:`auto_increment`,**当对应的字段,不给值,或者是默认值,或者是`null`的时候,就会自动的被系统触发,系统会从当前字段中取已有的最大值再进行`+1`操作,得到新的字段值**。 5 | 6 | 自增长通过跟主键进行搭配使用,其特点为: 7 | 8 | - 任何字段要做自增长,前提其本身必须是一个索引,即`key`栏有值; 9 | - 自增长字段必须是数字(整型); 10 | - 每张表最多有一个自增长字段。 11 | 12 | 执行如下 SQL 语句,进行测试: 13 | 14 | ``` 15 | -- 自增长示例 16 | create table my_auto( 17 | id int primary key auto_increment, 18 | name varchar(20) not null 19 | )charset utf8; 20 | ``` 21 | 22 | ![create-table-myauto](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/create-table-myauto.png) 23 | 24 | ### 使用自增长 25 | 26 | 当自增长给定的值为`null`或者默认值的时候,就是触发自动增长。 27 | 28 | ``` 29 | -- 触发自增长 30 | insert into my_auto (name) values('Charies'); 31 | insert into my_auto values(null,'Guo'); 32 | insert into my_auto values(default,'ChariesGuo'); 33 | ``` 34 | ![insert-myauto](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/insert-myauto.png) 35 | 36 | 如上图所示,自增长的第一个元素默认是`1`,自增长每次都是自增`1`。此外,如果自增长对应的字段输入了值,那么自增长失效,但是下一次还是能够正确的自增长,即从取该字段的最大值`+1`. 37 | 38 | 那么,如何确定下一次自增长的数值是什么呢?简单,咱们可以通过查看表的创建语句看到。 39 | 40 | ``` 41 | -- 查看表的创建语句 42 | show create table my_auto; 43 | ``` 44 | ![show-myauto](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/show-myauto.png) 45 | 46 | 如上图所示,显然在咱们之前插入的 3 条记录之后,下一次自增长是`4`,符合咱们的结论。 47 | 48 | ### 修改自增长 49 | 50 | 自增长如果是涉及到字段改变,就必须先删除自增长,然后再增加自增长,因为每张表只能有一个自增长字段。 51 | 52 | 如果修改当前自增长字段已经存在的值,则只能修改比当前已有自增长字段中的最大值更大,不能更小,因为更小不生效。 53 | 54 | - 基本语法:`alter table + 表名 + auto_increment = 值;` 55 | 56 | 执行如下 SQL 语句,进行测试: 57 | 58 | ``` 59 | -- 修改自增长测试 60 | alter table my_auto auto_increment = 2; 61 | ``` 62 | 63 | ![alter-myauto](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/alter-myauto.png) 64 | 65 | 如上图所示,当咱们修改自增长小于当前自增长字段中的最大值时,虽然显示 SQL 语句执行成功,但实际上并没有修改成功。下面,在执行如下 SQL 语句,进行测试: 66 | 67 | ``` 68 | -- 修改自增长测试 69 | alter table my_auto auto_increment = 5; 70 | ``` 71 | 72 | ![alter-myauto-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/alter-myauot-2.png) 73 | 74 | 如上图所示,显然当咱们修改自增长大于当前自增长字段中的最大值时,修改成功。 75 | 76 | 在这里,咱们不妨思考一下,为什么自增长是从`1`开始呢?为什么每次都自增`1`呢?虽然现在咱们不知道是什么原因导致上面的表示形式,但是咱们知道,所有系统的表现(如字符集、校对集)都是由系统内部的变量进行控制的,因此咱们可以查看自增长对应的变量: 77 | 78 | - 基本语法:`show variables like 'auto_increment%';` 79 | 80 | ``` 81 | -- 查看自增长变量 82 | show variables like 'auto_increment%'; 83 | ``` 84 | ![show-variables](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/show-variables.png) 85 | 86 | 如上图所示,其中`auto_increment_increment`表示`步长`,`auto_increment_offset`表示`初始值`. 87 | 88 | 因此,咱们可以通过修改上面的两个变量实现不同的效果,但是需要注意的是:**修改是会话级别,并且修改的是整个数据库,而不是单张表。** 89 | 90 | - 基本语法:`set auto_increment_increment = 值;` 91 | 92 | 执行如下 SQL 语句,进行测试: 93 | 94 | ``` 95 | -- 修改自增长步长 96 | set auto_increment_increment = 5; 97 | insert into my_auto values (null,'Guobinhit'); 98 | ``` 99 | ![set-auto-increment](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/set-auto-increment.png) 100 | 101 | 如上图所示,咱们已经修改成功!接下来,执行如下 SQL 语句,进行测试: 102 | ``` 103 | -- 插入测试数据 104 | insert into my_auto values (null,'Guobinhit'); 105 | insert into my_auto values (default,'Guobinhit'); 106 | ``` 107 | 108 | ![select-myauto](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/select-myauto.png) 109 | 110 | 如上图所示,咱们插入的第一个`Guobinhit`的`id`值竟然是`6`,第二个`Guobinhit`的`id`值倒是在`6`的基础上增加了`5`为`11`正常。这个现象产生的原因是:咱们之前的修改会导致系统产生一个误差,从初始值`1`开始计算加`5`,因此第一个`Guobinhit`的`id`值是`6`. 111 | 112 | 不过说实话,修改自增长并没有什么实际的意义,在此只是想让大家知道:自增长的初始值和步长都是可以修改的而已。 113 | 114 | ### 删除自增长 115 | 116 | 自增长是字段的一个属性,因此可以通过`modify`来进行修改。想要删除自增长的话,**只需要保证字段没有`auto_increment`即可**。 117 | 118 | - 基本语法:`alter table + 表名 + modify + 字段 + 类型;` 119 | 120 | 执行如下 SQL 语句,进行测试: 121 | 122 | ``` 123 | -- 删除自增长 124 | alter table my_auto modify id int primary key; 125 | ``` 126 | ![modify-myauto](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/modify-myauto.png) 127 | 128 | 如上图所示,呃,好吧,出错啦!这是因为表`my_auto`之前已经定义了主键,所以在执行上述 SQL 语句的时候,系统会认为咱们想要定义多个主键,自然就要报错啦!解决方法就是,去掉上述 SQL 语句中的`primary key`即可。 129 | 130 | ![alter-modify-myauto](https://github.com/guobinhit/mysql-tutorial/blob/master/images/increment/alter-modify-myauto.png) 131 | 132 | 如上图所示,显然咱们已经成功删除自增长啦! 133 | 134 | ---------- 135 | 136 | **温馨提示**:符号`+`表示连接的意思。 137 | 138 | ---------- 139 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 140 | -------------------------------------------------------------------------------- /articles/index.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十三)「索引」 2 | 3 | ## 索引 4 | 5 | 索引:**系统根据某种算法,将已有的数据(未来可能新增的数据),单独建立一个文件,这个文件能够实现快速匹配数据,并且能够快速的找到对应的记录**,几乎所有的索引都是建立在字段之上的。 6 | 7 | 索引的意义: 8 | 9 | - 提升查询数据的效率; 10 | - 约束数据的有效性。 11 | 12 | 但是增加索引是有前提条件的,这是因为索引本身会产生索引文件(有的时候可能会比数据本身都大),因此非常耗费磁盘空间。 13 | 14 | - 如果某个字段需要作为查询的条件经常使用,可以使用索引; 15 | - 如果某个字段需要进行数据的有效性约束,也可以使用索引(主键或唯一键)。 16 | 17 | MySQL 中提供了多种索引,包括: 18 | 19 | 1. 主键索引`primary key` 20 | 2. 唯一键索引`unique key` 21 | 3. 全文索引`fulltext index` 22 | 4. 普通索引`index` 23 | 24 | 其中,主键和唯一键咱们之前已经了解过啦!至于普通索引,顾名思义,并没有什么特色,唯一的任务就是加快数据的查询速度。 25 | 26 | 在这里,咱们说说全文索引。全文索引,即根据文章内部的关键字进行索引,其最大的难度就是在于如何确定关键字。对于英文来说,全文索引的建立相对容易,因为英文的两个单词之间有空格;但是对于中文来说,全文索引的建立就比较难啦,因为中文两个字之间不仅没有空格,而是还可以随意组合。 27 | 28 | 29 | ---------- 30 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 31 | -------------------------------------------------------------------------------- /articles/install-mysql.md: -------------------------------------------------------------------------------- 1 | # 详述 MySQL 数据库的安装及配置 2 | 3 | 首先,下载 MySQL 数据库的安装包:[mysql-5.7.17.msi](http://pan.baidu.com/s/1miyoKbu). 4 | 5 | 下载完成之后,双击打开此`msi`文件,进入如下界面: 6 | 7 | ![choosing-a-setup-tyep](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/choosing-a-setup-tyep.png) 8 | 9 | - 标注1:安装所有 MySQL 数据库需要的产品; 10 | - 标注2:仅仅使用 MySQL 数据库的服务器; 11 | - 标注3:仅仅使用 MySQL 数据库的客户端; 12 | - 标注4:安装所有包含 MySQL 数据库的产品; 13 | - 标注5:手动选择需要安装的 MySQL 数据库的产品。 14 | 15 | 在此,咱们只需要选择 **标注2** 所示的`Server only`即可,然后点击`Next`,进入如下界面: 16 | 17 | ![installation](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/installation.png) 18 | 19 | 如上图所示,此为安装提示界面,直接点击`Execute`: 20 | 21 | ![installation-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/installation-2.png) 22 | 23 | - 标注1:表示当前的状态; 24 | - 标注2:表示当前的升级进度; 25 | - 标注3:显示或隐藏升级信息。 26 | 27 | 如上图所示,此界面展示了当前的状态、进度及升级信息,当升级进度达到`100%`后,如下图所示: 28 | 29 | ![installation-3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/installation-3.png) 30 | 31 | 如上图所示,此为 MySQL 数据库升级成功的标志,点击`Next`: 32 | 33 | ![product-configuration](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/product-configuration.png) 34 | 35 | 如上图所示,提示咱们已经进入了产品配置的阶段,直接点击`Next`即可: 36 | 37 | ![type-and-networing](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/type-and-networing.png) 38 | 39 | - 标注1:配置服务器类型; 40 | - 标注2:选择`TCP/IP`协议; 41 | - 标注3:选择端口号为`3306`. 42 | 43 | 如上图所示,选择默认配置即可,点击`Next`: 44 | 45 | ![accounts-and-roles](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/accounts-and-roles.png) 46 | 47 | 如上图所示,此界面为设置账号和角色,在这里,咱们只需要设置`root`账号的密码(必须记住,登录 MySQL 数据库时需要验证)即可,密码至少四位,设置完成后,点击`Next`: 48 | 49 | ![windows-service](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/windows-service.png) 50 | 51 | - 标注1:由于咱们使用的是`mysql-5.7.17`版本,因此默认的服务器名称为`MySQL57`; 52 | - 标注2:默认选择`Standard System Account`即可。 53 | 54 | 如上图所示,选择默认配置即可,点击`Next`: 55 | 56 | ![plugins-and-extensions](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/plugins-and-extensions.png) 57 | 58 | 如上图所示,此为配置`Plugins and Extension`,即配置插件和扩展应用的,不用管它,直接点击`Next`即可: 59 | 60 | ![apply-server-configuration](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/apply-server-configuration.png) 61 | 62 | 如上图所示,此界面为让咱们确认需要应用的服务器配置,确认无误后,点击`Execute`: 63 | 64 | ![apply-server-configuration-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/apply-server-configuration-2.png) 65 | 66 | 如上图所示,正在进行服务器配置,此时,如果电脑弹出提示框,显示“危险”等提示信息,不用管它,这只是安全软件遇到修改配置的时候自动报警而已,直接点击“同意”即可。 67 | 68 | ![apply-server-configuration-3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/apply-server-configuration-3.png) 69 | 70 | 如上图所示,服务器配置完成,点击`Finish`: 71 | 72 | ![product-configuration-next](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/product-configuration-next.png) 73 | 74 | 如上图所示,进一步显示配置完成,直接点击`Next`: 75 | 76 | ![installation-complete](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/installation-complete.png) 77 | 78 | 如上图所示,到这来,咱就已经将 MySQL 安装完成啦,直接点击`Finish`即可。当然,如果咱们想要查看 MySQL 的详细安装日志,可以点击`Copy Log to Clipboard`将日志复制到文本编辑器进行查看。接下来,打开 MySQL 命令行工具,验证 MySQL 是否安装成功: 79 | 80 | ![mysql-client](https://github.com/guobinhit/mysql-tutorial/blob/master/images/install-mysql/mysql-client.png) 81 | 82 | 如上图所示,显然咱们已经安装成功啦! 83 | 84 | 85 | ---------- 86 | 87 | **温馨提示**:在这里,咱们仅仅安装了 MySQL 数据库的服务器,至于客户端工具,推荐`Navicat for MySQL`和`DbVisualizer`. 88 | 89 | ---------- 90 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 91 | -------------------------------------------------------------------------------- /articles/join-query.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二十)「连接查询」 2 | 3 | **连接查询**:将多张表(大于等于 2 张表)按照某个指定的条件进行数据的拼接,其最终结果记录数可能有变化,但字段数一定会增加。 4 | 5 | **连接查询的意义**:在用户查询数据的时候,需要显示的数据来自多张表。 6 | 7 | 连接查询为`join`,使用方式为:**左表`join`右表**。 8 | 9 | - 左表:`join`左边的表; 10 | - 右表:`join`右边的表。 11 | 12 | **连接查询分类**:在 SQL 中将连接查询分为四类,分别为内连接、外链接、自然连接和交叉连接。 13 | 14 | 15 | ## 交叉连接 16 | 17 | **交叉连接**:`cross join`,从一张表中循环取出每一条记录,每条记录都去另外一张表进行匹配,匹配的结果都保留(没有条件匹配),而连接本身的字段会增加,最终形成的结果为笛卡尔积形式。 18 | 19 | - **基本语法**:`左表 cross join 右边;` 20 | 21 | 其结果与多表查询相同。 22 | 23 | 执行如下 SQL 语句,进行测试: 24 | 25 | ``` 26 | -- 将表 student 与 class 进行交叉连接 27 | select * from student cross join class; 28 | -- 将表 student 与 class 进行多表查询 29 | select * from student,class; 30 | ``` 31 | 32 | ![select-student-crossjoin-class](https://github.com/guobinhit/mysql-tutorial/blob/master/images/join-query/select-student-crossjoin-class.png) 33 | 34 | 实际上,笛卡尔积形式(交叉连接和多表查询)的结果并没有什么实际意义,应该尽量避免,其存在的价值就是保证连接这种结构的完整性。 35 | 36 | ## 内连接 37 | 38 | 39 | **内连接**:`inner join`,从左表中取出每一条记录,和右表中的所有记录进行匹配,并且仅当某个条件在左表和右表中的值相同时,结果才会保留,否则不保留。 40 | 41 | - **基本语法**:`左表 + [inner] + join + 右表 + on + 左表.字段 = 右表.字段;` 42 | 43 | 其中,关键字`on`表示连接条件,两表中的条件字段有着相同的业务含义。 44 | 45 | 执行如下 SQL 语句,进行测试: 46 | 47 | ``` 48 | -- 将表 student 与 class 进行内连接 49 | select * from student inner join class on student.grade = class.grade; 50 | select * from student join class on student.grade = class.grade; 51 | ``` 52 | 53 | ![select-student-innerjoin-class](https://github.com/guobinhit/mysql-tutorial/blob/master/images/join-query/select-student-innerjoin-class.png) 54 | 55 | 在这里,值得注意的是:**如果两表中有某个表的条件字段名唯一,那么在书写连接条件的时候,可以省略表名,直接书写字段名,MySQL 会自动识别唯一字段名,但不建议这么做**。此外,咱们会发现,在上面的结果中有同名字段,这会给咱们理解数据的意义造成一定的困扰,这时就需要使用字段别名和表别名做区别啦! 56 | 57 | 执行如下 SQL 语句,进行测试: 58 | 59 | ``` 60 | -- 将表 student 与 class 进行内连接,起别名 61 | select s.*,c.id as c_id,c.grade as c_grade,room from student as s inner join class as c on s.grade = c.grade; 62 | ``` 63 | 64 | ![select-student-innerjoin-class-alias](https://github.com/guobinhit/mysql-tutorial/blob/master/images/join-query/select-student-innerjoin-class-alias.png) 65 | 66 | 最后,内连接可以没有连接条件,即可以没有`on`及之后的内容,这时内连接的结果全部保留,与交叉连接的结果完全相同。而且在内连接的时候可以使用`where`关键字代替`on`,但不建议这么做,因为`where`没有`on`的效率高。 67 | 68 | 执行如下 SQL 语句,进行测试: 69 | 70 | ``` 71 | -- 将表 student 与 class 进行内连接,不加连接条件 72 | select s.*,c.id as c_id,c.grade as c_grade,room from student as s inner join class as c; 73 | 74 | -- 将表 student 与 class 进行交叉连接 75 | select s.*,c.id as c_id,c.grade as c_grade,room from student as s cross join class as c; 76 | 77 | -- 使用 on 关键字进行内连接 78 | select s.*,c.id as c_id,c.grade as c_grade,room from student as s inner join class as c on s.grade = c.grade; 79 | 80 | -- 使用 where 关键字进行内连接 81 | select s.*,c.id as c_id,c.grade as c_grade,room from student as s inner join class as c where s.grade = c.grade; 82 | ``` 83 | 84 | ![innerjoin-crossjoin](https://github.com/guobinhit/mysql-tutorial/blob/master/images/join-query/innerjoin-crossjoin.png) 85 | ![on-where-join](https://github.com/guobinhit/mysql-tutorial/blob/master/images/join-query/on-where-join.png) 86 | 87 | ## 外连接 88 | 89 | **外连接**:`left\right join`,以某张表为主表,取出里面的所有记录,然后让主表中的每条记录都与另外一张表进行连接,不管能否匹配成功,其最终结果都会保留,匹配成功,则正确保留;匹配失败,则将另外一张表的字段都置为`NULL`. 90 | 91 | - **基本语法**:`左表 + left\right + join + 右表 + on + 左表.字段 = 右表.字段;` 92 | 93 | 其中,关键字`on`表示连接条件,两表中的条件字段有着相同的业务含义。在这里,以主表为依据,外连接分为两种,分别为: 94 | 95 | - `left join`:左外连接(左连接),以左表为主表; 96 | - `right join`:右外连接(右连接),以右表为主表。 97 | 98 | 执行如下 SQL 语句,进行测试: 99 | 100 | ``` 101 | -- 将表 student 与 class 进行左连接 102 | select s.*,c.id as c_id,c.grade as c_grade,room from student as s left join class as c on s.grade = c.grade; 103 | 104 | -- 将表 student 与 class 进行右连接 105 | select s.*,c.id as c_id,c.grade as c_grade,room from student as s right join class as c on s.grade = c.grade; 106 | ``` 107 | 108 | ![left-right-join](https://github.com/guobinhit/mysql-tutorial/blob/master/images/join-query/left-right-join.png) 109 | 110 | 实际上,无论以那张表为主表,其外连接的结果(记录数量)都不会少于主表的记录总数。此外,虽然左连接与右连接有主表差异,但显示的结果都是:**左表的数据在左边,右表的数据在右边**。 111 | 112 | 113 | ## 自然连接 114 | 115 | 116 | **自然连接**:`nature join`,自然连接其实就是自动匹配连接条件,系统以两表中同名字段作为匹配条件,如果两表有多个同名字段,那就都作为匹配条件。在这里,自然连接可以分为自然内连接和自然外连接。 117 | 118 | ### 自然内连接 119 | 120 | - **基本语法**:`左表 + nature + join + 右表;` 121 | 122 | 执行如下 SQL 语句,进行测试: 123 | 124 | ``` 125 | -- 将表 student 与 class 进行自然内连接 126 | select * from student natural join class; 127 | 128 | -- 将表 student 与 class 进行内连接,连接条件为 id 和 grade 129 | select * from student inner join class on student.id = class.id and student.grade = class.grade; 130 | ``` 131 | 132 | ![natural-join](https://github.com/guobinhit/mysql-tutorial/blob/master/images/join-query/natural-join.png) 133 | 134 | 观察上图,咱们会发现:**自然连接自动使用同名字段作为连接条件,而且在连接完成之后合并同名字段**。 135 | 136 | ### 自然外连接 137 | 138 | - **基本语法**:`左表 + nature + left/right + join + 右表;` 139 | 140 | 执行如下 SQL 语句,进行测试: 141 | 142 | ``` 143 | -- 将表 student 与 class 进行自然左外连接 144 | select * from student natural left join class; 145 | 146 | -- 将表 student 与 class 进行自然右外连接 147 | select * from student natural right join class; 148 | ``` 149 | 150 | ![natural-left-join](https://github.com/guobinhit/mysql-tutorial/blob/master/images/join-query/natural-left-join.png) 151 | 152 | 实际上,自然连接并不常用。而且,咱们可以用内连接和外连接来模拟自然连接,模拟的关键就在于使用同名字段作为连接条件及合并同名字段。 153 | 154 | - **基本语法**:`左表 + inner/left/right + join + 右表 + using(字段名);` 155 | 156 | 其中,`using`内部的字段名就是作为连接条件的字段,也是需要合并的同名字段。 157 | 158 | 执行如下 SQL 语句,进行测试: 159 | 160 | ``` 161 | -- 将表 student 与 class 进行自然左外连接 162 | select * from student natural left join class; 163 | 164 | -- 用左外连接模拟自然左外连接 165 | select * from student left join class using(id,grade); 166 | ``` 167 | 168 | ![leftjoin-like-naturaljoin](https://github.com/guobinhit/mysql-tutorial/blob/master/images/join-query/leftjoin-like-naturaljoin.png) 169 | 170 | ---------- 171 | 172 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 173 | 174 | 175 | ---------- 176 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 177 | -------------------------------------------------------------------------------- /articles/mysql_db.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(三)「 MySQL 数据库」 2 | 3 | MySQL 数据库 4 | ========= 5 | 6 | MySQL 数据库是一种`C\S`结构的软件,即分为:客户端和服务端。 7 | 8 | 若想访问服务器,则必须通过客户端;服务器应该一直运行,客户端则在需要使用的时候运行。 9 | 10 | 交互方式 11 | ---- 12 | 13 | 1. 客户端连接认证,即连接服务器,认证身份`mysql.exe -hPup` 14 | 15 | - `-h`,主机地址,本地为`localhost`,远程为`IP`地址 16 | - `-P`,端口号,用来找软件 17 | - `-u`,用户名 18 | - `-p`,密码 19 | 20 | 2. 发送 SQL 指令; 21 | 3. 服务器接受 SQL 指令,然后处理 SQL 指令并返回操作结果; 22 | 4. 客户端接受结果并显示结果; 23 | 5. 由于服务器并发限制,需要断开连接(三种指令,分别为:`exit`、`quit`和`\q`),释放资源。 24 | 25 | 服务器对象 26 | ----- 27 | 由于没办法完全了解服务器内部的结构,因此只能粗略的分析数据库服务器的内部结构。 28 | 29 | 一般来说,将 MySQL 数据库服务器的内部对象分为四层,分别为:数据管理系统(DBMS)--> 数据库(DB)--> 表(Table)--> 字段(Filed). 30 | 31 | 32 | 33 | 34 | 35 | ---------- 36 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 37 | -------------------------------------------------------------------------------- /articles/paradigm.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十五)「范式」 2 | 3 | ## 范式 4 | 5 | 范式:`Normal Farmat`,**是为了解决数据的存储和优化问题**。 6 | 7 | 在数据存储之后,凡是能够通过关系寻找出来的数据,坚决不再重复存储,范式的终极目标是减少数据冗余。 8 | 9 | 范式是一种分层结构的规范,共 6 层,分别为`1NF`、`2NF`、`3NF`、`4NF`、`5NF`和`6NF`,每一层都比上一层严格,若要满足下一层范式,其前提是先满足上一层范式。其中,`1NF`是最底层的范式,`6NF`为最高层的范式,也最严格。 10 | 11 | MySQL 数据库属于关系型数据库,其存储数据的时候有些浪费空间,但也致力于节省空间,这就与范式想要解决的问题不谋而合,因此在设计数据库的时候,大都会利用范式来指导设计。但是数据库不单是要解决存储空间的问题,还要保证效率的问题,而范式只为解决存储空间的问题,所以数据库的设计又不能完全按照范式的要求来实现,因此在一般情况下,只需要满足前三种范式即可。 12 | 13 | 此外,咱们需要知道:**范式在数据库的设计中是有指导意义的,但不是强制规范**。 14 | 15 | ## 1NF 16 | 17 | 第一范式:在设计表存储数据的时候,如果表中设计的字段存储的数据,在取出来使用之前还需要额外的处理(拆分),那么表的设计就不满足第一范式,**第一范式要求字段的数据具有原子性,不可再分**。 18 | 19 | 例如,咱们设计一个「学校假期时间表」,如下所示: 20 | 21 | **表 1:学校假期时间表** 22 | 23 | | ID(P) | 学校名称 | 起始日期,结束日期| 24 | | ------------- |:-------------| :-----| 25 | |1| 哈尔滨工业大学 |20170625,20170903| 26 | |2 |浙江大学 |20170630,20170901| 27 | 28 | 观察上表,咱们会发现`表1`的设计并没有什么问题,但是如果需求是查询各学校开始放假的日期呢?那显然上表的设计并不满足`1NF`,数据不具有原子性。对于此类问题,解决的方案就是将`表1`进行拆分: 29 | 30 | **表 2:拆分后的表 1** 31 | 32 | | ID(P) | 学校名称 | 起始日期|结束日期| 33 | | ------------- |:-------------| :-----|:-----| 34 | |1| 哈尔滨工业大学 |20170625|20170903| 35 | |2 |浙江大学 |20170630|20170901| 36 | 37 | 38 | ## 2NF 39 | 40 | 第二范式:在数据表的设计过程中,如果有复合主键(多字段主键),且表中有字段并不是由整个主键来确定,而是依赖复合主键中的某个字段(主键的部分),也就是说存在字段依赖主键的部分的问题(称之为部分依赖),**第二范式就是要解决表设计中不允许出现部分依赖**。 41 | 42 | 例如,咱们设计一个「教室授课表」,如下所示: 43 | 44 | **表 3:教室授课表** 45 | 46 | | 教师(P) | 性别 | 课程|授课地点(P)| 47 | | ------------- |:-------------| :-----|:-----| 48 | |许仙| 男 |《如何追到心爱的女孩》|杭州西湖| 49 | |白娘子 |女 |《论女人的恋爱修养》|雷峰塔| 50 | |白娘子 |女 |《如何打赢与和尚之间的持久战》|金山寺| 51 | 52 | 观察上表,咱们会发现:教师不能作为独立的主键,需要与授课地点相结合才能作为主键(复合主键,每个教师的某个课程只能在固定的地点上),其中性别依赖于具体的教师,而课程依赖于授课地点,这就出现了表的字段依赖于部分主键的问题,从而导致不满足第二范式。 53 | 54 | - **解决方案 1**:将教师和性别,课程和授课地点,分成两张单独的表; 55 | - **解决方案 2**:取消复合主键,使用逻辑主键。 56 | 57 | 在此,咱们采用 **方案 2** 的解决方法,即取消复合主键,使用逻辑主键。 58 | 59 | |ID(P)| 教师 | 性别 | 课程|授课地点| 60 | |:--------| :------------- |:-------------| :-----|:-----| 61 | |1|许仙| 男 |《如何追到心爱的女孩》|杭州西湖| 62 | |2|白娘子 |女 |《论女人的恋爱修养》|雷峰塔| 63 | |3|白娘子 |女 |《如何打赢与和尚之间的持久战》|金山寺| 64 | 65 | 66 | ## 3NF 67 | 68 | 第三范式:需要满足第一范式和第二范式,理论上讲,每张表中的所有字段都应该直接依赖主键(逻辑主键,代表是业务主键),如果表设计中存在一个字段,并不直接依赖主键,而是通过某个非主键字段依赖,最终实现主键依赖(把这种不是直接依赖主键,而是依赖非主键字段的依赖关系,称之为传递依赖),**第三范式就是要解决表设计中出现传递依赖的问题**。 69 | 70 | 以上述的添加逻辑主键后的 **表3** 为例: 71 | 72 | |ID(P)| 教师 | 性别 | 课程|授课地点| 73 | |:--------| :------------- |:-------------| :-----|:-----| 74 | |1|许仙| 男 |《如何追到心爱的女孩》|杭州西湖| 75 | |2|白娘子 |女 |《论女人的恋爱修养》|雷峰塔| 76 | |3|白娘子 |女 |《如何打赢与和尚之间的持久战》|金山寺| 77 | 78 | 在以上表的设计中,性别依赖教师,教师依赖主键;课程依赖授课地点,授课地点依赖主键,因此性别和课程都存在传递依赖的问题。 79 | 80 | - **解决方案**:将存在传递依赖的字段,以及依赖的字段本身单独取出来,形成一个单独的表,然后在需要使用对应的信息的时候,把对应的实体表的主键添加进来。 81 | 82 | **表 4:教师表** 83 | 84 | |TEACHER_ID(P)| 教师 | 性别 | 85 | |:--------| :------------- |:-------------| 86 | |1|许仙| 男 | 87 | |2|白娘子 |女 | 88 | |3|白娘子 |女 | 89 | 90 | **表 5:授课地点表** 91 | 92 | |ADDRESS_ID(P)| 课程|授课地点| 93 | |:--------| :-----|:-----| 94 | |1|《如何追到心爱的女孩》|杭州西湖| 95 | |2|《论女人的恋爱修养》|雷峰塔| 96 | |3|《如何打赢与和尚之间的持久战》|金山寺| 97 | 98 | **表 6:进行处理后的表** 99 | 100 | |ID(P)| TEACHER_ID|ADDRESS_ID| 101 | |:--------| :-----|:-----| 102 | |1|1|1| 103 | |2|2|2| 104 | |3|3|3| 105 | 106 | 在观察上述 **表 4** 和 **表 5**,咱们会发现`TEACHER_ID`等价于`教师`且`ADDRESS_ID`等价于`授课地点`,因此其逻辑主键并没有什么实际的限制意义,咱们只需要看其具体代表的业务主键即可。咱们之所以使用逻辑主键,是因为:**逻辑主键可以实现自动增长,并且数字传递比较方便,而且有利于节省空间**。 107 | 108 | ## 逆规范化 109 | 110 | 在某些特定的环境中(例如淘宝数据库),在设计表的时候,如果一张表中有几个字段是需要从另外的表中去获取数据,理论上讲,的确可以获得想要的数据,但是相对来说,其效率低会一点。此时为了提高查询效率,咱们会刻意的在某些表中,不去保存另外一张表的主键(逻辑主键),而是直接保存想要存储的数据信息,这样的话,在查询数据的时候,这张表就可以直接提供咱们想要的数据,而不需要多表查询,但是这样做会导致数据冗余。 111 | 112 | 实际上,**逆规范化是磁盘利用率和效率之间的对抗**。 113 | 114 | 115 | 116 | ---------- 117 | 118 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 119 | 120 | 121 | -------------------------------------------------------------------------------- /articles/primarykey.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十)「列属性 之 主键」 2 | 3 | ## 主键 4 | 5 | 主键:`primary key`,**表中主要的键,每张表只能有一个字段(复合主键,可以多个字段)使用此属性,用来唯一的约束该字段里面的数据,不能重复**。 6 | 7 | ### 增加主键 8 | 9 | 在 SQL 操作中,有 3 种方法可以给表增加主键,分别为: 10 | 11 | **第 1 种**:在创建表的时候,直接在字段之后,添加`primary key`关键字 12 | 13 | ``` 14 | -- 增加主键 15 | create table my_pri1( 16 | name varchar(20) not null comment '姓名', 17 | number char(10) primary key comment '学号' 18 | )charset utf8; 19 | ``` 20 | ![create-table-mypri1](https://github.com/guobinhit/mysql-tutorial/blob/master/images/primarykey/create-table-mypri1.png) 21 | 22 | 如上图所示,此方法的优点是清晰明了,缺点则是只能使用一个字段作为主键。 23 | 24 | **第 2 种**:在创建表的时候,在所有的字段之后,使用`primary key(主键字段列表)`来创建主键(如果有多个字段作为主键,则称之为复合主键) 25 | 26 | ``` 27 | -- 复合主键 28 | create table my_pri2( 29 | number char(10) not null comment '学号', 30 | course char(10) not null comment '课程编号', 31 | score tinyint unsigned default 60, 32 | -- 增加主键限制,学号和课程编号应该是对应的,具有唯一性 33 | primary key(number,course) 34 | )charset utf8; 35 | ``` 36 | 37 | ![create-table-mypri2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/primarykey/create-table-mypri1.png) 38 | 39 | **第 3 种**:当表创建完之后,额外追加主键,可以直接追加主键,也可以通过修改表字段的属性追加主键 40 | 41 | ``` 42 | -- 追加主键 43 | create table my_pri3( 44 | course char(10) not null comment '课程编号', 45 | name varchar(10) not null comment '课程名称' 46 | )charset utf8; 47 | ``` 48 | ![create-table-mypri3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/primarykey/create-table-mypri1.png) 49 | 50 | 在这里,追加主键有两种方式,分别为: 51 | 52 | - `alter table my_pri3 modify course char(10) primary key comment '课程编号'; -- 不建议使用` 53 | 54 | - `alter table my_pri3 add primary key(course); -- 推荐使用` 55 | 56 | ![alter-mypri3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/primarykey/alter-mypri3.png) 57 | 58 | 如上图所示,咱们追加主键成功。不过,想要用此方法,有一个前提,那就是:**表中对应字段的数据是不重复的,即保证唯一性**。 59 | 60 | ### 主键约束 61 | 62 | 主键约束,即**主键对应的字符中的数据不允许重复,如果重复,则数据操作(主要是增和改)失败**。 63 | 64 | ``` 65 | -- 主键约束(冲突)测试 66 | insert into my_pri3 values('MATH00123','泛函分析'); 67 | insert into my_pri3 values('MATH00123','非线性分析'); 68 | ``` 69 | 70 | ![insert-mypri3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/primarykey/insert-mypri3.png) 71 | 72 | ### 更新主键 & 删除主键 73 | 74 | 对于主键,没有办法直接更新,主键必须先删除,然后才能更新。 75 | 76 | - 基本语法:`alter table + 表名 + drop primary key;` 77 | 78 | 执行如下 SQL 语句,进行测试: 79 | ``` 80 | -- 删除主键 81 | alter table my_pri3 drop primary key; 82 | ``` 83 | ![desc-mypri3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/primarykey/desc-mypri3.png) 84 | 85 | 如上图所示,咱们已经成功删除表`my_pri3`的主键啦!想要增加主键,只需要通过前面讲的 3 种方法即可。 86 | 87 | ### 主键分类 88 | 89 | 根据主键的字段类型,咱们可以将主键分为两类,分别为: 90 | 91 | - 业务主键,即使用真实的业务数据作为主键,例如学号、课程编号等等,很少使用; 92 | - 逻辑主键,即使用逻辑性的字段作为主键,字段没有业务含义,值有没有都没有关系,经常使用。 93 | 94 | 至此,咱们已经将主键的相关内容讲完啦! 95 | 96 | 97 | ---------- 98 | 99 | **温馨提示**:符号`+`表示连接的意思。 100 | 101 | ---------- 102 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 103 | -------------------------------------------------------------------------------- /articles/procedure.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(三十三)「存储过程」 2 | 3 | ## 存储过程 4 | 5 | 存储过程简称过程,`procedure`,是一种用来处理数据(增删改)的方式。简单点,我们也可以将其理解为没有返回值的函数。 6 | 7 | ### 创建过程 8 | 9 | ``` 10 | -- 基本语法 11 | create procedure 过程名([参数列表]) 12 | begin 13 | -- 过程体 14 | end 15 | ``` 16 | 如果我们定义的过程的过程体内仅含有一条语句,则可以省略`begin`和`end`。执行如下语句,进行测试: 17 | 18 | ``` 19 | -- 创建过程 20 | create procedure pro() 21 | select * from student; 22 | ``` 23 | 24 | ![create-procedure](https://github.com/guobinhit/mysql-tutorial/blob/master/images/procedure/create-procedure.png) 25 | 26 | 如上图所示,我们创建了一个名为`pro()`的过程,其目的就是为了查询`student`表中的数据。但实际上,过程多用于处理数据,查询并不多用。 27 | 28 | ### 查看过程 29 | 30 | 查看过程,基本语法为: 31 | 32 | - `show procedure status + [like 'pattern'];` 33 | 34 | ![show-procedure](https://github.com/guobinhit/mysql-tutorial/blob/master/images/procedure/show-procedure.png) 35 | 36 | 查看过程的创建语句,基本语法为: 37 | 38 | - `show create procedure + 过程名;` 39 | 40 | ![show-create-procedure](https://github.com/guobinhit/mysql-tutorial/blob/master/images/procedure/show-create-procedure.png) 41 | 42 | ### 调用过程 43 | 44 | 由于函数有返回值,因此我们可以用`select`来调用函数。但是存储过程没有返回值,怎么办?实际上,对于存储过程,有一个专门的调用关键字`call`,调用过程的基本语法为: 45 | 46 | - `call + 过程名;` 47 | 48 | ![call-pro](https://github.com/guobinhit/mysql-tutorial/blob/master/images/procedure/call-pro.png) 49 | 50 | ### 修改过程 & 删除过程 51 | 52 | 过程只能先删除后新增,不能修改。删除过程的基本语法为: 53 | 54 | - `drop procedure + 过程名;` 55 | 56 | 执行如下语句,进行测试: 57 | 58 | ``` 59 | -- 删除过程 60 | drop procedure pro; 61 | -- 查看过程 62 | show procedure status like 'pro'\G; 63 | ``` 64 | 65 | ![drop-procedure](https://github.com/guobinhit/mysql-tutorial/blob/master/images/procedure/drop-procedure.png) 66 | 67 | ### 过程参数 68 | 69 | 函数的参数需要指定数据类型,过程比函数更加严格。过程有三种自己的参数类型,分别为: 70 | 71 | - `in`,数据只是从过程外部传入给过程内部使用,可以是数值也可以是变量; 72 | - `out`,此参数只能传递变量,且变量指向的数据需要先清空然后才能进入过程内部,该引用供过程内部使用,过程结束后可以将变量的值传递给过程外部使用; 73 | - `inout`,此参数只能传递变量,该变量的值可以给过程内部使用,过程结束后可以变量的值传递给过程外部使用。 74 | 75 | 因此,过程定义的具体形式应该为: 76 | 77 | - `procedure 过程名(in 参数名字 参数类型, out 参数名字 参数类型, inout 参数名字 参数类型)` 78 | 79 | 下面,我们定义一个简单的过程,并调用过程。代码如下: 80 | 81 | ``` 82 | delimiter $$ 83 | create procedure pro2(in var1 int, out var2 int, inout var3 int) 84 | begin 85 | -- 查看该过程传入的三个变量 86 | select var1, var2, var3; 87 | end 88 | $$ 89 | delimiter ; 90 | 91 | -- 调用过程 92 | call pro2(1,2,3); 93 | ``` 94 | 95 | ![create-pro2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/procedure/create-pro2.png) 96 | 97 | 如上图所示,过程`pro2`创建成功。但是,在调用过程的时候出现错误,造成该错误的原因为:过程的`out`和`inout`两个参数只能接受变量,而我们传递了具体的数值,报错也就在情理之中啦!接下来,执行如下语句,进行测试: 98 | 99 | ``` 100 | -- 设置全局变量 101 | set @var1 = 1; 102 | set @var2 = 2; 103 | set @var3 = 3; 104 | 105 | -- 调用过程 106 | call pro2(@var1, @var2, @var3); 107 | -- 查看变量 108 | select @var1, @var2, @var3; 109 | ``` 110 | 111 | ![set-aite-var](https://github.com/guobinhit/mysql-tutorial/blob/master/images/procedure/set-aite-var.png) 112 | 113 | 如上图所示,在我们将变量传递给过程的时候,过程正常执行。此外,通过`select`语句我们可以看到传递给`out`类型参数的`@var2`的值在经过过程处理之后,被置为`null`值啦,这也是符合`out`类型参数的先清空后使用原则的。而且,由于`out`和`inout`只能接受变量作为参数,因此在过程内部对`out`和`inout`传入的变量的修改会影响到过程外部。在这里,值得我们注意是:存储过程对变量的操作是滞后的,即**只有在过程结束的时候,才会将过程内部修改的值赋值给外部传入的对应的全局变量**。执行如下语句,进行测试: 114 | 115 | ``` 116 | delimiter $$ 117 | create procedure pro3(in var1 int, out var2 int, inout var3 int) 118 | begin 119 | -- 查看该过程传入的三个变量 120 | select var1, var2, var3; 121 | -- 修改局部变量 122 | set var1 = 10; 123 | set var2 = 20; 124 | set var3 = 30; 125 | -- 查看局部变量 126 | select var1, var2, var3; 127 | -- 查看全局变量 128 | select @var1, @var2, @var3; 129 | -- 修改全局变量 130 | set @var1 = 'a'; 131 | set @var2 = 'b'; 132 | set @var3 = 'c'; 133 | -- 查看全局变量 134 | select @var1, @var2, @var3; 135 | end 136 | $$ 137 | delimiter ; 138 | ``` 139 | 140 | ![create-pro3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/procedure/create-pro3.png) 141 | 142 | ``` 143 | -- 调用过程 144 | call pro3(@var1, @var2, @var3); 145 | -- 在过程结束后,查看全局变量 146 | select @var1, @var2, @var3; 147 | ``` 148 | 149 | ![call-pro3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/procedure/call-pro3.png) 150 | 151 | 如上图所示,存储过程执行成功,且验证了我们结论,即:**在存储过程没有结束的时候,对传入变量的修改并不会影响到对应的全局变量;只有在存储过程结束后,才会将对应的变量值赋值给`out`和`inout`类型的变量,而`in`类型的变量不受影响**。 152 | 153 | ---------- 154 | 155 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 156 | 157 | 158 | ---------- 159 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 160 | 161 | -------------------------------------------------------------------------------- /articles/record-length.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(八)「记录长度」 2 | 3 | ## 记录长度 4 | 5 | MySQL 中规定:**任何一条记录最长不超过 65535 个字节,这意味着`varchar`永远达不到理论最大值**。 6 | 7 | 那么,`varchar`实际存储长度能达到多大呢?这由编码字符集决定。 8 | 9 | 下面,以`varchar`在`UTF-8`和`GBK`的情况为例,执行如下 SQL 语句,进行演示: 10 | 11 | ``` 12 | -- 求出 varchar 在 utf8 和 gbk 字符集下的实际最大值 13 | create table my_utf8( 14 | name varchar(65535) 15 | )charset utf8; 16 | 17 | create table my_gbk( 18 | name varchar(65535) 19 | )charset gbk; 20 | ``` 21 | 22 | ![create-table-myutf8](https://github.com/guobinhit/mysql-tutorial/blob/master/images/record-length/create-table-myutf8.png) 23 | 24 | 观察上面的结果,发现咱们定义的字段`name`的长度超过限制啦,并且提示了其在`utf8`和`gbk`字符集下各自的最大值。那么,咱们修改 SQL 语句如下,并再次执行: 25 | 26 | ``` 27 | -- 求出 varchar 在 utf8 和 gbk 字符集下的实际最大值 28 | create table my_utf8( 29 | name varchar(21845) 30 | )charset utf8; 31 | 32 | create table my_gbk( 33 | name varchar(32767) 34 | )charset gbk; 35 | ``` 36 | 37 | ![myutf8-mygbk](https://github.com/guobinhit/mysql-tutorial/blob/master/images/record-length/myutf8-mygbk.png) 38 | 39 | 观察上面的执行结果,好吧,仍然在报错,为什么呢?观察如下 SQL 语句,并执行: 40 | 41 | ``` 42 | -- 求出 varchar 在 utf8 和 gbk 字符集下的实际最大值 43 | create table my_utf8( 44 | name varchar(21844) -- 21844 * 3 + 2 = 65534 45 | )charset utf8; 46 | 47 | create table my_gbk( 48 | name varchar(32766) -- 32766 * 2 + 2 = 65534 49 | )charset gbk; 50 | ``` 51 | 52 | ![utf8-gbk](https://github.com/guobinhit/mysql-tutorial/blob/master/images/record-length/utf8-gbk.png) 53 | 54 | 如上图所示,咱们已经创建成功啦!至于什么定义字段`name`的长度为`21844`和`32766`是由于: 55 | 56 | - `21845 * 3 + 2 = 65537 > 65535` 57 | - `32767 * 2 + 2 = 65536 > 65535` 58 | 59 | 因此,在提示的最大值的基础上各自减`1`. 至于,为什么还要加`2`,则是因为`varchar`为变长字符串,在其定义的时候,也就是说在分配存储空间的时候,都会自动多分配`1`到`2`个字节空间,因为咱们想要算最大的存储范围,所以加`2`. 60 | 61 | 在这里,细心的同学会发现一个问题,那就是:在咱们创建表`my_utf8`和`my_gbk`的时候,咱们仅用了`65534`个字节,还剩余一个字节。现在,如果咱们想要将`65535`个字节都用了,怎么办呢?好说,增加一个`tinyint`类型的字段即可: 62 | 63 | ``` 64 | -- 求出 varchar 在 utf8 和 gbk 字符集下的实际最大值 65 | create table my_utf81( 66 | stuno tinyint, -- 1 67 | name varchar(21844) -- 21844 * 3 + 2 = 65534 68 | )charset utf8; 69 | 70 | create table my_gbk1( 71 | stuno tinyint, -- 1 72 | name varchar(32766) -- 32766 * 2 + 2 = 65534 73 | )charset gbk; 74 | ``` 75 | 76 | ![myutf81-mygbk1](https://github.com/guobinhit/mysql-tutorial/blob/master/images/record-length/myutf81-mygbk1.png) 77 | 78 | 观察上面的结果,呃,竟然又出错啦!为什么啊?`65534 + 1 = 65535`,并没有超出范围啊!其实吧,之所以会出现这样的问题,是因为:**在 MySQL 的记录中,如果有任何一个字段允许为空,那么系统就会自动从整个记录中保留一个字节来存储`null`,若想释放`null`所占的字节,则必须保证所有字段都不允许为空。** 79 | 80 | ``` 81 | -- 求出 varchar 在 utf8 和 gbk 字符集下的实际最大值 82 | create table my_utf82( 83 | stuno tinyint not null, -- 1 84 | name varchar(21844) not null -- 21844 * 3 + 2 = 65534 85 | )charset utf8; 86 | 87 | create table my_gbk2( 88 | stuno tinyint not null, -- 1 89 | name varchar(32766) not null -- 32766 * 2 + 2 = 65534 90 | )charset gbk; 91 | ``` 92 | 93 | ![myutf82-mygbk2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/record-length/myutf82-mygbk2.png) 94 | 95 | 如上图所示,咱们已经成功创建了表`my_utf82`和`my_gbk2`. 96 | 97 | 此外,在 MySQL 中,`text`文本字符串不占用记录长度,额外存储,但是`text`文本字符串也是属于记录的一部分,无论是在`utf8`还是在`gbk`字符集之中,其都占用记录中的`10`个字节长度,用来保存数据的地址以及长度。 98 | 99 | 100 | 101 | 102 | 103 | 104 | ---------- 105 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 106 | -------------------------------------------------------------------------------- /articles/relation-db.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二)「关系型数据库」 2 | 3 | 关系型数据库 4 | ====== 5 | 6 | 1 定义 7 | ---- 8 | 关系型数据库,**是一种建立在关系模型(数学模型)上的数据库。** 9 | 10 | 至于关系模型,则是一种所谓建立在关系上的模型,其包含三个方面,分别为: 11 | 12 | - 数据结构:数据存储的形式,二维表(行和列); 13 | - 操作指令集合:所有的 SQL 语句; 14 | - 完整性约束:表内数据约束(字段与字段)和表与表之间的约束(外键)。 15 | 16 | 2 设计 17 | ---- 18 | 19 | - 数据库:从需要存储的数据需求中分析,如果是一类数据(实体),则应该设计成二维表; 20 | - 二维表:由表头(字段名,用来规定数据的名称)和数据(实际存储的内容)部分组成。 21 | 22 | 在此处,需要特别注意:**如果表中对应的某个字段值为空,但是系统依然会为其分配存储空间**,这也就是关系型数据库比较浪费空间的原因啦! 23 | 24 | 3 关键字说明 25 | ------- 26 | 27 | - DB:Database,数据库; 28 | - DBMS:Database Management System,数据库管理系统; 29 | - DBS:Database System = DBMS + DB,数据库系统; 30 | - DBA:Database Administrator,数据库管理员。 31 | - 行\记录:`row\record`,本质都是指表中的一行(一条记录),行是从结构角度出发,记录则是从数据角度出发。 32 | - 列\字段:`column\field`,本质都是指表中的一列(一个字段),列是从结构角度出发,字段则是从数据角度出发。 33 | 34 | 4 SQL 35 | ----- 36 | 37 | SQL:Structured Query Language,结构化查询语言(数据以查询为主,99% 都是在进行查询操作)。 38 | 39 | SQL 主要分为三种: 40 | 41 | - DDL:Data Definition Language,数据定义语言,用来维护存储数据的结构(数据库、表),代表指令为`create`、`drop`和`alter`等。 42 | - DML:Data Manipulation Language,数据操作语言,用来对数据进行操作(表中的内容)代表指令为`insert`、`delete`和`update`等,不过在 DML 内部又单独进行了一个分类,即 DQL(Data Query Language),数据查询语言,代表指令为`select`. 43 | - DCL:Data Control Language,数据控制语言,主要是负责(用户)权限管理,代表指令为`grant`和`revoke`等。 44 | 45 | SQL 是关系型数据库的操作指令,是一种约束,但不强制,类似于 W3C,因此这意味着:不同的数据库产品(如 Oracle 和 MySQL)内部可能会有一些细微的区别。 46 | 47 | ---------- 48 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 49 | -------------------------------------------------------------------------------- /articles/relation.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十四)「关系」 2 | 3 | ## 关系 4 | 5 | 在数据库中,将实体与实体的关系反应到表的设计上来,可以细分为 3 种,分别为:一对一`(1:1)`,一对多`(1:N)`(或多对一`(N:1)`)和多对多`(N:N)`。 6 | 7 | 在此,所有的关系都是指表与表之间的关系。 8 | 9 | ### 一对一 10 | 11 | 一对一,即**一张表的一条记录只能与另外一张表的一条记录相对应,反之亦然**。 12 | 13 | 例如,咱们设计一张「个人信息表」,其字段包含:姓名、性别、年龄、身高、体重、籍贯和居住地等。 14 | 15 | ![0](http://img.blog.csdn.net/20170601085452637) 16 | 17 | 如上表所示,基本满足咱们的要求,其中姓名、性别和年龄属于常用数据,但是身高、体重、籍贯和居住地为不常用数据。如果每次查询都要查询所有数据的话,那么不常用数据就会影响效率,而且又不常用。因此,咱们可以将常用的数据和不常用的数据分离存储,即分为两张表,例如: 18 | 19 | **表 1:常用数据** 20 | 21 | ![1](http://img.blog.csdn.net/20170601085511060) 22 | 23 | **表 2:不常用数据** 24 | 25 | ![2](http://img.blog.csdn.net/20170601085527435) 26 | 27 | 如上面`表1`和`表2`所示,通过字段`ID`,`表1`中的一条记录只能匹配`表2`中的一条记录,反之亦然,这就是`一对一`的关系。 28 | 29 | ### 一对多/多对一 30 | 31 | 一对多,即**一张表中的记录可以对应另外一张表中的多条记录,但是反过来,另外一张表中的一条记录只能对应第一张表中的一条记录**。 32 | 33 | 例如,咱们设计「国家城市表」,其包含两个实体,即国家和城市。 34 | 35 | **表 3:国家表** 36 | 37 | ![3](http://img.blog.csdn.net/20170601085541820) 38 | 39 | **表 4:城市表** 40 | 41 | ![4](http://img.blog.csdn.net/20170601085555233) 42 | 43 | 如上面`表3`和`表4`所示,通过字段`国家`,`表3`中的一条记录可以匹配`表4`中的多条记录,但反过来,`表4`中的一条记录只能匹配`表3`中的一条记录,这就是典型的`一对多`的关系。 44 | 45 | ### 多对多 46 | 47 | 多对多,即**一张表中的记录可以对应另外一张表中的多条记录,反过来,另外一张表中的一条记录也可以对应第一张表中的多条记录**。 48 | 49 | 例如,咱们设计「教师学生表」,其包含两个实体,即教师和学生。 50 | 51 | **表 5:教师表** 52 | 53 | ![5](http://img.blog.csdn.net/20170601085610524) 54 | 55 | **表 6:学生表** 56 | 57 | ![6](http://img.blog.csdn.net/20170601085624014) 58 | 59 | 观察上面的`表5`和`表6`,咱们会发现:`表5`和`表6`的设计满足了实体的属性,但没有维护实体之间的关系,即一个老师教过多个学生,一个学生也被多个老师教过。但是无论咱们在`表5`中还是在`表6`中增加字段,都会出现一个问题,那就是:该字段要保存多个数据,并且还是与其他表有关系的字段,不符合设计规范。因此,咱们可以再设计一张「中间表」,专门用来维护`表5`和`表6`的关系。 60 | 61 | **表 7:中间表** 62 | 63 | ![7](http://img.blog.csdn.net/20170601085636952) 64 | 65 | 观察上面的`表5`、`表6`和`表7`,咱们会发现增加`表7`之后,咱们维护`表5`和`表6`的关系更加方便啦!无论是想从`表5`通过`表7`查到`表6`,还是想从`表6`通过`表7`查到`表5`,都非常容易啦!这就是典型的`多对多`的关系。 66 | 67 | 68 | ---------- 69 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 70 | -------------------------------------------------------------------------------- /articles/resovle-method.md: -------------------------------------------------------------------------------- 1 | # 详述 MySQL 数据库输入密码后闪退的问题及解决方案 2 | 3 | 1 案例说明 4 | ------ 5 | 6 |   最近一直在用 MySQL 数据库演示基础功能,但是这两天忽然出现了一个问题,那就是:**在启动 MySQL 服务端并输入密码后,出现闪退现象。** 7 | 8 |   之后,在网上搜了搜,发现出现这种问题很常见,大多数原因可能是在咱们使用安全软件的时候,无意中关闭了 MySQL 服务。此外,如果 MySQL 服务已经启动了,但还是出现了闪退的现象,那就可能是 MySQL 的配置出现了问题。 9 | 10 | 11 | 12 | 2 解决方案 13 | ------ 14 | 15 |   在出现上述问题的时候,咱们首先要查看 MySQL 服务是否启动,如果 MySQL 服务没有启动,那么大多数情况,当咱们手动启动 MySQL 服务之后,上述问题就可以得到解决;如果 MySQL 服务已经启动,但还是出现了闪退现象,这就需要咱们修改相关配置啦! 16 | 17 | 接下来,按照如下步骤(依次点击),进入`服务`管理页面: 18 | 19 | 1. 我的电脑; 20 | 2. 管理; 21 | 3. 服务和应用程序; 22 | 4. 服务。 23 | 24 | ![computer-management](https://github.com/guobinhit/mysql-tutorial/blob/master/images/resovle-method/computer-management.png) 25 | 26 | 如上图所示,在这里,咱们就可以查看 MySQL 的服务的状态啦! 27 | 28 | 29 | **第 1 种情况:MySQL 服务没有启动** 30 | 31 | 咳咳,这个容易,点击右键或者点击下图红色箭头所示的按钮启动 MySQL 服务即可。 32 | 33 | ![start-server](https://github.com/guobinhit/mysql-tutorial/blob/master/images/resovle-method/start-server.png) 34 | 35 | 点击`启动`后,就让咱们重新启动 MySQL 服务端,输入密码,进行测试: 36 | 37 | ![test-mysql-client](https://github.com/guobinhit/mysql-tutorial/blob/master/images/resovle-method/test-mysql-client.png) 38 | 39 | 如上图所示,显然咱们的问题已经得到了解决。 40 | 41 | **第 2 种情况:MySQL 服务已经启动** 42 | 43 | 在 MySQL 服务启动的情况下,出现闪退的问题,这就可能是 MySQL 的配置出现了问题。更进一步,可能是`C:\ProgramFiles\MySQL\MySQL Server X.X`的`my.ini`文件(安装路径下)有问题。对于此问题: 44 | 45 | - **方法 1**:首先进入`cmd`切入`MySQL`的安装目录,再切入`bin`目录,输入`mysqld-nt--skip-grant-tables`命令。然后,此`cmd`窗口先不要关闭, 打开另一个窗口登陆`MySQL`或直接点开`MySQL CommandLine Client`输入正确的密码,即可。 46 | - **方法 2**:找出运行`win+R`,在这个`DOS`窗体中,`cd`到`MySQL Server X.X`的`bin`目录下,然后输入`mysql -u root -p`命令,再输入密码,即可。 47 | - **方法 3**:如果登录又提示`mysql: unknownvariable 'character-set-server=gbk'`,解决方法:修改`MySQL`安装目录下的`my.ini`文件,将里面的`default-character-set=gbk`注释或删除掉,在服务里重启`MySQL`服务,即可。 48 | 49 | 到这里,相信如果再遇到 MySQL 数据库输入密码后闪退问题时,咱们都可以轻而易举的解决啦! 50 | 51 | ---------- 52 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 53 | -------------------------------------------------------------------------------- /articles/secure.md: -------------------------------------------------------------------------------- 1 | # 详述 MySQL 导出数据遇到 secure-file-priv 的问题 2 | 3 | > **ERROR 1290 (HY000)**: The MySQL server is running with the --secure-file-priv option so it cannot execute this statement. 4 | 5 | 对于上述错误,相信对于第一次执行 MySQL 数据导出操作的同学大都会遇见。至于为什么会遇到这个错误,原因很简单,那就是:我们不知道 MySQL 默认的导出目录是哪里,甚至都不知道 MySQL 对于数据的导出目录都有所限制。这其实很正常,因为我们不可能知道所有事,只要我们在遇到问题之后,能够找到正确的解决方法并记住就足够啦!学习嘛,就是一个不断积累的过程。 6 | 7 | 接下来,我们就一起来看看如何解决这个问题:在我们安装完 MySQL 之后,会自动生成一个名为`my.ini`的配置文件,该文件记录了 MySQL 的所有默认配置,如端口号、默认字符集、默认存储引擎等等。而这个配置文件,则位于隐藏文件夹`ProgramData`中,至于如何找到该隐藏文件夹,具体可以参考[详述查看 MySQL 数据文件存储位置的方法](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/datafile.md)。 8 | 9 | 此外,我们也可以通过命令查看`secure-file-priv`的当前值: 10 | 11 | - `show variables like '%secure%';` 12 | 13 | 执行上述命令,进行测试: 14 | 15 | ![show-variables](https://github.com/guobinhit/mysql-tutorial/blob/master/images/secure/show-variables.png) 16 | 17 | 如上图所示,我设置的`secure-file-priv`值为`D:/CoderLife/testMySQL`,而 MySQL 默认的值为: 18 | 19 | - `secure-file-priv="C:/ProgramData/MySQL/MySQL Server 5.7/Uploads"` 20 | 21 | 我们可以通过打开`my.ini`配置文件进行查看及修改: 22 | 23 | ![my-ini](https://github.com/guobinhit/mysql-tutorial/blob/master/images/secure/my-ini.png) 24 | 25 | 如上图所示,我注释了 MySQL 的默认值,并修改成自己指定的路径。实际上,在我们修改此配置文件的内容之后,例如修改了`secure-file-priv`的默认值,要想使其生效,我们必须关闭 MySQL 然后重新启动。在这里,需要我们注意的是:**关闭 MySQL 并不是指简单的用`exit`命令退出 MySQL 或者关闭 MySQL 窗口,而是关闭 MySQL 服务,然后重新启动服务**。至于如何开启和关闭 MySQL 服务,具体可以参考[详述 MySQL 数据库输入密码后闪退的问题及解决方案](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/resovle-method.md)。 26 | 27 | 28 | ---------- 29 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /articles/select.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十九)「数据的高级操作 之 查询」 2 | 3 | ## 数据的高级操作 - 查询数据 4 | 5 | - **基本语法**: `select + 字段列表/* + from + 表名 + [where 条件];` 6 | - **完整语法**: `select + [select 选项] + 字段列表[字段别名]/* + from + 数据源 + [where 条件] + [1] + [2] + [3];` 7 | + `[1] = [group by 子句]` 8 | + `[2] = [order by 子句]` 9 | + `[3] = [limit 子句]` 10 | 11 | ### SELECT 选项 12 | 13 | `select`选项,即`select`对查出来的结果的处理方式。 14 | 15 | - `all`:默认,保留所有的查询结果; 16 | - `distinct`:去重,将查出来的结果中所有字段都相同的记录去除。 17 | 18 | 执行如下 SQL 语句,进行测试: 19 | 20 | ``` 21 | -- 查询表 my_copy 中的数据 22 | select * from my_copy; 23 | select all * from my_copy; 24 | select distinct * from my_copy; 25 | ``` 26 | 27 | ![select-mycopy](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-mycopy.png) 28 | 29 | 30 | ### 字段别名 31 | 32 | 字段别名,即当数据进行查询的时候,有时候字段的名字并不一定满足需求(特别地,在多表查询的时候,很可能会有同名字段),这时就需要对字段进行重命名、取别名。 33 | 34 | - **基本语法**:`字段名 + [as] + 别名;` 35 | 36 | 执行如下 SQL 语句,进行测试: 37 | 38 | ``` 39 | -- 使用别名 40 | select id, 41 | name as 姓名, 42 | age as 年龄, 43 | grade as 年级 44 | from student; 45 | ``` 46 | 47 | ![use-alias](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/use-alias.png) 48 | 49 | ### 数据源 50 | 51 | 数据源,即数据的来源,关系型数据库的数据源都是数据表,本质上只要保证数据类似二维表,最终就可以作为数据源。 52 | 53 | 数据源分为 3 种,分别为:单表数据源,多表数据源和查询语句。 54 | 55 | **第 1 种**:单表数据源 56 | 57 | - **基本语法**:`select * from + 表名;` 58 | 59 | ![select-student](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-student.png) 60 | 61 | **第 2 种**:多表数据源 62 | 63 | - **基本语法**:`select * from + 表名1,表名2...;` 64 | 65 | ![select-student-myclass](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-student-myclass.png) 66 | 67 | 如上图所示,使用多表数据源时默认从一张表中取出一条记录去另外一张表中匹配所有记录,而且全部保留,比较浪费资源,应该尽量避免。 68 | 69 | 70 | **第 3 种**:查询语句(子查询) 71 | 72 | - **基本语法**:`select * from + (select * from + 表名) + [as] + 别名;` 73 | 74 | ![select-union-select](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-union-select.png) 75 | 76 | 如上图所示,数据的来源是一条查询语句,而查询语句的结果是一张二维表。 77 | 78 | 79 | ### `where`子句 80 | 81 | `where`字句:**用来判断数据和筛选数据,返回的结果为`0`或者`1`,其中`0`代表`false`,`1`代表`true`**,`where`是唯一一个直接从磁盘获取数据的时候就开始判断的条件,从磁盘中读取一条数据,就开始进行`where`判断,如果判断的结果为真,则保持,反之,不保存。 82 | 83 | **判断条件**: 84 | 85 | - 比较运算符:`>`、`<`、`>=`、`<=`、`<>`、`=`、`like`、`between and`、`in`和`not in`; 86 | - 逻辑运算符:`&&`、`||`、和`!`. 87 | 88 | 89 | 执行如下 SQL 语句,进行测试: 90 | 91 | ``` 92 | -- 查询表 student 中 id 为 2、3、5 的记录 93 | select * from student where id = 2 || id = 3 || id = 5; 94 | select * from student where id in (2,3,5); 95 | ``` 96 | 97 | ![select-or](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-or.png) 98 | 99 | ``` 100 | -- 查询表 student 中 id 在 2 和 5 之间的记录 101 | select * from student where id between 2 and 5; 102 | ``` 103 | 104 | ![select-between](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-between.png) 105 | 106 | 如上图所示,咱们会发现:**在使用`between and`的时候,其选择的区间为闭区间,即包含端点值**。此外,`and`前面的数值必须小于等于`and`后面的数值,否则会出现空判断,例如: 107 | 108 | ![select-set](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-set.png) 109 | 110 | 111 | ### `group by`子句 112 | 113 | `group by`子句:**根据表中的某个字段进行分组,即将含有相同字段值的记录放在一组,不同的放在不同组**。 114 | 115 | - **基本语法**:`group by + 字段名;` 116 | 117 | 执行如下 SQL 语句,进行测试: 118 | 119 | ``` 120 | -- 将表 student 中的数据按字段 sex 进行分组 121 | select * from student group by sex; 122 | ``` 123 | 124 | ![select-group-bysex](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-group-bysex.png) 125 | 126 | 观察上图,咱们会发现:表`student`在分组过后,数据“丢失”啦!实际上并非如此,产生这样现象原因为:**`group by`分组的目的是为了(按分组字段)统计数据,并不是为了单纯的进行分组而分组**。为了方便统计数据,SQL 提供了一系列的统计函数,例如: 127 | 128 | - `cout()`:统计分组后,每组的总记录数; 129 | - `max()`:统计每组中的最大值; 130 | - `min()`:统计每组中的最小值; 131 | - `avg()`:统计每组中的平均值; 132 | - `sum()`:统计每组中的数据总和。 133 | 134 | 执行如下 SQL 语句,进行测试: 135 | 136 | ``` 137 | -- 将表 student 中的数据按字段 sex 进行分组,并进行统计 138 | select sex,count(*),max(age),min(age),avg(age),sum(age) from student group by sex; 139 | ``` 140 | ![select-count-max-min](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-count-max-min.png) 141 | 142 | 其中,`count()`函数里面可以使用两种参数,分别为:`*`表示统计组内全部记录的数量;`字段名`表示统计对应字段的非`null`(如果某条记录中该字段的值为`null`,则不统计)记录的总数。此外,使用`group by`进行分组之后,展示的记录会根据分组的字段值进行排序,默认为升序。当然,也可以人为的设置升序和降序。 143 | 144 | - **基本语法**:`group by + 字段名 + [asc/desc];` 145 | 146 | 执行如下 SQL 语句,进行测试: 147 | 148 | ``` 149 | -- 将表 student 中的数据按字段 sex 进行分组,并排序 150 | select sex,count(*) from student group by sex; 151 | select sex,count(*) from student group by sex asc; 152 | select sex,count(*) from student group by sex desc; 153 | ``` 154 | ![select-sex-count](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-sex-count.png) 155 | 156 | 通过观察上面数个分组示例,细心的同学会发现:咱们在之前的示例中,都是用单字段进行分组。实际上,咱们也可以使用**多字段分组**,即:**先根据一个字段进行分组,然后对分组后的结果再次按照其他字段(前提是分组后的结果中包含此字段)进行分组**。 157 | 158 | 执行如下 SQL 语句,进行测试: 159 | 160 | ``` 161 | -- 将表 student 中的数据先按字段 grade 进行分组,再按字段 sex 进行分组 162 | select *,count(*) from student group by grade,sex; 163 | ``` 164 | 165 | ![select-by-grade-sex](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-by-grade-sex.png) 166 | 167 | 在这里,函数`group_concat(字段名)`可以对分组的结果中的某个字段值进行字符串连接,即保留该组某个字段的所有值。例如: 168 | 169 | ``` 170 | -- 将表 student 中的数据按字段 sex进行分组,并保留字段 name 的值 171 | select sex,age,count(*),group_concat(name) from student group by sex; 172 | ``` 173 | ![select-group-by-sex](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-group-by-sex.png) 174 | 175 | 此外,简单介绍**回溯统计**的概念:**利用`with rollup`关键字(书写在 SQL 语句末尾),可以在每次分组过后,根据当前分组的字段进行统计,并向上一级分组进行汇报**。例如: 176 | 177 | ``` 178 | -- 将表 student 中的数据按字段 sex进行分组,并进行回溯统计 179 | select sex,count(*) from student group by sex with rollup; 180 | ``` 181 | ![select-with-rollup](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-with-rollup.png) 182 | 183 | 观察上图,咱们会发现:**在进行回溯统计的时候,会将分组字段置空**。 184 | 185 | 186 | ### `having`子句 187 | 188 | `having`字句:**与`where`子句一样,都是进行条件判断的**,但是`where`是针对磁盘数据进行判断,数据进入内存之后,会进行分组操作,分组结果就需要`having`来处理。思考可知,`having`能做`where`能做的几乎所有事情,但是`where`却不能做`having`能做的很多事情。 189 | 190 | **第 1 点:分组统计的结果或者说统计函数只有`having`能够使用** 191 | 192 | 执行如下 SQL 语句,进行测试: 193 | 194 | ``` 195 | -- 求出表 student 中所有班级人数大于等于 2 的班级 196 | select grade,count(*) from student group by grade having count(*) >= 2; 197 | select grade,count(*) from student where count(*) >= 2 group by grade; 198 | ``` 199 | 200 | ![select-having](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-having.png) 201 | 202 | 如上图所示,显然`having`子句可以对统计函数得到的结果进行筛选,但是`where`却不能。 203 | 204 | **第 2 点:`having`能够使用字段别名,`where`则不能** 205 | 206 | 执行如下 SQL 语句,进行测试: 207 | 208 | ``` 209 | -- 求出表 student 中所有班级人数大于等于 2 的班级 210 | select grade,count(*) as total from student group by grade having total >= 2; 211 | select grade,count(*) as total from student where total >= 2 group by grade; 212 | ``` 213 | 214 | ![select-having-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-having-2.png) 215 | 216 | 如上图所示,显然咱们的结论得到了验证。究其原因,`where`是从磁盘读取数据,而磁盘中数据的名字只能是字段名,别名是数据(字段)进入到内存后才产生的。值得注意的是,**在上述 SQL 语句中咱们使用了字段别名,这在无意中就优化了 SQL 并提高了效率,因为少了一次统计函数的计算**。 217 | 218 | 219 | ### `order by`子句 220 | 221 | `order by`子句:**根据某个字段进行升序或者降序排序,依赖校对集**。 222 | 223 | - **基本语法**:`order by + [asc/desc];` 224 | 225 | 其中,`asc`为升序,为默认值;`desc`为降序。 226 | 227 | 执行如下 SQL 语句,进行测试: 228 | 229 | ``` 230 | -- 将表 student 中的数据按年龄 age 进行排序 231 | select * from student order by age; 232 | ``` 233 | 234 | ![select-order-by](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-order-by.png) 235 | 236 | 此外,咱们可以进行「**多字段排序**」,即**先根据某个字段进行排序,然后在排序后的结果中,再根据某个字段进行排序**。 237 | 238 | 执行如下 SQL 语句,进行测试: 239 | 240 | ``` 241 | -- 将表 student 中的数据先按年龄 age 升序排序,再按班级 grade 降序排序 242 | select * from student order by age,grade desc; 243 | ``` 244 | 245 | ![select-order-by-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-order-by-2.png) 246 | 247 | 248 | ### `limit`子句 249 | 250 | `limit`子句:**是一种限制结果的语句,通常来限制结果的数量**。 251 | 252 | - **基本语法**:`limit + [offset] + length;` 253 | 254 | 其中,`offset`为起始值;`length`为长度。 255 | 256 | **第 1 种:只用来限制长度(数据量)** 257 | 258 | 执行如下 SQL 语句,进行测试: 259 | 260 | ``` 261 | -- 查询表 student 中的全部记录 262 | select * from student; 263 | -- 查询表 student 中的 3 条记录 264 | select * from student limit 3; 265 | ``` 266 | ![select-limit](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-limit.png) 267 | 268 | 269 | **第 2 种:限制起始值,限制长度(数据量)** 270 | 271 | 执行如下 SQL 语句,进行测试: 272 | 273 | ``` 274 | -- 查询表 student 中的记录 275 | select * from student limit 0,2; 276 | -- 查询表 student 中的记录 277 | select * from student limit 2,2; 278 | ``` 279 | 280 | ![select-limit-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/select/select-limit-2.png) 281 | 282 | **第 3 种:主要用来实现数据的分页,目的是为用户节省时间,提高服务器的响应效率,减少资源的浪费** 283 | 284 | 大致设计: 285 | 286 | - 对于用户来讲,可以通过点击页码按钮,如`1`、`2`、`3`等来进行选择; 287 | - 对于服务器来讲,可以根据用户选择的页码来获取不同的数据。 288 | 289 | 其中, 290 | 291 | - `length`:表示每页的数据量,基本不变; 292 | - `offset`:表示每页的起始值,公式为`offset=(页码-1)*length`. 293 | 294 | 如果大家感兴趣的话,可以结合`Java`或者其他语言进行测试。 295 | 296 | 297 | ---------- 298 | 299 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 300 | 301 | 302 | ---------- 303 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 304 | -------------------------------------------------------------------------------- /articles/sql-data.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(六)「SQL 基本操作 之 数据操作」 2 | 3 | SQL 基本操作 4 | ======== 5 | 6 | 基本操作:CURD,即**增删改查**。 7 | 8 | 根据操作对象的不同,咱们可以将 SQL 的基本操作分为三类,分别为:库操作、表(字段)操作和数据操作。 9 | 10 | 数据操作 11 | --- 12 | **1 新增数据** 13 | 14 | 对于数据的新增操作,有两种方法。 15 | 16 | - **第 1 种**:给全表字段插入数据,不需要指定字段列表,但要求数据的值出现的顺序必须与表中的字段出现的顺序一致,并且凡是非数值数据,都需要用引号(建议使用单引号)括起来。 17 | - 基本语法:`insert into + 表名 + values(值列表)[,(值列表)];` 18 | - 示例:`insert into test valus('charies',18,'3.1');` 19 | - **第 2 种**:给部分字段插入数据,需要选定字段列表,字段列表中字段出现的顺序与表中字段的顺序无关,但值列表中字段值的顺序必须与字段列表中的顺序保持一致。 20 | - 基本语法:`insert into + 表名(字段列表) + values(值列表)[,(值列表)];` 21 | - 示例:`insert into test(age,name) valus(18,'guo');` 22 | 23 | 24 | **2 查询数据** 25 | 26 | 查看全部 --> 基本语法:`select * from + 表名 + [where 条件];` 27 | 28 | - 示例:`select * from test`; 29 | 30 | 查看部分 --> 基本语法:`select + 字段名称[,字段名称] + from + 表名 + [where 条件];` 31 | 32 | - 示例:`select name,age,grade from test where age = '18'`; 33 | 34 | 35 | **3 更新数据** 36 | 37 | 基本语法:`update + 表名 + set + 字段 = 值 + [where 条件];` 38 | 39 | - 示例:`update test set age = 20 where name = 'guo';` 40 | 41 | 在这里,建议尽量加上`where`条件,否则的话,操作的就是全表数据。 42 | 43 | 此外,判断更新操作是否成功,并不是看 SQL 语句是否执行成功,而是看是否有记录受到影响,即`affected`的数量大于`1`时,才是真正的更新成功。 44 | 45 | **4 删除数据** 46 | 47 | 基本语法:`delete from + 表名 + [where 条件];` 48 | 49 | - 示例:`delete from test where grade = '3.1';` 50 | 51 | 52 | 当然,我们也可以用`drop`来实现删除操作,不过与`delete`相比,`drop`的威力更强,其在执行删除操作的时候,不仅会删除数据,还会删除定义并释放存储空间;而`delete`在执行删除操作的时候,仅会删除数据,并不会删除定义和释放存储空间。 53 | 54 | ---------- 55 | 56 | **温馨提示**:用符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 57 | 58 | ---------- 59 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 60 | -------------------------------------------------------------------------------- /articles/sql-database.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(四)「SQL 基本操作 之 库操作」 2 | 3 | SQL 基本操作 4 | ======== 5 | 6 | 基本操作:CURD,即**增删改查**。 7 | 8 | 根据操作对象的不同,咱们可以将 SQL 的基本操作分为三类,分别为:库操作、表(字段)操作和数据操作。 9 | 10 | 库操作 11 | --- 12 | **1 新增数据库** 13 | 14 | 基本语法:`create database + 数据库名称 + [库选项];` 15 | 16 | 其中,库选项是用来约束数据库的,为可选项(有默认值),共有两种,分别为: 17 | 18 | - 字符集设定:`charset/ character set`+ 具体字符集,用来表示数据存储的编码格式,常用的字符集包括`GBK`和`UTF8`等。 19 | - 校对集设定:`collate`+ 具体校对集,表示数据比较的规则,其依赖字符集。 20 | 21 | 示例:`create database TBL_ERROR_CODE charset utf8;` 22 | 23 | 其中,数据库的名字不能用关键字(已经被占用的字符,例如 update 和 insert 等)或者保留字(将来可能会用的,例如 access 和 cast 等)。 24 | 25 | 如果非要使用数据库的关键字或者保留字作为数据库名称,那么必须用反引号将其括起来,例如: 26 | 27 | `create database `access` charset utf8;` 28 | 29 | 如果还想使用中文作为数据库的名称,那就得保证数据库能够识别中文(强烈建议不要用中文命名数据库的名称),例如: 30 | 31 | ``` 32 | -- 设置中文名称的方法,其中 gbk 为当前数据库的默认字符集 33 | set names gbk; 34 | create database 北京 charset gbk; 35 | ``` 36 | 37 | ![1](http://img.blog.csdn.net/20170503130944273) 38 | 39 | **2 查询数据库** 40 | 41 | 查看全部 --> 基本语法:`show databases;` 42 | 43 | 查看部分(模糊查询)--> 基本语法:`show databases like 'pattern';` 44 | 45 | 其中,`pattern`是匹配模式,有两种,分别为: 46 | 47 | - `%`:表示匹配多个字符; 48 | - `_`:表示匹配单个字符。 49 | 50 | 此外,在匹配含有下划线`_`的数据库名称的时候,需要在下划线前面加上反斜线`\_`进行转义操作。 51 | 52 | 示例:`show databases like 'TBL%';`表示匹配所有`TBL`开头的数据库。 53 | 54 | 查看数据库的创建语句 --> 基本语法:`show create database + 数据库名称;` 55 | 56 | 在这里,查看的结果有可能与咱们书写的 SQL 语句不同,这是因为数据库在执行 SQL 语句之前会优化 SQL,系统保存的是优化后的结果。 57 | 58 | **3 更新数据库** 59 | 60 | 在这里,需要注意:数据库的名字不可以修改。 61 | 62 | 数据库的修改仅限库选项,即字符集和校对集(校对集依赖字符集)。 63 | 64 | 基本语法:`alter database + 数据库名称 + [库选项];` 65 | 66 | - `charset/character set[=] 字符集;` 67 | - `collate[=] 校对集;` 68 | 69 | 示例:`alter database TBL_ERROR_CODE charset gbk;`表示修改此数据库的字符集为`gbk`. 70 | 71 | **4 删除数据库** 72 | 73 | 基本语法:`drop database + 数据库名称;` 74 | 75 | 在这里,需要注意:在删除数据库之前,应该先进行备份操作,因为删除为不可逆操作,所以不要随意删除数据库。 76 | 77 | ---------- 78 | 79 | **温馨提示**:用符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 80 | 81 | ---------- 82 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 83 | -------------------------------------------------------------------------------- /articles/sql-operation.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(四)「SQL 基本操作」 2 | 3 | SQL 基本操作 4 | ======== 5 | 6 | 基本操作:CURD,即**增删改查**。 7 | 8 | 根据操作对象的不同,咱们可以将 SQL 的基本操作分为三类,分别为:库操作、表(字段)操作和数据操作。 9 | 10 | 库操作 11 | --- 12 | **1 新增数据库** 13 | 14 | 基本语法:`create database + 数据库名称 + [库选项];` 15 | 16 | 其中,库选项是用来约束数据库的,为可选项(有默认值),共有两种,分别为: 17 | 18 | - 字符集设定:`charset/ character set`+ 具体字符集,用来表示数据存储的编码格式,常用的字符集包括`GBK`和`UTF8`等。 19 | - 校对集设定:`collate`+ 具体校对集,表示数据比较的规则,其依赖字符集。 20 | 21 | 示例:`create database TBL_ERROR_CODE charset utf8;` 22 | 23 | 其中,数据库的名字不能用关键字(已经被占用的字符,例如 update 和 insert 等)或者保留字(将来可能会用的,例如 access 和 cast 等)。 24 | 25 | 如果非要使用数据库的关键字或者保留字作为数据库名称,那么必须用反引号将其括起来,例如: 26 | 27 | `create database `access` charset utf8;` 28 | 29 | 如果还想使用中文作为数据库的名称,那就得保证数据库能够识别中文(强烈建议不要用中文命名数据库的名称),例如: 30 | 31 | ``` 32 | -- 设置中文名称的方法,其中 gbk 为当前数据库的默认字符集 33 | set names gbk; 34 | create database 北京 charset gbk; 35 | ``` 36 | 37 | ![set-name-gbk](https://github.com/guobinhit/mysql-tutorial/blob/master/images/sql-operation/set-name-gbk.png) 38 | 39 | **2 查询数据库** 40 | 41 | 查看全部 --> 基本语法:`show databases;` 42 | 43 | 查看部分(模糊查询)--> 基本语法:`show databases like 'pattern';` 44 | 45 | 其中,`pattern`是匹配模式,有两种,分别为: 46 | 47 | - `%`:表示匹配多个字符; 48 | - `_`:表示匹配单个字符。 49 | 50 | 此外,在匹配含有下划线`_`的数据库名称的时候,需要在下划线前面加上反斜线`\_`进行转义操作。 51 | 52 | 示例:`show databases like 'TBL%';`表示匹配所有`TBL`开头的数据库。 53 | 54 | 查看数据库的创建语句 --> 基本语法:`show create database + 数据库名称;` 55 | 56 | 在这里,查看的结果有可能与咱们书写的 SQL 语句不同,这是因为数据库在执行 SQL 语句之前会优化 SQL,系统保存的是优化后的结果。 57 | 58 | **3 更新数据库** 59 | 60 | 在这里,需要注意:数据库的名字不可以修改。 61 | 62 | 数据库的修改仅限库选项,即字符集和校对集(校对集依赖字符集)。 63 | 64 | 基本语法:`alter database + 数据库名称 + [库选项];` 65 | 66 | - `charset/character set[=] 字符集;` 67 | - `collate[=] 校对集;` 68 | 69 | 示例:`alter database TBL_ERROR_CODE charset gbk;`表示修改此数据库的字符集为`gbk`. 70 | 71 | **4 删除数据库** 72 | 73 | 基本语法:`drop database + 数据库名称;` 74 | 75 | 在这里,需要注意:在删除数据库之前,应该先进行备份操作,因为删除为不可逆操作,所以不要随意删除数据库。 76 | 77 | 表操作 78 | --- 79 | **1 新增表** 80 | 81 | 基本语法: 82 | ``` 83 | create table [if not exists] + 表名( 84 | 字段名称 数据类型, 85 | …… 86 | 字段名称 数据类型 /* 最后后一行,不需要加逗号 */ 87 | )[表选项]; 88 | ``` 89 | 90 | 其中,`if not exists`表示 91 | 92 | - 如果表名不存在,就执行创建代码;如果表名存在,则不执行创建代码。 93 | 94 | 表选项则是用来控制表的表现形式的,共有三种,分别为: 95 | 96 | - 字符集设定:`charset/ character set`+ 具体字符集,用来表示数据存储的编码格式,常用的字符集包括`GBK`和`UTF8`等。 97 | - 校对集设定:`collate`+ 具体校对集,表示数据比较的规则,其依赖字符集。 98 | - 存储引擎:`engine`+具体存储引擎,默认为`InnoDB`,常用的还有`MyISAM`. 99 | 100 | 由于任何表都归属于某个数据库,因此在创建表的时候,都必须先指定具体的数据库。在这里,指定数据库的方式有两种,分别为: 101 | 102 | - **第 1 种**:显式的指定表所属的数据库,示例 103 | 104 | ``` 105 | create table if not exists test.student( 106 | name varchar(10), 107 | age int, /* 整型不需要指定具体的长度 */ 108 | grade varchar(10) /* 最后后一行,不需要加逗号 */ 109 | )charset utf8; 110 | ``` 111 | - **第 2 种**:隐式的指定表所属的数据库,示例 112 | 113 | ``` 114 | use test; /* use + 数据库名称,表示切换到指定的数据库,这句命令其实不加分号也可以,但不建议这么做 */ 115 | create table if not exists student( 116 | name varchar(10), 117 | age int, /* 整型不需要指定具体的长度 */ 118 | grade varchar(10) /* 最后后一行,不需要加逗号 */ 119 | )charset utf8; 120 | ``` 121 | 122 | **2 查询表** 123 | 124 | 查看全部 --> 基本语法:`show tables;` 125 | 126 | 查看部分(模糊查询)--> 基本语法:`show tables like 'pattern';` 127 | 128 | 其中,`pattern`是匹配模式,有两种,分别为: 129 | 130 | - `%`:表示匹配多个字符; 131 | - `_`:表示匹配单个字符。 132 | 133 | 此外,在匹配含有下划线`_`的表名的时候,需要在下划线前面加上反斜线`\_`进行转义操作。 134 | 135 | 示例:`show tables like '%t';`表示匹配所有以`t`结尾的表。 136 | 137 | 查看表的创建语句 --> 基本语法:`show create table + 表名;` 138 | 139 | 在这里,咱们也可以用`\g`和`\G`代替上述语句中的`;`分号,其中`\g`等价于分号,`\G`则在等价于分号的同时,将查的表结构旋转`90`度,变成纵向结构。 140 | 141 | 查看表中的字段信息 --> 基本语法:`desc/describe/show columns from + 表名;` 142 | 143 | **3 更新表** 144 | 145 | 在这里,需要注意:表的修改,分为修改表本身和修改表中的字段。 146 | 147 | - **第 1 类**:修改表本身 148 | - 修改表名,基本语法:`rename table 旧表名 to 新表名;` 149 | - 修改表选项,基本语法:`alter table + 表名 + 表选项[=] + 值;` 150 | 151 | - **第 2 类**:修改表中的字段,新增、修改、重命名和删除 152 | - 新增字段,基本语法:`alter table + 表名 + add + [column] + 字段名 + 数据类型 + [列属性][位置];` 153 | - 其中,位置表示此字段存储的位置,分为`first(第一个位置)`和`after + 字段名(指定的字段后,默认为最后一个位置)`. 154 | - 示例:`alter table student add column id int first;` 155 | - 修改字段,基本语法:`alter table + 表名 + modify + 字段名 + 数据类型 + [列属性][位置];` 156 | - 其中,位置表示此字段存储的位置,分为`first(第一个位置)`和`after + 字段名(指定的字段后,默认为最后一个位置)`. 157 | - 示例:`alter table student modify name char(10) after id;` 158 | - 重命名字段,基本语法:`alter table + 表名 + change + 旧字段名 + 新字段名 + 数据类型 + [列属性][位置];` 159 | - 其中,位置表示此字段存储的位置,分为`first(第一个位置)`和`after + 字段名(指定的字段后,默认为最后一个位置)`. 160 | - 示例:`alter table student change grade class varchar(10);` 161 | - 删除字段,基本语法:`alter table + 表名 + drop+ 字段名;` 162 | - 示例:`alter table student drop age;` 163 | - 注意:如果表中已经存在数据,那么删除该字段会清空该字段的所有数据,而且不可逆,慎用。 164 | 165 | **4 删除表** 166 | 167 | 基本语法: 168 | 169 | ``` 170 | -- 可以一次删除多张表 171 | drop table + 表1, 表2 ... ; 172 | ``` 173 | 174 | 在这里,需要注意:此删除为不可逆操作,希望大家谨慎使用。 175 | 176 | 177 | 数据操作 178 | --- 179 | **1 新增数据** 180 | 181 | 对于数据的新增操作,有两种方法。 182 | 183 | - **第 1 种**:给全表字段插入数据,不需要指定字段列表,但要求数据的值出现的顺序必须与表中的字段出现的顺序一致,并且凡是非数值数据,都需要用引号(建议使用单引号)括起来。 184 | - 基本语法:`insert into + 表名 + values(值列表)[,(值列表)];` 185 | - 示例:`insert into test valus('charies',18,'3.1');` 186 | - **第 2 种**:给部分字段插入数据,需要选定字段列表,字段列表中字段出现的顺序与表中字段的顺序无关,但值列表中字段值的顺序必须与字段列表中的顺序保持一致。 187 | - 基本语法:`insert into + 表名(字段列表) + values(值列表)[,(值列表)];` 188 | - 示例:`insert into test(age,name) valus(18,'guo');` 189 | 190 | 191 | **2 查询数据** 192 | 193 | 查看全部 --> 基本语法:`select * from + 表名 + [where 条件];` 194 | 195 | - 示例:`select * from test`; 196 | 197 | 查看部分 --> 基本语法:`select + 字段名称[,字段名称] + from + 表名 + [where 条件];` 198 | 199 | - 示例:`select name,age,grade from test where age = '18'`; 200 | 201 | 202 | **3 更新数据** 203 | 204 | 基本语法:`update + 表名 + set + 字段 = 值 + [where 条件];` 205 | 206 | - 示例:`update test set age = 20 where name = 'guo';` 207 | 208 | 在这里,建议尽量加上`where`条件,否则的话,操作的就是全表数据。 209 | 210 | 此外,判断更新操作是否成功,并不是看 SQL 语句是否执行成功,而是看是否有记录受到影响,即`affected`的数量大于`1`时,才是真正的更新成功。 211 | 212 | **4 删除数据** 213 | 214 | 基本语法:`delete from + 表名 + [where 条件];` 215 | 216 | - 示例:`delete from test where grade = '3.1';` 217 | 218 | 219 | 当然,我们也可以用`drop`来实现删除操作,不过与`delete`相比,`drop`的威力更强,其在执行删除操作的时候,不仅会删除数据,还会删除定义并释放存储空间;而`delete`在执行删除操作的时候,仅会删除数据,并不会删除定义和释放存储空间。 220 | 221 | ---------- 222 | 223 | **温馨提示**:用符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 224 | 225 | ---------- 226 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 227 | -------------------------------------------------------------------------------- /articles/sql-table.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(五)「SQL 基本操作 之 表操作」 2 | 3 | SQL 基本操作 4 | ======== 5 | 6 | 基本操作:CURD,即**增删改查**。 7 | 8 | 根据操作对象的不同,咱们可以将 SQL 的基本操作分为三类,分别为:库操作、表(字段)操作和数据操作。 9 | 10 | 表操作 11 | --- 12 | **1 新增表** 13 | 14 | 基本语法: 15 | ``` 16 | create table [if not exists] + 表名( 17 | 字段名称 数据类型, 18 | …… 19 | 字段名称 数据类型 /* 最后后一行,不需要加逗号 */ 20 | )[表选项]; 21 | ``` 22 | 23 | 其中,`if not exists`表示 24 | 25 | - 如果表名不存在,就执行创建代码;如果表名存在,则不执行创建代码。 26 | 27 | 表选项则是用来控制表的表现形式的,共有三种,分别为: 28 | 29 | - 字符集设定:`charset/ character set`+ 具体字符集,用来表示数据存储的编码格式,常用的字符集包括`GBK`和`UTF8`等。 30 | - 校对集设定:`collate`+ 具体校对集,表示数据比较的规则,其依赖字符集。 31 | - 存储引擎:`engine`+具体存储引擎,默认为`InnoDB`,常用的还有`MyISAM`. 32 | 33 | 由于任何表都归属于某个数据库,因此在创建表的时候,都必须先指定具体的数据库。在这里,指定数据库的方式有两种,分别为: 34 | 35 | - **第 1 种**:显式的指定表所属的数据库,示例 36 | 37 | ``` 38 | create table if not exists test.student( 39 | name varchar(10), 40 | age int, /* 整型不需要指定具体的长度 */ 41 | grade varchar(10) /* 最后后一行,不需要加逗号 */ 42 | )charset utf8; 43 | ``` 44 | - **第 2 种**:隐式的指定表所属的数据库,示例 45 | 46 | ``` 47 | use test; /* use + 数据库名称,表示切换到指定的数据库,这句命令其实不加分号也可以,但不建议这么做 */ 48 | create table if not exists student( 49 | name varchar(10), 50 | age int, /* 整型不需要指定具体的长度 */ 51 | grade varchar(10) /* 最后后一行,不需要加逗号 */ 52 | )charset utf8; 53 | ``` 54 | 55 | **2 查询表** 56 | 57 | 查看全部 --> 基本语法:`show tables;` 58 | 59 | 查看部分(模糊查询)--> 基本语法:`show tables like 'pattern';` 60 | 61 | 其中,`pattern`是匹配模式,有两种,分别为: 62 | 63 | - `%`:表示匹配多个字符; 64 | - `_`:表示匹配单个字符。 65 | 66 | 此外,在匹配含有下划线`_`的表名的时候,需要在下划线前面加上反斜线`\_`进行转义操作。 67 | 68 | 示例:`show tables like '%t';`表示匹配所有以`t`结尾的表。 69 | 70 | 查看表的创建语句 --> 基本语法:`show create table + 表名;` 71 | 72 | 在这里,咱们也可以用`\g`和`\G`代替上述语句中的`;`分号,其中`\g`等价于分号,`\G`则在等价于分号的同时,将查的表结构旋转`90`度,变成纵向结构。 73 | 74 | 查看表中的字段信息 --> 基本语法:`desc/describe/show columns from + 表名;` 75 | 76 | **3 更新表** 77 | 78 | 在这里,需要注意:表的修改,分为修改表本身和修改表中的字段。 79 | 80 | - **第 1 类**:修改表本身 81 | - 修改表名,基本语法:`rename table 旧表名 to 新表名;` 82 | - 修改表选项,基本语法:`alter table + 表名 + 表选项[=] + 值;` 83 | 84 | - **第 2 类**:修改表中的字段,新增、修改、重命名和删除 85 | - 新增字段,基本语法:`alter table + 表名 + add + [column] + 字段名 + 数据类型 + [列属性][位置];` 86 | - 其中,位置表示此字段存储的位置,分为`first(第一个位置)`和`after + 字段名(指定的字段后,默认为最后一个位置)`. 87 | - 示例:`alter table student add column id int first;` 88 | - 修改字段,基本语法:`alter table + 表名 + modify + 字段名 + 数据类型 + [列属性][位置];` 89 | - 其中,位置表示此字段存储的位置,分为`first(第一个位置)`和`after + 字段名(指定的字段后,默认为最后一个位置)`. 90 | - 示例:`alter table student modify name char(10) after id;` 91 | - 重命名字段,基本语法:`alter table + 表名 + change + 旧字段名 + 新字段名 + 数据类型 + [列属性][位置];` 92 | - 其中,位置表示此字段存储的位置,分为`first(第一个位置)`和`after + 字段名(指定的字段后,默认为最后一个位置)`. 93 | - 示例:`alter table student change grade class varchar(10);` 94 | - 删除字段,基本语法:`alter table + 表名 + drop+ 字段名;` 95 | - 示例:`alter table student drop age;` 96 | - 注意:如果表中已经存在数据,那么删除该字段会清空该字段的所有数据,而且不可逆,慎用。 97 | 98 | **4 删除表** 99 | 100 | 基本语法: 101 | 102 | ``` 103 | -- 可以一次删除多张表 104 | drop table + 表1, 表2 ... ; 105 | ``` 106 | 107 | 在这里,需要注意:此删除为不可逆操作,希望大家谨慎使用。 108 | 109 | ---------- 110 | 111 | **温馨提示**:用符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 112 | 113 | 114 | ---------- 115 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 116 | -------------------------------------------------------------------------------- /articles/sub-query.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二十三)「子查询」 2 | 3 | **子查询**:`sub query`,查询是在某个查询结果之上进行的,一条`select`语句内部包含了另外一条`select`语句。 4 | 5 | ## 分类 6 | 7 | 子查询有两种分类方式,分别为:按按结果分类和位置分类。 8 | 9 | **按结果分类**,即根据子查询得到的数据进行分类(理论上,任何一个查询结果都可以理解为一个二维表),分别为: 10 | 11 | - 标量子查询:子查询得到的结果是一行一列,出现的位置在`where`之后; 12 | - 列子查询:子查询得到的结果是一列多行,出现的位置在`where`之后; 13 | - 行子查询:子查询得到的结果是多行一列(多行多列),出现的位置在`where`之后; 14 | - 表子查询:子查询得到的结果是多行多列,出现的位置在`from`之后。 15 | 16 | 17 | **按位置分类**,即根据子查询(`select`语句)在外部查询(`select`语句)中出现的位置进行分类,分别为: 18 | 19 | - `from`子查询:子查询出现在`from`之后; 20 | - `where`子查询:子查询出现在`where`条件之中; 21 | - `exists`子查询:子查询出现在`exists`里面。 22 | 23 | ## 标量子查询 24 | 25 | **需求**:现知道班级名称为`PM3.1`,想要获取该班的全部学生。 26 | 27 | **思路**: 28 | 29 | - 先确定数据源,学生表。 30 | - `select * from student where c_id = ?;` 31 | - 然后获取班级 ID,可以通过(班级表)班级名称来确定。 32 | - `select id from class where grade = "PM3.1";` 33 | 34 | 执行如下 SQL 语句,进行测试: 35 | 36 | ``` 37 | -- 标量子查询 38 | select * from student where c_id = (select id from class where grade = "PM3.1"); 39 | ``` 40 | 41 | ![biaol](http://img.blog.csdn.net/20170826223108914) 42 | 43 | ## 列子查询 44 | 45 | **需求**:查询所有在读班级(学生表中存在的班级)的学生。 46 | 47 | **思路**: 48 | 49 | - 先确定数据源,学生表。 50 | - `select * from student where c_id in ?;` 51 | - 然后确定全部有效的班级 ID。 52 | - `select id from class;` 53 | 54 | 执行如下 SQL 语句,进行测试: 55 | 56 | ``` 57 | -- 列子查询 58 | select * from student where c_id in (select id from class); 59 | ``` 60 | 61 | ![column](http://img.blog.csdn.net/20170826231655784) 62 | 63 | 如上图所示,我们完成了列子查询。在列子查询的结果为一行多列时,我们需要使用`in`作为条件进行匹配;此外,在 MySQL 中还有三个类似的条件,分别为:`all`、`some`和`any`。 64 | 65 | - `any`等价于`in`,表示其中一个; 66 | - `any`等价于`smoe`,而`any`和`some`用于否定时却有些区别; 67 | - `all`表示等于全部。 68 | 69 | 值得注意的是,在我们使用上面三个关键字中任何一个的时候,都需要搭配`=`使用,例如: 70 | 71 | ``` 72 | -- 列子查询 73 | select * from student where c_id = any (select id from class); 74 | 75 | select * from student where c_id = some (select id from class); 76 | 77 | select * from student where c_id = all (select id from class); 78 | ``` 79 | 80 | ![ass](http://img.blog.csdn.net/20170826231616645) 81 | 82 | 如上图所示,为`any`、`some`和`all`的肯定用法,下面我们来测试其否定用法: 83 | 84 | ``` 85 | -- 列子查询 86 | select * from student where c_id != any (select id from class); 87 | 88 | select * from student where c_id != some (select id from class); 89 | 90 | select * from student where c_id != all (select id from class); 91 | ``` 92 | 93 | ![fouze](http://img.blog.csdn.net/20170826231526787) 94 | 95 | 观察上图,我们会发现`any`、`some`和`all`在用于否定时,其会将`null`值排除掉。实际上,在真正的开发中,这三个关键字并不常用。 96 | 97 | ## 行子查询 98 | 99 | 行子查询,返回的结果可以使一行多列或者多行多列。 100 | 101 | **需求**:查询学生表中,年龄最大且身高最高的学生。 102 | 103 | **思路**: 104 | 105 | - 先确定数据源,学生表。 106 | - `select * from student where age = ? and height = ?;` 107 | - 然后确定最大年龄和最大身高。 108 | - `select max(age), max(height) from student;` 109 | 110 | 执行如下 SQL 语句,进行测试: 111 | 112 | ``` 113 | -- 列子查询 114 | select * from student where 115 | -- 其中,(age, height) 称之为行元素 116 | (age, height) = (select max(age), max(height) from student); 117 | ``` 118 | 119 | ![row](http://img.blog.csdn.net/20170827105939052) 120 | 121 | ## 表子查询 122 | 123 | 表子查询,返回的结果是多行多列二维表(将子查询的结果当做二维表来使用),实际上,任何查询返回的结果都可以称之为二维表。 124 | 125 | **需求**:找出每个班身高最高的学生。 126 | 127 | **思路**: 128 | 129 | - 先确定数据源,将学生按身高进行降序排序。 130 | - `select * from student order by height desc;` 131 | - 从每个班级选出第一个学生。 132 | - `select * from student group by c_id;` 133 | 134 | 在这里,我们可能会有些疑问:为什么要将学生表降序排序?为什么从每个班级选出第一个学生就可以?这是因为`group by`(分组)只会取表中分组字段的第一条记录,而当我们将学生表按身高降序排序时,(每组)身高最高的学生就会出现在第一位。 135 | 136 | 执行如下 SQL 语句,进行测试: 137 | 138 | ``` 139 | -- 表子查询 140 | select * from 141 | -- 关键字 from 后面接表名 142 | (select * from student order by height desc) as student 143 | -- 按 c_id 进行分组 144 | group by c_id; 145 | ``` 146 | 147 | ![table](http://img.blog.csdn.net/20170827112336833) 148 | 149 | 由上面的 SQL 语句可知,表子查询也是`from`子查询,即有`select`语句位于`from`之后。 150 | 151 | 152 | ## `exists`子查询 153 | 154 | `exists`:表示是否存在的意思,因此`exists`子查询就是用来判断某些条件是否满足(跨表),`exists`是接在`where`之后,其返回的结果为`1`或`0`,满足条件为`1`,反之为`0`. 155 | 156 | **需求**:在班级存在的前提下,查询所有的学生。 157 | 158 | **思路**: 159 | 160 | - 先确定数据源。 161 | - `select * from student where ?;` 162 | - 然后确定条件是否满足。 163 | - `exists(select * from class);` 164 | 165 | 执行如下 SQL 语句,进行测试: 166 | 167 | ``` 168 | -- exists 子查询 169 | select * from student where 170 | exists(select * from class); 171 | 172 | -- 添加限定条件,满足条件 173 | select * from student where 174 | exists(select * from class where id = 3); 175 | 176 | -- 添加限定条件,不满足条件 177 | select * from student where 178 | exists(select * from class where id = 100); 179 | ``` 180 | 181 | ![exists](http://img.blog.csdn.net/20170827120457531) 182 | 183 | 至此,我们已经将子查询学习完啦!也许大家还会有些疑惑,那就是到底在什么时候用什么子查询?对于这个问题,我们不用过于纠结,因为这根本就是我们要用什么子查询的问题,而是根据实际需求,我们将查询返回的结果按形式命名的称呼而已。 184 | 185 | ---------- 186 | **查询`class`表**: 187 | 188 | ![class](http://img.blog.csdn.net/20170826223402050) 189 | 190 | **查询`student`表**: 191 | 192 | ![student](http://img.blog.csdn.net/20170827105224514) 193 | 194 | ---------- 195 | 196 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 197 | 198 | 199 | ---------- 200 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 201 | -------------------------------------------------------------------------------- /articles/thing-one.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二十七)「事务(上)」 2 | 3 | > **案例**:银行的数据库里面存储着用户的账户信息表,当用户 A 想用户 B 转账的时候,正常情况下,A 账户的余额减少,B 账户的余额增加;但是由于某种原因(例如突然断电),当 A 账户的余额减少之后,B 账户的余额并没有增加,这就造成了数据库数据的安全隐患。 4 | 5 | > **解决方案**:当 A 账户的余额减少之后,不要立即修改数据表,而是在确认 B 账户的余额增加之后,同时修改数据表。 6 | 7 | # 事务 8 | 9 | 通过前面的案例及解决方案,我们就引出了一个全新的概念,那就是:**事务**,即 10 | 11 | - 一系列将要发生或正在发生的连续操作。 12 | 13 | 而**事务安全,是一种保护连续操作同时实现(完成)的机制**。事务安全的意义就是,**保证数据操作的完整性**。 14 | 15 | 首先,执行如下 SQL 语句,创建银行账户表并插入数据: 16 | 17 | ``` 18 | -- 创建银行账户表 19 | create table bank_account( 20 | id int primary key auto_increment, 21 | cardno varchar(16) not null unique comment 'bank card number', 22 | name varchar(20) not null, 23 | money decimal(10,2) default 0.0 comment 'account balance' 24 | )charset utf8; 25 | 26 | -- 插入数据 27 | insert into bank_account values 28 | (null, '0000000000000001', 'Charies', 8000), 29 | (null, '0000000000000002', 'Gavin', 6000); 30 | ``` 31 | 32 | ![create-bankaccount](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-one/create-bankaccount.png) 33 | 34 | 接下来,让我们一起了解事务的操作。 35 | 36 | ## 事务操作 37 | 38 | 事务操作,分为两种:**自动事务(默认的),手动事务**。 39 | 40 | 在这里,以银行账户的余额增减为例,我们来了解手动事务的操作流程。 41 | 42 | **第 1 步**:开启事务,告诉系统以下所有操作,不要直接写入数据库,先存到事务日志。 43 | 44 | - **基本语法**:`start transaction;` 45 | 46 | 执行如上 SQL 语句,开启事务: 47 | 48 | ``` 49 | -- 开启事务 50 | start transaction; 51 | ``` 52 | 53 | ![start-transaction](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-one/start-transaction.png) 54 | 55 | **第 2 步**:减少 Charies 账户的余额 56 | 57 | ``` 58 | -- 更新 Charies 账户余额 59 | update bank_account set money = money - 1000 where id = 1; 60 | -- 查询 bank_account 表数据 61 | select * from bank_account; 62 | ``` 63 | 64 | ![update-bankaccount](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-one/update-bankaccount.png) 65 | 66 | 如上图所示,Charies 账户的余额显示减少`1000`,但实际上,由于我们开启了事务,数据表真实的数据,并没有同步更新。为了验证这个论断,我们重新打开一个数据库客户端,查询`bank_account`表的数据: 67 | 68 | ![compare-bankaccount](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-one/compare-bankaccount.png) 69 | 70 | 如上图所示,显然数据库的事务安全机制起了作用,当我们开启(手动)事务之后,其后一系列操作并没有直接写入数据库,而是存入了事务日志。在这里,我们并没有打开数据库事务的日志进行验证,因为事务日志存储的是经过编译之后的字节码文件。 71 | 72 | **第 3 步**:增加 Gavin 账户的余额 73 | 74 | ``` 75 | -- 更新 Gavin 账户余额 76 | update bank_account set money = money + 1000 where id = 2; 77 | -- 查询 bank_account 表数据 78 | select * from bank_account; 79 | ``` 80 | 81 | ![compare-bankaccount-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-one/compare-bankaccount-2.png) 82 | 83 | 如上图所示,Gavin 账户的余额显示增加`1000`,但是,由于我们开启了事务,数据表真实的数据,仍然没有同步更新。 84 | 85 | **第 4 步**:提交事务或回滚事务 86 | 87 | - **提交事务基本语法**:`commit;` 88 | - **回滚事务基本语法**:`rollback;` 89 | 90 | 如果我们选择提交事务,则将事务日志存储的记录直接更新到数据库,并清除事务日志;如果我们选择回滚事务,则直接将事务日志清除,所有在开启事务至回滚事务之间的操作失效,保持原有的数据库记录不变。在这里,我们以提交事务为例: 91 | 92 | ``` 93 | -- 提交事务 94 | commit; 95 | -- 查询 bank_account 表数据 96 | select * from bank_account; 97 | ``` 98 | 99 | ![compare-bankaccount-3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-one/compare-bankaccount-3.png) 100 | 101 | 如上图所示,当我们提交事务之后,数据库的真实记录更新,两个客户端的数据一致。 102 | 103 | 在此,值得我们注意的是:**当我们提交事务之后,在进行回滚事务是不起作用的,因为事务日志在提交事务的同时已经被清除啦**! 104 | 105 | 此外,我们还要知道:**现阶段,只有 InnoDB 和 BDB 两个存储引擎是支持事务安全机制的**,其中 InnoDB 免费,BDB 收费。因此,InnoDB 使用的最为广泛。 106 | 107 | 108 | 109 | 110 | ---------- 111 | 112 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 113 | 114 | 115 | ---------- 116 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 117 | -------------------------------------------------------------------------------- /articles/thing-two.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二十八)「事务(下)」 2 | 3 | > **温馨提示**:在「[事务(上)](https://github.com/guobinhit/mysql-tutorial/blob/master/articles/thing-one.md)」中,我们已经了解了如何在 MySQL 中开启事务,以及事务的一些基本操作。在本文中,我们将进一步学习事务的知识,包括事务原理、自动事务、回滚点和事务特性等。 4 | 5 | ## 事务原理 6 | 7 | **事务原理**:在事务开启之后,所有的操作都会被临时存储到事务日志,事务日志只有在收到`commit`命令之后,才会将操作同步到数据表,其他任何情况都会清空事务日志,例如突然断开连接、收到`rollback`命令等。 8 | 9 | 接下来,我们简单分析一下 MySQL 的操作过程: 10 | 11 | - **Step 1**:客户端与服务端建立连接,同时开启一个临时的事务日志,此事务日志只作用于当前用户的当次连接; 12 | - **Step 2**:在客户端用 SQL 语句执行写操作,客户端收到 SQL 语句,执行,将结果直接写入到数据表,并将数据表同步到数据库; 13 | - **Step 3**:我们在客户端开启事务,则服务端原来的操作机制被改变,后续所有操作都会被先写入到临时日志文件; 14 | - **Step 4**:在客户端执行 SQL 语句(例如写操作),服务端收到 SQL 语句,执行,将结果写入到临时日志文件,并不将结果同步到数据库; 15 | - **Step 5**:在客户端执行查询操作,服务端直接从临时日志文件中捞取数据,返回给客户端; 16 | - **Step 6**:在客户端执行`commit`或者`rollback`命令,清空临时日志文件,如果是`commit`命令,则将结果同步到数据库;如果是`rollback`命令,则不同步。 17 | 18 | 通过上面的分析,我们就知道了为什么在我们同时开启两个 MySQL 客户端窗口(两次连接)时,当一个窗口开启事务并执行 SQL 操作之后,另一个窗口在查询时并不会收到同步数据。原因就在于,当我们开启事务之后,服务端会将后续的操作都写入到临时日志文件,而另一个窗口在查询的时候,则是直接从数据库捞取数据,并会不走前一个的临时日志文件。 19 | 20 | ## 回滚点 21 | 22 | **回滚点**:在某个操作成功完成之后,后续的操作有可能成功也有可能失败,但无论后续操作的结果如何,前一次操作都已经成功了,因此我们可以在当前成功的位置,设置一个操作点,其可以供后续操作返回该位置,而不是返回所有操作,这个点称之为回滚点。关于回滚点的基本语法为, 23 | 24 | - **设置回滚点**:`savepoint + 回滚点名称;` 25 | - **返回回滚点**:`rollback to + 回滚点名称;` 26 | 27 | 执行如下 SQL 语句,进行测试: 28 | 29 | ``` 30 | -- 测试回滚点 31 | -- 查询 bank_account 表数据 32 | select * from bank_account; 33 | 34 | -- 开启事务 35 | start transaction; 36 | 37 | -- 事务操作 1:给 Charies 发工资 1000 元 38 | update bank_account set money = money + 10000 where id = 1; 39 | 40 | -- 设置回滚点 41 | savepoint spone; 42 | 43 | -- 银行扣税:错误 44 | update bank_account set money = money - 10000 * 0.05 where id = 2; 45 | 46 | -- 查询 bank_account 表数据 47 | select * from bank_account; 48 | ``` 49 | 50 | ![test-savepoint](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-two/test-savepoint.png) 51 | 52 | 执行如下 SQL 语句,继续进行测试: 53 | 54 | ``` 55 | -- 测试回滚点 56 | -- 返回回滚点 57 | rollback to spone; 58 | 59 | -- 银行扣税:正确 60 | update bank_account set money = money - 10000 * 0.05 where id = 1; 61 | 62 | -- 查询 bank_account 表数据 63 | select * from bank_account; 64 | 65 | -- 提交事务 66 | commit; 67 | ``` 68 | 69 | ![rollback](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-two/rollback.png) 70 | 71 | 如上图所示,显然在执行返回回滚点的操作之后,我们之前的错误操作得到了修正。 72 | 73 | ## 自动事务 74 | 75 | 在 MySQL 中,默认的都是自动事务处理,即用户在操作完成之后,其操作结果会立即被同步到数据库中。 76 | 77 | 自动事务是通过`autocommit`变量控制的,我们可以通过如下 SQL 语句,进行查看: 78 | 79 | ``` 80 | -- 查询自动事务 81 | show variables like 'autocommit'; 82 | ``` 83 | 84 | ![show-variables](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-two/show-variables.png) 85 | 86 | 如上图所示,此为 MySQL 的默认设置。实际上,我们可以自己选择是否开启自动事务处理,其基本语法为, 87 | 88 | - **开启自动事务处理**:`set autocommit = on / 1;` 89 | - **关闭自动事务处理**:`set autocommit = off / 0;` 90 | 91 | 在此,我们以关闭自动事务处理为例,进行演示: 92 | 93 | ``` 94 | -- 关闭自动事务处理 95 | set autocommit = 0; 96 | 97 | -- 查看自动事务处理 98 | show variables like 'autocommit'; 99 | 100 | -- 查看 bank_account 表数据 101 | select * from bank_account; 102 | 103 | -- 修改 bank_account 表数据 104 | update bank_account set money = money + 1000 where id = 1; 105 | 106 | -- 查看 bank_account 表数据 107 | select * from bank_account; 108 | ``` 109 | 110 | ![set-autocommit](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-two/set-autocommit.png) 111 | 112 | 如上图所示,我们并没有开启事务,仅是关闭了自动事务处理,但是我们发现,在我们修改了`bank_account`表中数据之后,其结果并不会立即同步到数据库。实际上,这就是关闭了自动事务处理的正常现象。在我们执行`commit`命令之后,上述操作的结果即可进行同步: 113 | 114 | ``` 115 | -- 提交 116 | commit; 117 | 118 | -- 查看 bank_account 表数据 119 | select * from bank_account; 120 | ``` 121 | 122 | ![commit](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-two/commit.png) 123 | 124 | 125 | 当然,如果我们不执行`commit`命令,而是执行`rollback`命令,那么之前的所用操作都会回滚到初始的状态。在此,我们需要注意的是:**通常情况下,我们是应该开启自动事务处理的,否则的话,每次操作完成之后都需要我们手动提交,那岂不是要被累死了**? 126 | 127 | ## 事务特性 128 | 129 | 事务的特性,可以简单的概括为`ACID`,具体为: 130 | 131 | - **原子性**:`Atomic`,表示事务的整个操作是一个整体,是不可分割的,要么全部成功,要么全部失败; 132 | - **一致性**:`Consistency`,表示事务操作的前后,数据表中的数据处于一致状态; 133 | - **隔离性**:`Isolation`,表示不同的事务操作之间是相互隔离的,互不影响; 134 | - **持久性**:`Durability`,表示事务一旦提交,将不可修改,永久性的改变数据表中的数据。 135 | 136 | 对于上述事务的四个特性,其中原子性、一致性、持久性比较容易理解,但是隔离性却需要格外注意。例如,开启两个客户端窗口,分别执行如下 SQL 语句,进行测试: 137 | 138 | ``` 139 | -- 演示隔离性操作:窗口 1 140 | -- 开始事务 141 | start transaction; 142 | 143 | -- 修改 id 为 1 的数据 144 | update bank_account set money = money + 666 where id = 1; 145 | 146 | -- 查看 bank_account 表数据 147 | select * from bank_account; 148 | 149 | --------- 万人迷分割线 --------- 150 | 151 | -- 演示隔离性操作:窗口 2 152 | -- 开始事务 153 | start transaction; 154 | 155 | -- 修改 id 为 2 的数据 156 | update bank_account set money = money + 666 where id = 2; 157 | 158 | -- 查看 bank_account 表数据 159 | select * from bank_account; 160 | ``` 161 | 162 | ![compare-bankaccount](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-two/compare-bankaccount.png) 163 | 164 | 如上图所示,其完美的展示了事务隔离性的效果,即窗口 1 的中的事务操作,没有影响到窗口 2 的事务操作;窗口 2 的中的事务操作,也没有影响到窗口 1 的事务操作。But,在我们执行下面的 SQL 语句之后,我们将会看到不同的效果: 165 | 166 | ``` 167 | -- 演示隔离性操作:窗口 1 168 | -- 开始事务 169 | start transaction; 170 | 171 | -- 修改 name 为 Charies 的数据 172 | update bank_account set money = money + 666 where name = 'Charies'; 173 | 174 | -- 查看 bank_account 表数据 175 | select * from bank_account; 176 | 177 | --------- 万人迷分割线 --------- 178 | 179 | -- 演示隔离性操作:窗口 2 180 | -- 开始事务 181 | start transaction; 182 | 183 | -- 修改 name 为 Gavin 的数据 184 | update bank_account set money = money + 666 where name = 'Gavin'; 185 | 186 | -- 查看 bank_account 表数据 187 | select * from bank_account; 188 | ``` 189 | 190 | ![compare-bankaccount-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-two/compare-bankaccount-2.png) 191 | 192 | 如上图所示,窗口 1 的事务可以正常执行,但是窗口 2 的事务开启成功,但是在修改数据的时候被“卡”住了,并且在持续一段时间之后,报出了一个 `Lock wait timeout exceeded`的错误: 193 | 194 | ![compare-bankaccount-3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/thing-two/compare-bankaccount-3.png) 195 | 196 | 那么到底是什么原因导致了上述错误的发生呢?这就是涉及到了数据库的另外一个知识点 **锁机制** 啦! 197 | 198 | 实际上,MySQL 使用的默认存储引擎是 InnoDB,而 InnoDB 默认使用的锁机制是 **行锁**(锁住操作的当前行),但是如果在事务操作的过程中,我们没有使用索引字段,那么系统就会自动进行全表检索,也就是其自动将行锁升级为 **表锁**(锁住操作的当前表)。 199 | 200 | 现在回想一下,我们在第一次测试的时候,使用的条件`id`为主键索引,所以两个事务可以表示出很好的隔离性,互不影响;在第二次测试的时候,我们将条件换为`name`,而`name`并不是索引字段,因此在第二次测试的时候,窗口 1 的事务使用了表锁,锁住了整张表,而在事务提交或回滚之前,其并不释放锁,所以所有试图修改被锁住表的数据的操作,都会陷入等待状态。等待超时,自然就报错啦! 201 | 202 | 对于锁机制,在「[基础教程](https://github.com/guobinhit/mysql-tutorial)」篇,我们并不做过多的介绍,在后续的「[性能优化](https://github.com/guobinhit/mysql-tutorial)」篇中在详细的进行讨论。 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | ---------- 214 | 215 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 216 | 217 | 218 | ---------- 219 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 220 | -------------------------------------------------------------------------------- /articles/trigger.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(三十)「触发器」 2 | 3 | > **案例**:网上购物,根据生产订单的类型,商品的库存量对应的进行增和减。此案例涉及两张表,分别为订单表和商品表,下单时,商品表库存减少;退单时,商品表库存增加。如何实现? 4 | 5 | ## 触发器 6 | 7 | **触发器**:`trigger`,是指**事先为某张表绑定一段代码,当表中的某些内容发生改变(增、删、改)的时候,系统会自动触发代码并执行**。 8 | 9 | 触发器包含三个要素,分别为 10 | 11 | - 事件类型:增删改,即`insert`、`delete`和`update`; 12 | - 触发时间:事件类型前和后,即`before`和`after`; 13 | - 触发对象:表中的每一条记录(行),即`整张表`。 14 | 15 | 每张表只能拥有一种触发时间的一种事件类型的触发器,即**每张表最多可以拥有 6 种触发器**。 16 | 17 | ### 创建触发器 18 | 19 | ``` 20 | -- 创建触发器基本语法 21 | delimiter 自定义符号 -- 临时修改语句结束符,在后续语句中只有遇到自定义符号才会结束语句 22 | create trigger + 触发器名称 + 触发器时间 + 事件类型 on 表名 for each row 23 | begin -- 代表触发器内容开始 24 | -- 触发器内容主体,每行用分号结尾 25 | end -- 代表触发器内容结束 26 | 自定义符号 -- 用于结束语句 27 | delimiter ; -- 恢复语句结束符 28 | ``` 29 | 30 | 根据上述案例的需求,我们先来创建两张表,分别为商品表`goods`和订单表`orders`,SQL 语句如下: 31 | 32 | ``` 33 | -- 创建商品表 34 | create table goods( 35 | id int primary key auto_increment, 36 | name varchar(20) not null, 37 | price decimal(10, 2) default 0, 38 | inventory int comment '商品库存量' 39 | )charset utf8; 40 | 41 | -- 插入两条数据 42 | insert into goods values(null, 'iPhone8', 5088, 1000), (null, 'iPhoneX', 8088, 1000); 43 | 44 | -- 创建订单表 45 | create table orders( 46 | id int primary key auto_increment, 47 | goods_id int not null, 48 | goods_number int default 1 49 | )charset utf8; 50 | ``` 51 | ![create-goods](https://github.com/guobinhit/mysql-tutorial/blob/master/images/trigger/create-goods.png) 52 | 53 | 接下来,执行如下 SQL 语句,创建触发器: 54 | 55 | ``` 56 | -- 创建触发器 57 | delimiter $$ -- 临时修改语句结束符 58 | create trigger after_order after insert on orders for each row 59 | begin -- 触发器内容开始 60 | -- 触发器内容主体,每行用分号结尾 61 | update goods set inventory = inventory - 1 where id = 1; 62 | end -- 触发器内容结束 63 | $$ -- 结束语句 64 | delimiter ; -- 恢复语句结束符 65 | ``` 66 | ![create-trigger](https://github.com/guobinhit/mysql-tutorial/blob/master/images/trigger/create-trigger.png) 67 | 68 | ### 查询触发器 69 | 70 | 查询所有触发器或模糊匹配, 71 | 72 | - **基本语法**:`show triggers + [like 'pattern'];` 73 | 74 | 执行如下 SQL 语句,进行测试: 75 | 76 | ``` 77 | -- 查询所有触发器,\G 表示旋转 78 | show triggers\G; 79 | ``` 80 | ![show-triggers](https://github.com/guobinhit/mysql-tutorial/blob/master/images/trigger/show-triggers.png) 81 | 82 | 当然,我们也可以查询创建触发器的语句 83 | 84 | - **基本语法**:`show create trigger + 触发器名称;` 85 | 86 | 执行如下 SQL 语句,进行测试: 87 | 88 | ``` 89 | -- 查询触发器创建语句,\G 表示旋转 90 | show create trigger after_order\G; 91 | ``` 92 | ![show-ceate-triggers](https://github.com/guobinhit/mysql-tutorial/blob/master/images/trigger/show-ceate-triggers.png) 93 | 94 | 此外,**所有的触发器都会被系统保持到`information_schema.triggers`这张表中**,执行如下 SQL,进行测试: 95 | ``` 96 | -- 查询触发器,\G 表示旋转 97 | select * from information_schema.triggers\G; 98 | ``` 99 | ![select-triggers](https://github.com/guobinhit/mysql-tutorial/blob/master/images/trigger/select-triggers.png) 100 | 101 | ### 使用触发器 102 | 103 | 实际上,触发器不是我们手动触发的,而是在某种情况发生的时候自动触发,例如我们上面创建的`after_order`触发器,当我们`insert`订单表的时候,该触发器自动执行。执行如下 SQL 语句,进行测试: 104 | 105 | ``` 106 | -- 查看商品表 107 | select * from goods; 108 | -- 查看订单表 109 | select * from orders; 110 | -- 插入订单表 111 | insert into orders values(null, 2, 10); 112 | -- 查看订单表 113 | select * from orders; 114 | -- 查看商品表 115 | select * from goods; 116 | ``` 117 | 118 | ![user-triggers](https://github.com/guobinhit/mysql-tutorial/blob/master/images/trigger/user-triggers.png) 119 | 120 | 观察上图,我们会发现:触发器确实生效了,在我们向`orders`表`insert`数据的时候,`goods`表发生了变化;但是其并没有如我们期望那样执行,就算我们将`goods_id`设置为`2`,`goods_number`设置为`10`,触发器操作的仍然是`goods`表中`id`为 `1`的记录且库存量只减`1`。且先不提这个问题,在创建触发器的时候,我们要特别注意:**触发器的触发对象和事件类型,决不能同触发器主体的内容相同,防止发生死循环**。 121 | 122 | ### 修改触发器 & 删除触发器 123 | 124 | **触发器不能修改,只能删除**。因此,当我们需要修改触发器的时候,唯一的方法就是:先删除,后新增。 125 | 126 | - **基本语法**:`drop trigger + 触发器名称;` 127 | 128 | 执行如下 SQL 语句,进行测试: 129 | 130 | ``` 131 | -- 删除触发器 132 | drop trigger after_order; 133 | -- 查询触发器 134 | show triggers; 135 | ``` 136 | 137 | ![drop-triggers](https://github.com/guobinhit/mysql-tutorial/blob/master/images/trigger/drop-triggers.png) 138 | 139 | ### 触发器记录 140 | 141 | 触发器记录:无论触发器是否触发,只要当某种操作准备执行,系统就会将当前操作的记录的当前状态和即将执行之后的状态分别记录下来,供触发器使用。其中,当前状态被保存到`old`中,操作之后的状态被保存到`new`中。至于`old`和`new`是什么鬼?不知道大家是否还记得查看表`information_schema.triggers`的时候,标红的两个字段: 142 | 143 | - `ACTION_REFERENCE_OLD_ROW:OLD` 144 | - `ACTION_REFERENCE_NEW_ROW:NEW` 145 | 146 | 其中, 147 | 148 | - `OLD`,代表是旧记录,也就是当前记录的状态,插入时没有`OLD`; 149 | - `NEW`,代表是新记录,也就是假设操作发生之后记录的状态,删除时没有`NEW`。 150 | 151 | 无论`OLD`还是 `NEW`,都代表记录本身,而且任何一条记录除了有数据,还有字段名。因此,使用`OLD`和 `NEW`的方法就是: 152 | 153 | - **基本语法**:`OLD/NEW + . + 字段名` 154 | 155 | 在这里,我们就能够通过触发器记录解决刚才`after_order`触发器的问题了。依次执行如下 SQL 语句,进行测试: 156 | 157 | ``` 158 | -- 创建新触发器 159 | delimiter $$ -- 临时修改语句结束符 160 | create trigger after_order_new after insert on orders for each row 161 | begin -- 触发器内容开始 162 | -- 触发器内容主体,每行用分号结尾 163 | update goods set inventory = inventory - NEW.goods_number where id = NEW.goods_id; 164 | end -- 触发器内容结束 165 | $$ -- 结束语句 166 | delimiter ; -- 恢复语句结束符 167 | 168 | -- 查看新触发器 169 | show triggers\G; 170 | ``` 171 | 172 | ![create-show-triggers](https://github.com/guobinhit/mysql-tutorial/blob/master/images/trigger/create-show-triggers.png) 173 | 174 | ``` 175 | -- 查看商品表 176 | select * from goods; 177 | -- 查看订单表 178 | select * from orders; 179 | -- 插入订单表 180 | insert into orders values(null, 2, 10); 181 | -- 查看订单表 182 | select * from orders; 183 | -- 查看商品表 184 | select * from goods; 185 | ``` 186 | 187 | ![select-goods](https://github.com/guobinhit/mysql-tutorial/blob/master/images/trigger/select-goods.png) 188 | 189 | 如上图所示,显然`after_order_new`触发器按我们预期那样正确的工作啦! 190 | 191 | ---------- 192 | 193 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 194 | 195 | 196 | ---------- 197 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 198 | -------------------------------------------------------------------------------- /articles/union.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二十二)「联合查询」 2 | 3 | **联合查询**:`union`,将多次查询(多条`select`语句)的结果,在字段数相同的情况下,在记录的层次上进行拼接。 4 | 5 | ## 基本语法 6 | 7 | 联合查询由多条`select`语句构成,每条`select`语句获取的字段数相同,但与字段类型无关。 8 | 9 | - **基本语法**:`select 语句1 + union + [union选项] + select 语句2 + ...;` 10 | - **union 选项**:与`select`选项一样有两种 11 | - `all`:无论重复与否,保留所有记录; 12 | - `distinct`:表示去重,为默认选项。 13 | 14 | 执行如下 SQL 语句,进行测试: 15 | 16 | ``` 17 | -- 联合查询,默认去重 18 | select * from class 19 | union distinct 20 | select * from class; 21 | 22 | -- 联合查询,保留所有记录 23 | select * from class 24 | union all 25 | select * from class; 26 | ``` 27 | 28 | ![select-union-class](https://github.com/guobinhit/mysql-tutorial/blob/master/images/union/select-union-class.png) 29 | 30 | 如上图所示,展示了联合查询的两种形式。特别地,联合查询只要求字段数相同,而跟类型无关。执行如下 SQL 语句,进行测试: 31 | 32 | ``` 33 | -- 联合查询,字段数相同,类型不同 34 | select id, grade, room from class 35 | union distinct 36 | select name, age, id from student; 37 | ``` 38 | 39 | ![select-union-distinct](https://github.com/guobinhit/mysql-tutorial/blob/master/images/union/select-union-distinct.png) 40 | 41 | 如上图所示,联合查询只保留了第一张表的字段,而不保留第二张表的字段。 42 | 43 | ## 意义 44 | 45 | 联合查询的意义有两种,分别为: 46 | 47 | - 查询同一张表,按时需要不同,例如查询学生信息,要求男生按年龄升序排序,女生按年龄降序排序; 48 | - 多表查询,多张表的结构是完全一样的,保持的数据结构也是一样的。 49 | 50 | 此外,如果数据量非常的大,就要进行分表(垂直分表和水平分表),而分表的依据无外乎数据多不多和常不常用。 51 | 52 | ## 排序 53 | 54 | 首先,让我们看看`student`表中的数据: 55 | 56 | ![select-student](https://github.com/guobinhit/mysql-tutorial/blob/master/images/union/select-student.png) 57 | 58 | 接下来,给出一个需求:**在`student`表中,让男生按年龄升序排序,让女生按年龄降序排序**。根据我们刚刚学到的联合查询,貌似很容易啊!执行如下 SQL 语句,进行测试: 59 | 60 | ``` 61 | -- 在 student 表中,按年龄,男升女降 62 | select * from student where gender = "boy" order by age asc 63 | union 64 | select * from student where gender = "girl" order by age desc; 65 | ``` 66 | 67 | ![select-union-error](https://github.com/guobinhit/mysql-tutorial/blob/master/images/union/select-union-error.png) 68 | 69 | 如上图所示,呃,好吧,貌似出错啦!这是因为要想在联合查询中使用`order by`,我们必须将`select`语句用括号括起来。执行如下 SQL 语句,进行测试: 70 | 71 | ``` 72 | -- 在 student 表中,按年龄,男升女降 73 | (select * from student where gender = "boy" order by age asc) 74 | union 75 | (select * from student where gender = "girl" order by age desc); 76 | ``` 77 | 78 | ![union-order](https://github.com/guobinhit/mysql-tutorial/blob/master/images/union/union-order.png) 79 | 80 | 如上图所示,啊,我们都已经将`select`语句用括号括起来了,但是男生和女生也没有按我们的目的实现啊!好吧,这是因为要想在联合查询中使`order by`生效,我们必须将其与`limit`搭配使用,而`limit`的限定数,我们设置为一个非常大的数即可。执行如下 SQL 语句,进行测试: 81 | 82 | ``` 83 | -- 在 student 表中,按年龄,男升女降 84 | (select * from student where gender = "boy" order by age asc limit 666) 85 | union 86 | (select * from student where gender = "girl" order by age desc limit 666); 87 | ``` 88 | 89 | ![union-order-2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/union/union-order-2.png) 90 | 91 | 如上图所示,显然,这次咱们的目的实现啦! 92 | 93 | ---------- 94 | 95 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 96 | 97 | 98 | ---------- 99 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 100 | -------------------------------------------------------------------------------- /articles/uniquekey.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十二)「列属性 之 唯一键」 2 | 3 | ## 唯一键 4 | 5 | 唯一键:每张表往往有多个字段需要具有唯一性,数据不能重复,但是在每张表中,只能有一个主键,因此**唯一键就是用来解决表中多个字段需要具有唯一性的问题**。 6 | 7 | 唯一键的本质与主键差不多,唯一键默认的允许字段为空,而且可以多个字段为空,因此空字段不参与唯一性的比较。 8 | 9 | ### 增加唯一键 10 | 11 | 增加唯一键的方法和主键类似,有 3 种方法,分别为: 12 | 13 | **第一种**:在创建表的时候,字段后面直接添加`unique`或者`unique key`关键字 14 | 15 | ``` 16 | -- 增加唯一键 17 | create table my_unique( 18 | number char(10) unique comment '学号', 19 | name varchar(20) not null 20 | )charset utf8; 21 | ``` 22 | ![create-table-myunique](https://github.com/guobinhit/mysql-tutorial/blob/master/images/uniquekey/create-table-myunique.png) 23 | 24 | **第 2 种**:在所有字段之后,增加`unique key(字段列表)`,可以设置复合唯一键 25 | 26 | ``` 27 | -- 测试唯一键 28 | create table my_unique2( 29 | number char(10) not null, 30 | name varchar(20) not null, 31 | unique key(number) 32 | )charset utf8; 33 | ``` 34 | ![create-table-myunique2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/uniquekey/create-table-myunique2.png) 35 | 36 | 观察上图,咱们可能会发现一个问题,那就是:**咱们设置的唯一键`UNI`,怎么变成了主键`PRI`啊?这是由于当唯一键满足非空条件的时候,其性质就和主键一样啦,因此在表中显示为`PRI`**. 当然,在咱们执行如下 SQL 语句的时候,其就会表现出真正的性质: 37 | 38 | ``` 39 | -- 查看表创建语句 40 | show create table my_unique2; 41 | ``` 42 | ![show-create-myunique2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/uniquekey/show-create-myunique2.png) 43 | 44 | **第 3 种**:在创建表之后,增加唯一键 45 | 46 | ``` 47 | -- 创建未设置唯一键的表 48 | create table my_unique3( 49 | id int primary key auto_increment, 50 | number char(10) not null, 51 | name varchar(20) not null 52 | )charset utf8; 53 | ``` 54 | 55 | ![create-table-myunique3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/uniquekey/create-table-myunique3.png) 56 | 57 | 如上图所示,表`my_unique3`未设置唯一键。接下来,执行如下 SQL 语句,进行测试: 58 | 59 | ``` 60 | -- 增加唯一键 61 | alter table my_unique3 add unique key(number); 62 | ``` 63 | ![alter-myunique3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/uniquekey/alter-myunique3.png) 64 | 65 | 如上图所示,咱们已经成功向表中增加唯一键啦! 66 | 67 | ### 唯一键约束 68 | 69 | 唯一键与主键本质相同,区别在于:**唯一键允许字段值为空,并且允许多个空值存在**。 70 | 71 | ``` 72 | -- 测试唯一键约束 73 | insert into my_unique values(null,'Charies'); 74 | insert into my_unique values(null,'Guo'); 75 | ``` 76 | ![insert-myunique](https://github.com/guobinhit/mysql-tutorial/blob/master/images/uniquekey/insert-myunique.png) 77 | 78 | ### 更新唯一键 & 删除唯一键 79 | 80 | 在表中,更新唯一键的时候,可以不用先删除唯一键,因为表的唯一键允许有多个。 81 | 82 | 删除唯一键的语法为: 83 | 84 | - 基本语法:`alter table + 表名 + drop index + 索引名字;` 85 | 86 | 在这里,唯一键默认使用字段名作为索引名。 87 | 88 | ``` 89 | -- 删除唯一键 90 | alter table my_unique3 drop index number; 91 | ``` 92 | ![desc-myunique3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/uniquekey/desc-myunique3.png) 93 | 94 | 如上图所示,显然咱们已经成功删除表中的唯一键啦! 95 | 96 | 97 | ---------- 98 | 99 | **温馨提示**:符号`+`表示连接的意思。 100 | 101 | ---------- 102 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 103 | -------------------------------------------------------------------------------- /articles/updata-and-delete.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十八)「数据的高级操作 之 更新 & 删除」 2 | 3 | ## 数据的高级操作 4 | 5 | ### 更新数据 6 | 7 | - **基本语法**: `update + 表名 + set + 字段 = 值 + [where 条件];` 8 | - **高级语法**: `update + 表名 + set + 字段 = 值 + [where 条件] + [limit 更新数量];` 9 | 10 | 执行如下 SQL 语句,进行测试: 11 | 12 | ``` 13 | -- 将表 my_copy 中的部分 a 更新为 c 14 | update my_copy set name = 'c' where name = 'a' limit 3; 15 | ``` 16 | 17 | 执行上述 SQL 语句前: 18 | 19 | ![select-mycopy](https://github.com/guobinhit/mysql-tutorial/blob/master/images/updata-and-delete/select-mycopy.png) 20 | 21 | 执行上述 SQL 语句后: 22 | 23 | ![update-mycopy](https://github.com/guobinhit/mysql-tutorial/blob/master/images/updata-and-delete/update-mycopy.png) 24 | 25 | 26 | ### 删除数据 27 | 28 | 与更新类似,可以通过`limit`来限制删除的数量。 29 | 30 | - **基本语法**: `delete + from + 表名 + [where 条件];` 31 | - **高级语法**: `delete + from + 表名 + [where 条件] + [limit 删除数量];` 32 | 33 | 执行如下 SQL 语句,进行测试: 34 | 35 | ``` 36 | -- 将表 my_copy 中的部分 b 删除 37 | delete from my_copy where name = 'b' limit 10; 38 | ``` 39 | 40 | ![delete-mycopy](https://github.com/guobinhit/mysql-tutorial/blob/master/images/updata-and-delete/delete-mycopy.png) 41 | 42 | 此外,在删除记录的过程中,**如果表中存在自增长的主键,那么删除之后,自增长不会还原**。执行如下 SQL 语句,进行测试: 43 | 44 | ``` 45 | -- 删除表 student 中的记录,查看自增长属性 46 | delete from student; 47 | show create table student; 48 | ``` 49 | 50 | ![delete-student](https://github.com/guobinhit/mysql-tutorial/blob/master/images/updata-and-delete/delete-student.png) 51 | 52 | 53 | 如上图所示,显然在咱们删除表`student`中的全部数据之后,`id`的自增长属性值`3`并没有发生改变,这是因为数据的删除是不会改变表结构的。如果想要还原自增长属性,思路是:**先删除表,然后重新建表**。 54 | 55 | - **基本语法**:`truncate + 表名;` 56 | 57 | 执行如下 SQL 语句,进行测试: 58 | 59 | ``` 60 | -- 先清空 student 表,再重新创建 student 表 61 | truncate student; 62 | ``` 63 | 64 | ![truncate-student](https://github.com/guobinhit/mysql-tutorial/blob/master/images/updata-and-delete/truncate-student.png) 65 | 66 | 如上图所示,显然咱们已经测试成功啦! 67 | 68 | 69 | ---------- 70 | 71 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 72 | 73 | 74 | ---------- 75 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 76 | -------------------------------------------------------------------------------- /articles/view-one.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二十四)「视图(上)」 2 | 3 | **视图**:`view`,是一种有结构(有行有列),但没有结果(结构中不真实存放数据)的虚拟表,虚拟表的结构来源不是自己定义的,而是从对应的基表(视图的数据来源)中产生的。 4 | 5 | 6 | ## 创建视图 7 | 8 | 首先,给出创建视图的基本语法, 9 | 10 | - **基本语法**:`create view + 视图名 + as + select语句;` 11 | 12 | 其中,`select`语句可以是普通查询,也可以是连接查询、联合查询、子查询等。 13 | 14 | 此外,视图根据数据的来源,可以分为单表视图和多表视图: 15 | 16 | - 单表视图:基表只有一个; 17 | - 多表视图:基表至少两个。 18 | 19 | 执行如下 SQL 语句,进行测试: 20 | 21 | ``` 22 | -- 单表视图 23 | create view my_v1 as select * from student; 24 | create view my_v2 as select * from class; 25 | 26 | -- 多表视图 27 | create view my_v3 as 28 | select * from student as s left join class c 29 | on s.c_id = c.id; 30 | ``` 31 | 32 | ![create-myv1v2v3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-one/create-myv1v2v3.png) 33 | 34 | 如上图所示,在我们创建多表视图的时候,由于表`student`和`class`中都含有`id`字段,因此导致出现错误“重复列名”。修改上述创建多表视图的 SQL 语句,继续进行测试: 35 | 36 | ``` 37 | -- 多表视图 38 | create view my_v3 as 39 | select s.*, c.grade, c.room from student as s left join class c 40 | on s.c_id = c.id; 41 | ``` 42 | 43 | ![create-myv3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-one/create-myv3.png) 44 | 45 | 如上图所示,当我们去掉表`class`中的`id`字段之后,成功创建多表视图。这是因为,当视图的基表有多张的时候,字段名不能重复。 46 | 47 | 48 | ## 查询视图 49 | 50 | 在这里,查询视图是指查看视图的结构,而不是查看视图的结果。 51 | 52 | 由于视图是一张虚拟表,因此表的所用查询语句,都适用于视图,例如: 53 | 54 | - `desc + 视图名;` 55 | - `show tables + 视图名;` 56 | - `show create table + 视图名;` 57 | 58 | 执行如下 SQL 语句,进行测试: 59 | 60 | ``` 61 | -- 查询视图 62 | desc my_v1; 63 | show create table my_v1; 64 | ``` 65 | 66 | ![desc-myv1](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-one/desc-myv1.png) 67 | 68 | 虽然视图是虚拟表,但它和真正的表,至少在关键字上还是有区别的,因此在查询视图创建语句的时候,可以使用如下 SQL 语句: 69 | 70 | ``` 71 | -- 查询视图创建语句 72 | show create view my_v1; 73 | ``` 74 | 75 | ![show-create-myv1](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-one/show-create-myv1.png) 76 | 77 | 此外,视图一旦创建,系统就会在视图对应的数据库文件夹下创建一个对应的`frm`结构文件,以保证结构的完整性。 78 | 79 | 80 | 81 | ## 使用视图 82 | 83 | 在操作数据库表的过程中,使用视图,主要就是为了查询,因此将视图当做表一样查询即可。 84 | 85 | 在这里需要注意的是,虽然我们说视图是一个虚拟表,它不保存数据,但是它却可以获取数据。 86 | 87 | 执行如下 SQL 语句,进行测试: 88 | 89 | ``` 90 | -- 使用视图 91 | select * from my_v1; 92 | select * from my_v2; 93 | select * from my_v3; 94 | ``` 95 | 96 | ![select-myv1v2v3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-one/select-myv1v2v3.png) 97 | 98 | 如上图所示,我们查询视图的结果和查询创建视图时`as`后面连接的`select`语句的结果完全相同。 99 | 100 | 因此,我们也可以认为:**创建视图,就是给一条`select`语句起别名,或者说是封装`select`语句**。 101 | 102 | ## 修改视图 103 | 104 | 视图本身不可修改,但是视图的来源(`select`)语句是可以修改的。因此,修改视图,就是修改视图的来源(`select`)语句。 105 | 106 | - **基本语法**:`alter view + 视图名 + as + 新的select语句;` 107 | 108 | 执行如下 SQL 语句,进行测试: 109 | 110 | ``` 111 | -- 修改视图 112 | alter view my_v1 as 113 | select id, name, gender, age, c_id from student; 114 | ``` 115 | 116 | ![alter-myv1](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-one/alter-myv1.png) 117 | 118 | ## 删除视图 119 | 120 | 与视图的其他操作相比,删除视图比较简单, 121 | 122 | - **基本语法**:`drop view + 视图名;` 123 | 124 | 执行如下 SQL 语句,进行测试: 125 | 126 | ``` 127 | -- 删除视图 128 | drop table my_v4; 129 | 130 | -- 删除视图 131 | drop view my_v4; 132 | ``` 133 | 134 | ![drop-myv4](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-one/drop-myv4.png) 135 | 136 | 如上图所示,我们不能用 137 | 138 | - `drop table + 视图名;` 139 | 140 | 来删除视图,因为`table`包含真实的数据,而`view`说到底就是封装的`select`语句,并不包含真实的数据。虽然删除视图并不会影响数据,但在实际工作中,建议还是不要乱删别人建立的视图,因为视图封装的`select`语句很有可能包含复杂的业务逻辑。 141 | 142 | ## 视图意义 143 | 144 | - 视图可以节省 SQL 语句,将一条复杂的查询语句用视图来进行封装,以后可以直接对视图进行操作; 145 | - 数据安全,视图操作主要是针对查询的,如果对视图结构进行处理,例如删除,并不会影响基表的数据; 146 | - 视图往往在大型项目中使用,而且是多系统使用,可以对外提供有用的数据,但是隐藏关键(或无用)的数据; 147 | - 视图是对外提供友好型的,不同的视图提供不同的数据,就如专门对外设计的一样; 148 | - 视图可以更好(或者说,容易)的进行权限控制。 149 | 150 | 151 | ---------- 152 | 153 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 154 | 155 | 156 | ---------- 157 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 158 | -------------------------------------------------------------------------------- /articles/view-two.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(二十五)「视图(下)」 2 | 3 | **视图数据操作**:虽然我们说视图可以称之为`select`语句的别名,但实际上,它和别名并不一样,因为视图是可以进行数据写操作的,只不过有很多限制而已。 4 | 5 | ## 新增数据 6 | 7 | 在这里,新增数据就是指通过视图直接对基表进行数据的新增操作。 8 | 9 | - **限制 1**:多表视图不能进行新增数据。 10 | 11 | 执行如下 SQL 语句,进行测试: 12 | 13 | ``` 14 | -- 查询视图 my_v3 结构 15 | desc my_v3; 16 | 17 | -- 多表视图新增数据 18 | insert into my_v3 values(7,'Gates','boy',2,170,'PM3.5','A315'); 19 | ``` 20 | 21 | ![desc-myv3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-two/desc-myv3.png) 22 | 23 | - **限制 2**:可以向单表视图新增数据,但视图中包含的字段必须有基表中所有不能为空的字段。 24 | 25 | 执行如下 SQL 语句,进行测试: 26 | 27 | ``` 28 | -- 查询 student 表结构 29 | desc student; 30 | 31 | -- 创建视图 my_v4 32 | create view my_v4 as 33 | select id,name,age,c_id from student; 34 | 35 | -- 单表视图新增数据 36 | insert into my_v4 values(7,'Gates',25,2); 37 | ``` 38 | 39 | ![desc-student](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-two/desc-student.png) 40 | 41 | 如上图所示,在我们新建的视图`my_v4`中,没有包含不能为空的字段`gender`,因此在我们向`my_v4`中新增数据的时候,报错。其实,这也很好理解,试想,在 MySQL 尝试将视图中新增的数据(一条记录)插入到基表的时候,忽然发现一个本不能为`null`的字段的值为默认值`null`,自然就会报错啦!反之,如果单表视图中包含了基表中的全部非空字段,自然可以插入成功。执行如下 SQL 语句,进行测试: 42 | 43 | ``` 44 | -- 查询 class 表数据 45 | select * from class; 46 | 47 | -- 创建视图 my_v5 48 | create view my_v5 as 49 | select * from class; 50 | 51 | -- 单表视图新增数据 52 | insert into my_v5 values(2,'PM2016','A315'); 53 | 54 | -- 查询 class 表数据 55 | select * from class; 56 | ``` 57 | 58 | ![create-myv5](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-two/create-myv5.png) 59 | 60 | 如上图所示,显然我们通过单表视图向基表中插入数据成功啦! 61 | 62 | 63 | ## 删除数据 64 | 65 | 与新增数据类似, 66 | 67 | - 多表视图不能删除数据; 68 | - 单表视图可以删除数据。 69 | 70 | 执行如下 SQL 语句,进行测试: 71 | 72 | ``` 73 | -- 查询多表视图 my_v3 74 | select * from my_v3; 75 | 76 | -- 删除多表视图 my_v3 中记录 77 | delete from my_v3 where id = 2; 78 | 79 | -- 查询单表视图 my_v5 80 | select * from my_v5; 81 | 82 | -- 删除单表视图 my_v5 中记录 83 | delete from my_v5 where id = 2; 84 | 85 | -- 查询单表视图 my_v5 86 | select * from my_v5; 87 | ``` 88 | 89 | ![delete-myv3](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-two/delete-myv3.png) 90 | 91 | ## 更新数据 92 | 93 | 理论上,无论多表视图还是单表视图,都可以进行数据的更新。 94 | 95 | 执行如下 SQL 语句,进行测试: 96 | 97 | ``` 98 | -- 查询单表视图 my_v5 99 | select * from my_v5; 100 | 101 | -- 更新单表视图 my_v5 102 | update my_v5 set grade = 'PM2014' where id = 5; 103 | 104 | -- 查询单表视图 my_v5 105 | select * from my_v5;-- 查询单表视图 my_v5 106 | select * from my_v5; 107 | 108 | -- 更新单表视图 my_v5 109 | update my_v5 set grade = 'PM2014' where id = 5; 110 | 111 | -- 查询单表视图 my_v5 112 | select * from my_v5; 113 | ``` 114 | 115 | ![update-myv5](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-two/update-myv5.png) 116 | 117 | 此外,更新视图数据并不总是成功的,这是因为有**更新限制**的存在。那么何为更新限制呢? 118 | 119 | - 更新限制:`with check option`,如果创建视图的时候,设置了某个字段的限制,那么对视图进行更新操作的时候,系统就会进行验证,要保证更新之后,数据依然可以被查出来,否则不让更新。 120 | 121 | 执行如下 SQL 语句,进行测试: 122 | 123 | ``` 124 | -- 创建单表视图 my_v6 125 | create view my_v6 as 126 | select * from student where height > 170 with check option; 127 | 128 | -- 查询单表视图 my_v6 129 | select * from my_v6; 130 | 131 | -- 更新单表视图 my_v6 132 | update my_v6 set height = 165 where id = 6; 133 | ``` 134 | 135 | ![create-myv6](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-two/create-myv6.png) 136 | 137 | 138 | 如上图所示,在更新视图的时候,更新失败,这是因为其违反了我们设置的更新限制。那么,视图之外的数据,我们能不能修改呢?执行如下 SQL 语句,进行测试: 139 | 140 | ``` 141 | -- 查询单表视图 my_v6 142 | select * from my_v6; 143 | 144 | -- 更新单表视图 my_v6 145 | update my_v6 set height = 188 where id = 4; 146 | 147 | -- 查询单表视图 my_v6 148 | select * from my_v6; 149 | ``` 150 | 151 | ![select-myv6](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-two/select-myv6.png) 152 | 153 | 如上图所示,更新视图`my_v6`之外数据的时候,显示成功。但是,待我们重新查询视图`my_v6`数据的时候,发现并没有真正更新成功。这是为什么呢?原因就在于我们不能通过视图去操作视图之外的数据。举一个不太恰当的例子,我们不能用自己手去操作别人兜里的钱啊! 154 | 155 | 156 | ## 视图算法 157 | 158 | 视图算法,即系统对视图以及外部查询视图的`select`语句的一种解析方式。视图算法有三种,分别为: 159 | 160 | - `undefined`:未定义(默认的),这不是一种实际使用的算法,而是一个“推卸责任”的算法。在未定义的情况下,告诉系统,视图没有定义算法,请自己选择。 161 | - `temptable`:临时表算法,系统先执行视图的`select`语句,后执行外部查询语句。 162 | - `merge`:合并算法,系统先将视图对应的`select`语句与外部查询视图的`select`语句进行合并,然后再执行。此算法比较高效,且在未定义算法的时候,经常会默认选择此算法。 163 | 164 | 对于视图的算法,我们需要在创建视图的时候指定, 165 | 166 | - **基本语法**:`create + [algorithm = temptable/merge/undefined] + view + 视图名 + as + select语句;` 167 | 168 | 执行如下 SQL 语句,进行测试: 169 | 170 | ``` 171 | -- 查看视图 my_v2 的默认算法 172 | show create view my_v2; 173 | 174 | -- 指定视图 my_v7 算法为 temptable 175 | create algorithm = temptable view my_v7 as 176 | select * from student; 177 | 178 | -- 查看视图 my_v7 的指定算法 179 | show create view my_v7; 180 | ``` 181 | 182 | ![show-myv2](https://github.com/guobinhit/mysql-tutorial/blob/master/images/view-two/show-myv2.png) 183 | 184 | 如上图所示,我们指定了视图`my_v7`的算法为`temptable`,但是对于算法的选择,我们该如何判断呢?答案是:如果视图的`select`语句中包含一个查询子句(五子句,包括`where`、`group by`、`order by` 、`having`和`limit`),而且很有可能查询子句的顺序比外部的查询语句的顺序要靠后(五子句的顺序),那么一定要使用`temptable`算法,其他情况可以不用指定,默认即可。 185 | 186 | 至此,我们已经将视图的内容大致讲完了。有一点需要我们特别注意,那就是:**视图最重要的功能就是查询,其他如增、删、改的操作一般不会使用,也不建议通过视图来操作基表的数据**。 187 | 188 | 189 | ---------- 190 | 191 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 192 | 193 | 194 | ---------- 195 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 196 | -------------------------------------------------------------------------------- /articles/worm-copy.md: -------------------------------------------------------------------------------- 1 | # 史上最简单的 MySQL 教程(十七)「数据的高级操作 之 蠕虫复制」 2 | 3 | ## 数据的高级操作 4 | 5 | ### 蠕虫复制 6 | 7 | 蠕虫复制:从已有的数据表中获取数据,然后将数据进行新增操作,数据成倍(以指数形式)的增加。 8 | 9 | **根据已有表创建新表,即复制表结构**,其基本语法为: 10 | 11 | - `create table + 表名 + like + [数据库名.]表名;` 12 | 13 | 执行如下 SQL 语句,进行测试: 14 | 15 | ``` 16 | -- 根据已有表,创建新表,当两张表位于同一数据库时,可以省略数据库名称 17 | create table my_copy like my_gbk; 18 | ``` 19 | 20 | ![desc-mygbk](https://github.com/guobinhit/mysql-tutorial/blob/master/images/worm-copy/desc-mygbk.png) 21 | 22 | 如上图所示,表`my_copy`和表`my_gbk`的表结构完成相同。 23 | 24 | 蠕虫复制的步骤为:先查出数据,然后将查出的数据新增一遍。 25 | 26 | - **基本语法**:`insert into + 表名 + [()] + select + 字段列表/* + from + 表名;` 27 | 28 | 执行如上 SQL 语句,进行测试: 29 | 30 | ``` 31 | -- 蠕虫复制 32 | insert into my_copy select * from my_collate_bin; 33 | ``` 34 | 35 | ![select-mycollate](https://github.com/guobinhit/mysql-tutorial/blob/master/images/worm-copy/select-mycollate.png) 36 | 37 | 如上图所示,咱们已经成功将表`my_collate_bin`中的数据复制到表`my_copy`中啦!接下来,咱们再执行如下 SQL 语句,测试蠕虫复制的效果: 38 | 39 | ``` 40 | -- 蠕虫复制 41 | insert into my_copy select * from my_copy; 42 | ``` 43 | 44 | ![insert-mycopy](https://github.com/guobinhit/mysql-tutorial/blob/master/images/worm-copy/insert-mycopy.png) 45 | 46 | 如上图所示,通过观察每次执行 SQL 语句后影响的列数,分别为`4`、`8`和`16`等,咱们会发现蠕虫复制的效果呈(指数)爆炸性增长。 47 | 48 | **蠕虫复制的意义**: 49 | 50 | 1. 从已有的数据表中拷贝数据到新的数据表; 51 | 2. 可以迅速的让表中的数据膨胀到一定的数量级,多用于测试表的压力及效率。 52 | 53 | ---------- 54 | 55 | **温馨提示**:符号`[]`括起来的内容,表示可选项;符号`+`,则表示连接的意思。 56 | 57 | 58 | ---------- 59 | ———— ☆☆☆ —— [返回 -> 史上最简单的 MySQL 教程 <- 目录](https://github.com/guobinhit/mysql-tutorial/blob/master/README.md) —— ☆☆☆ ———— 60 | -------------------------------------------------------------------------------- /images/backup/class-sql-location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/class-sql-location.png -------------------------------------------------------------------------------- /images/backup/class-sql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/class-sql.png -------------------------------------------------------------------------------- /images/backup/class-txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/class-txt.png -------------------------------------------------------------------------------- /images/backup/create-myisam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/create-myisam.png -------------------------------------------------------------------------------- /images/backup/data-location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/data-location.png -------------------------------------------------------------------------------- /images/backup/data-myclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/data-myclass.png -------------------------------------------------------------------------------- /images/backup/delete-class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/delete-class.png -------------------------------------------------------------------------------- /images/backup/into-outfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/into-outfile.png -------------------------------------------------------------------------------- /images/backup/login-mysql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/login-mysql.png -------------------------------------------------------------------------------- /images/backup/more-steps-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/more-steps-2.png -------------------------------------------------------------------------------- /images/backup/more-steps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/more-steps.png -------------------------------------------------------------------------------- /images/backup/my_myisam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/my_myisam.png -------------------------------------------------------------------------------- /images/backup/outfile-class2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/outfile-class2.png -------------------------------------------------------------------------------- /images/backup/pointed-single-table-backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/pointed-single-table-backup.png -------------------------------------------------------------------------------- /images/backup/show-tables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/show-tables.png -------------------------------------------------------------------------------- /images/backup/test-back-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/test-back-2.png -------------------------------------------------------------------------------- /images/backup/test-backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/test-backup.png -------------------------------------------------------------------------------- /images/backup/use-testoo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/backup/use-testoo.png -------------------------------------------------------------------------------- /images/chinese-data/mysql-command-line-client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/chinese-data/mysql-command-line-client.png -------------------------------------------------------------------------------- /images/chinese-data/select-from-student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/chinese-data/select-from-student.png -------------------------------------------------------------------------------- /images/chinese-data/show-character-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/chinese-data/show-character-set.png -------------------------------------------------------------------------------- /images/chinese-data/show-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/chinese-data/show-variables.png -------------------------------------------------------------------------------- /images/code-execution-structure/insert-orders-loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/code-execution-structure/insert-orders-loop.png -------------------------------------------------------------------------------- /images/code-execution-structure/insert-orders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/code-execution-structure/insert-orders.png -------------------------------------------------------------------------------- /images/code-execution-structure/select-goods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/code-execution-structure/select-goods.png -------------------------------------------------------------------------------- /images/collate/create-collate-bin-ci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/collate/create-collate-bin-ci.png -------------------------------------------------------------------------------- /images/collate/order-show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/collate/order-show.png -------------------------------------------------------------------------------- /images/collate/select-collate-bin-ci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/collate/select-collate-bin-ci.png -------------------------------------------------------------------------------- /images/collate/show-collation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/collate/show-collation.png -------------------------------------------------------------------------------- /images/column-null-comment-default/create-table-myclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-null-comment-default/create-table-myclass.png -------------------------------------------------------------------------------- /images/column-null-comment-default/create-table-mydefault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-null-comment-default/create-table-mydefault.png -------------------------------------------------------------------------------- /images/column-null-comment-default/create-table-myfriend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-null-comment-default/create-table-myfriend.png -------------------------------------------------------------------------------- /images/column-null-comment-default/insert-mydefault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-null-comment-default/insert-mydefault.png -------------------------------------------------------------------------------- /images/column-type/alter-myint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/alter-myint.png -------------------------------------------------------------------------------- /images/column-type/column-type-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/column-type-info.png -------------------------------------------------------------------------------- /images/column-type/create-table-mydate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/create-table-mydate.png -------------------------------------------------------------------------------- /images/column-type/create-table-mydecimal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/create-table-mydecimal.png -------------------------------------------------------------------------------- /images/column-type/create-table-myenum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/create-table-myenum.png -------------------------------------------------------------------------------- /images/column-type/create-table-myfloat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/create-table-myfloat.png -------------------------------------------------------------------------------- /images/column-type/create-table-myint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/create-table-myint.png -------------------------------------------------------------------------------- /images/column-type/create-table-myset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/create-table-myset.png -------------------------------------------------------------------------------- /images/column-type/field-type-null-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/field-type-null-key.png -------------------------------------------------------------------------------- /images/column-type/insert-myenum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/insert-myenum.png -------------------------------------------------------------------------------- /images/column-type/insert-myint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/insert-myint.png -------------------------------------------------------------------------------- /images/column-type/insert-myset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/insert-myset.png -------------------------------------------------------------------------------- /images/column-type/insert-select-myset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/insert-select-myset.png -------------------------------------------------------------------------------- /images/column-type/null-myint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/null-myint.png -------------------------------------------------------------------------------- /images/column-type/select-myenum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/select-myenum.png -------------------------------------------------------------------------------- /images/column-type/select-myset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/select-myset.png -------------------------------------------------------------------------------- /images/column-type/two-null-myint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/two-null-myint.png -------------------------------------------------------------------------------- /images/column-type/update-mydate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/update-mydate.png -------------------------------------------------------------------------------- /images/column-type/zerofill-myint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/column-type/zerofill-myint.png -------------------------------------------------------------------------------- /images/database-variable/select-system-var.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/database-variable/select-system-var.png -------------------------------------------------------------------------------- /images/database-variable/select-var-student-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/database-variable/select-var-student-2.png -------------------------------------------------------------------------------- /images/database-variable/select-var-student-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/database-variable/select-var-student-3.png -------------------------------------------------------------------------------- /images/database-variable/select-var-student-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/database-variable/select-var-student-4.png -------------------------------------------------------------------------------- /images/database-variable/select-var-student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/database-variable/select-var-student.png -------------------------------------------------------------------------------- /images/database-variable/set-global-var.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/database-variable/set-global-var.png -------------------------------------------------------------------------------- /images/database-variable/set-section-var.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/database-variable/set-section-var.png -------------------------------------------------------------------------------- /images/database-variable/set-varself.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/database-variable/set-varself.png -------------------------------------------------------------------------------- /images/database-variable/show-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/database-variable/show-variables.png -------------------------------------------------------------------------------- /images/datafile/show-global-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/datafile/show-global-variables.png -------------------------------------------------------------------------------- /images/duplicate-primary-key/desc-myclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/duplicate-primary-key/desc-myclass.png -------------------------------------------------------------------------------- /images/duplicate-primary-key/insert-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/duplicate-primary-key/insert-error.png -------------------------------------------------------------------------------- /images/duplicate-primary-key/insert-myclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/duplicate-primary-key/insert-myclass.png -------------------------------------------------------------------------------- /images/duplicate-primary-key/replace-myclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/duplicate-primary-key/replace-myclass.png -------------------------------------------------------------------------------- /images/duplicate-primary-key/select-myclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/duplicate-primary-key/select-myclass.png -------------------------------------------------------------------------------- /images/foreign-key/create-myforeign2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/create-myforeign2.png -------------------------------------------------------------------------------- /images/foreign-key/create-myforeign3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/create-myforeign3.png -------------------------------------------------------------------------------- /images/foreign-key/create-myforeignal1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/create-myforeignal1.png -------------------------------------------------------------------------------- /images/foreign-key/desc-myforeign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/desc-myforeign.png -------------------------------------------------------------------------------- /images/foreign-key/insert-alter-show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/insert-alter-show.png -------------------------------------------------------------------------------- /images/foreign-key/insert-myforeign3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/insert-myforeign3.png -------------------------------------------------------------------------------- /images/foreign-key/select-class-myforeign2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/select-class-myforeign2.png -------------------------------------------------------------------------------- /images/foreign-key/select-insert-class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/select-insert-class.png -------------------------------------------------------------------------------- /images/foreign-key/select-myforeign3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/select-myforeign3-2.png -------------------------------------------------------------------------------- /images/foreign-key/select-myforeign3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/select-myforeign3.png -------------------------------------------------------------------------------- /images/foreign-key/update-class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/foreign-key/update-class.png -------------------------------------------------------------------------------- /images/function/create-addall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/create-addall.png -------------------------------------------------------------------------------- /images/function/create-addall2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/create-addall2.png -------------------------------------------------------------------------------- /images/function/create-show-love.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/create-show-love.png -------------------------------------------------------------------------------- /images/function/drop-function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/drop-function.png -------------------------------------------------------------------------------- /images/function/select-addall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/select-addall.png -------------------------------------------------------------------------------- /images/function/select-addall2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/select-addall2.png -------------------------------------------------------------------------------- /images/function/select-char-length.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/select-char-length.png -------------------------------------------------------------------------------- /images/function/select-insert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/select-insert.png -------------------------------------------------------------------------------- /images/function/select-instr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/select-instr.png -------------------------------------------------------------------------------- /images/function/select-lpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/select-lpad.png -------------------------------------------------------------------------------- /images/function/select-strcmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/select-strcmp.png -------------------------------------------------------------------------------- /images/function/select-substring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/select-substring.png -------------------------------------------------------------------------------- /images/function/set-aite-cn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/set-aite-cn.png -------------------------------------------------------------------------------- /images/function/show-create-function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/show-create-function.png -------------------------------------------------------------------------------- /images/function/show-function-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/function/show-function-status.png -------------------------------------------------------------------------------- /images/increment/alter-modify-myauto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/alter-modify-myauto.png -------------------------------------------------------------------------------- /images/increment/alter-myauot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/alter-myauot-2.png -------------------------------------------------------------------------------- /images/increment/alter-myauto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/alter-myauto.png -------------------------------------------------------------------------------- /images/increment/create-table-myauto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/create-table-myauto.png -------------------------------------------------------------------------------- /images/increment/insert-myauto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/insert-myauto.png -------------------------------------------------------------------------------- /images/increment/modify-myauto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/modify-myauto.png -------------------------------------------------------------------------------- /images/increment/select-myauto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/select-myauto.png -------------------------------------------------------------------------------- /images/increment/set-auto-increment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/set-auto-increment.png -------------------------------------------------------------------------------- /images/increment/show-myauto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/show-myauto.png -------------------------------------------------------------------------------- /images/increment/show-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/increment/show-variables.png -------------------------------------------------------------------------------- /images/install-mysql/accounts-and-roles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/accounts-and-roles.png -------------------------------------------------------------------------------- /images/install-mysql/apply-server-configuration-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/apply-server-configuration-2.png -------------------------------------------------------------------------------- /images/install-mysql/apply-server-configuration-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/apply-server-configuration-3.png -------------------------------------------------------------------------------- /images/install-mysql/apply-server-configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/apply-server-configuration.png -------------------------------------------------------------------------------- /images/install-mysql/choosing-a-setup-tyep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/choosing-a-setup-tyep.png -------------------------------------------------------------------------------- /images/install-mysql/installation-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/installation-2.png -------------------------------------------------------------------------------- /images/install-mysql/installation-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/installation-3.png -------------------------------------------------------------------------------- /images/install-mysql/installation-complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/installation-complete.png -------------------------------------------------------------------------------- /images/install-mysql/installation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/installation.png -------------------------------------------------------------------------------- /images/install-mysql/mysql-client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/mysql-client.png -------------------------------------------------------------------------------- /images/install-mysql/plugins-and-extensions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/plugins-and-extensions.png -------------------------------------------------------------------------------- /images/install-mysql/product-configuration-next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/product-configuration-next.png -------------------------------------------------------------------------------- /images/install-mysql/product-configuration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/product-configuration.png -------------------------------------------------------------------------------- /images/install-mysql/type-and-networing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/type-and-networing.png -------------------------------------------------------------------------------- /images/install-mysql/windows-service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/install-mysql/windows-service.png -------------------------------------------------------------------------------- /images/join-query/innerjoin-crossjoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/join-query/innerjoin-crossjoin.png -------------------------------------------------------------------------------- /images/join-query/left-right-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/join-query/left-right-join.png -------------------------------------------------------------------------------- /images/join-query/leftjoin-like-naturaljoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/join-query/leftjoin-like-naturaljoin.png -------------------------------------------------------------------------------- /images/join-query/natural-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/join-query/natural-join.png -------------------------------------------------------------------------------- /images/join-query/natural-left-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/join-query/natural-left-join.png -------------------------------------------------------------------------------- /images/join-query/on-where-join.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/join-query/on-where-join.png -------------------------------------------------------------------------------- /images/join-query/select-student-crossjoin-class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/join-query/select-student-crossjoin-class.png -------------------------------------------------------------------------------- /images/join-query/select-student-innerjoin-class-alias.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/join-query/select-student-innerjoin-class-alias.png -------------------------------------------------------------------------------- /images/join-query/select-student-innerjoin-class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/join-query/select-student-innerjoin-class.png -------------------------------------------------------------------------------- /images/primarykey/alter-mypri3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/primarykey/alter-mypri3.png -------------------------------------------------------------------------------- /images/primarykey/create-table-mypri1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/primarykey/create-table-mypri1.png -------------------------------------------------------------------------------- /images/primarykey/create-table-mypri2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/primarykey/create-table-mypri2.png -------------------------------------------------------------------------------- /images/primarykey/create-table-mypri3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/primarykey/create-table-mypri3.png -------------------------------------------------------------------------------- /images/primarykey/desc-mypri3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/primarykey/desc-mypri3.png -------------------------------------------------------------------------------- /images/primarykey/insert-mypri3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/primarykey/insert-mypri3.png -------------------------------------------------------------------------------- /images/procedure/call-pro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/procedure/call-pro.png -------------------------------------------------------------------------------- /images/procedure/call-pro3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/procedure/call-pro3.png -------------------------------------------------------------------------------- /images/procedure/create-pro2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/procedure/create-pro2.png -------------------------------------------------------------------------------- /images/procedure/create-pro3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/procedure/create-pro3.png -------------------------------------------------------------------------------- /images/procedure/create-procedure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/procedure/create-procedure.png -------------------------------------------------------------------------------- /images/procedure/drop-procedure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/procedure/drop-procedure.png -------------------------------------------------------------------------------- /images/procedure/set-aite-var.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/procedure/set-aite-var.png -------------------------------------------------------------------------------- /images/procedure/show-create-procedure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/procedure/show-create-procedure.png -------------------------------------------------------------------------------- /images/procedure/show-procedure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/procedure/show-procedure.png -------------------------------------------------------------------------------- /images/record-length/create-table-myutf8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/record-length/create-table-myutf8.png -------------------------------------------------------------------------------- /images/record-length/myutf8-mygbk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/record-length/myutf8-mygbk.png -------------------------------------------------------------------------------- /images/record-length/myutf81-mygbk1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/record-length/myutf81-mygbk1.png -------------------------------------------------------------------------------- /images/record-length/myutf82-mygbk2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/record-length/myutf82-mygbk2.png -------------------------------------------------------------------------------- /images/record-length/utf8-gbk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/record-length/utf8-gbk.png -------------------------------------------------------------------------------- /images/relation/table-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/relation/table-1.png -------------------------------------------------------------------------------- /images/relation/table-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/relation/table-2.png -------------------------------------------------------------------------------- /images/relation/table-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/relation/table-3.png -------------------------------------------------------------------------------- /images/relation/table-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/relation/table-4.png -------------------------------------------------------------------------------- /images/relation/table-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/relation/table-5.png -------------------------------------------------------------------------------- /images/relation/table-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/relation/table-6.png -------------------------------------------------------------------------------- /images/relation/table-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/relation/table-7.png -------------------------------------------------------------------------------- /images/relation/table-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/relation/table-8.png -------------------------------------------------------------------------------- /images/resovle-method/computer-management.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/resovle-method/computer-management.png -------------------------------------------------------------------------------- /images/resovle-method/start-server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/resovle-method/start-server.png -------------------------------------------------------------------------------- /images/resovle-method/test-mysql-client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/resovle-method/test-mysql-client.png -------------------------------------------------------------------------------- /images/secure/my-ini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/secure/my-ini.png -------------------------------------------------------------------------------- /images/secure/show-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/secure/show-variables.png -------------------------------------------------------------------------------- /images/select/select-between.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-between.png -------------------------------------------------------------------------------- /images/select/select-by-grade-sex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-by-grade-sex.png -------------------------------------------------------------------------------- /images/select/select-count-max-min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-count-max-min.png -------------------------------------------------------------------------------- /images/select/select-group-by-sex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-group-by-sex.png -------------------------------------------------------------------------------- /images/select/select-group-bysex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-group-bysex.png -------------------------------------------------------------------------------- /images/select/select-having-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-having-2.png -------------------------------------------------------------------------------- /images/select/select-having.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-having.png -------------------------------------------------------------------------------- /images/select/select-limit-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-limit-2.png -------------------------------------------------------------------------------- /images/select/select-limit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-limit.png -------------------------------------------------------------------------------- /images/select/select-mycopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-mycopy.png -------------------------------------------------------------------------------- /images/select/select-or.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-or.png -------------------------------------------------------------------------------- /images/select/select-order-by-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-order-by-2.png -------------------------------------------------------------------------------- /images/select/select-order-by.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-order-by.png -------------------------------------------------------------------------------- /images/select/select-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-set.png -------------------------------------------------------------------------------- /images/select/select-sex-count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-sex-count.png -------------------------------------------------------------------------------- /images/select/select-student-myclass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-student-myclass.png -------------------------------------------------------------------------------- /images/select/select-student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-student.png -------------------------------------------------------------------------------- /images/select/select-union-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-union-select.png -------------------------------------------------------------------------------- /images/select/select-with-rollup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/select-with-rollup.png -------------------------------------------------------------------------------- /images/select/use-alias.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/select/use-alias.png -------------------------------------------------------------------------------- /images/sql-operation/set-name-gbk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sql-operation/set-name-gbk.png -------------------------------------------------------------------------------- /images/sub-query/across-sub-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sub-query/across-sub-query.png -------------------------------------------------------------------------------- /images/sub-query/column-any-some-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sub-query/column-any-some-all.png -------------------------------------------------------------------------------- /images/sub-query/column-non-any-some-all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sub-query/column-non-any-some-all.png -------------------------------------------------------------------------------- /images/sub-query/column-row-element.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sub-query/column-row-element.png -------------------------------------------------------------------------------- /images/sub-query/column-sub-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sub-query/column-sub-query.png -------------------------------------------------------------------------------- /images/sub-query/exists-sub-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sub-query/exists-sub-query.png -------------------------------------------------------------------------------- /images/sub-query/select-class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sub-query/select-class.png -------------------------------------------------------------------------------- /images/sub-query/select-student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sub-query/select-student.png -------------------------------------------------------------------------------- /images/sub-query/table-sub-query.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/sub-query/table-sub-query.png -------------------------------------------------------------------------------- /images/thing-one/compare-bankaccount-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-one/compare-bankaccount-2.png -------------------------------------------------------------------------------- /images/thing-one/compare-bankaccount-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-one/compare-bankaccount-3.png -------------------------------------------------------------------------------- /images/thing-one/compare-bankaccount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-one/compare-bankaccount.png -------------------------------------------------------------------------------- /images/thing-one/create-bankaccount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-one/create-bankaccount.png -------------------------------------------------------------------------------- /images/thing-one/start-transaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-one/start-transaction.png -------------------------------------------------------------------------------- /images/thing-one/update-bankaccount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-one/update-bankaccount.png -------------------------------------------------------------------------------- /images/thing-two/commit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-two/commit.png -------------------------------------------------------------------------------- /images/thing-two/compare-bankaccount-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-two/compare-bankaccount-2.png -------------------------------------------------------------------------------- /images/thing-two/compare-bankaccount-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-two/compare-bankaccount-3.png -------------------------------------------------------------------------------- /images/thing-two/compare-bankaccount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-two/compare-bankaccount.png -------------------------------------------------------------------------------- /images/thing-two/rollback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-two/rollback.png -------------------------------------------------------------------------------- /images/thing-two/set-autocommit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-two/set-autocommit.png -------------------------------------------------------------------------------- /images/thing-two/show-variables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-two/show-variables.png -------------------------------------------------------------------------------- /images/thing-two/test-savepoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/thing-two/test-savepoint.png -------------------------------------------------------------------------------- /images/trigger/create-goods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/trigger/create-goods.png -------------------------------------------------------------------------------- /images/trigger/create-show-triggers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/trigger/create-show-triggers.png -------------------------------------------------------------------------------- /images/trigger/create-trigger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/trigger/create-trigger.png -------------------------------------------------------------------------------- /images/trigger/drop-triggers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/trigger/drop-triggers.png -------------------------------------------------------------------------------- /images/trigger/select-goods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/trigger/select-goods.png -------------------------------------------------------------------------------- /images/trigger/select-triggers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/trigger/select-triggers.png -------------------------------------------------------------------------------- /images/trigger/show-ceate-triggers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/trigger/show-ceate-triggers.png -------------------------------------------------------------------------------- /images/trigger/show-triggers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/trigger/show-triggers.png -------------------------------------------------------------------------------- /images/trigger/user-triggers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/trigger/user-triggers.png -------------------------------------------------------------------------------- /images/union/select-student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/union/select-student.png -------------------------------------------------------------------------------- /images/union/select-union-class.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/union/select-union-class.png -------------------------------------------------------------------------------- /images/union/select-union-distinct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/union/select-union-distinct.png -------------------------------------------------------------------------------- /images/union/select-union-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/union/select-union-error.png -------------------------------------------------------------------------------- /images/union/union-order-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/union/union-order-2.png -------------------------------------------------------------------------------- /images/union/union-order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/union/union-order.png -------------------------------------------------------------------------------- /images/uniquekey/alter-myunique3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/uniquekey/alter-myunique3.png -------------------------------------------------------------------------------- /images/uniquekey/create-table-myunique.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/uniquekey/create-table-myunique.png -------------------------------------------------------------------------------- /images/uniquekey/create-table-myunique2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/uniquekey/create-table-myunique2.png -------------------------------------------------------------------------------- /images/uniquekey/create-table-myunique3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/uniquekey/create-table-myunique3.png -------------------------------------------------------------------------------- /images/uniquekey/desc-myunique3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/uniquekey/desc-myunique3.png -------------------------------------------------------------------------------- /images/uniquekey/insert-myunique.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/uniquekey/insert-myunique.png -------------------------------------------------------------------------------- /images/uniquekey/show-create-myunique2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/uniquekey/show-create-myunique2.png -------------------------------------------------------------------------------- /images/updata-and-delete/delete-mycopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/updata-and-delete/delete-mycopy.png -------------------------------------------------------------------------------- /images/updata-and-delete/delete-student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/updata-and-delete/delete-student.png -------------------------------------------------------------------------------- /images/updata-and-delete/select-mycopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/updata-and-delete/select-mycopy.png -------------------------------------------------------------------------------- /images/updata-and-delete/truncate-student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/updata-and-delete/truncate-student.png -------------------------------------------------------------------------------- /images/updata-and-delete/update-mycopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/updata-and-delete/update-mycopy.png -------------------------------------------------------------------------------- /images/view-one/alter-myv1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-one/alter-myv1.png -------------------------------------------------------------------------------- /images/view-one/create-myv1v2v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-one/create-myv1v2v3.png -------------------------------------------------------------------------------- /images/view-one/create-myv3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-one/create-myv3.png -------------------------------------------------------------------------------- /images/view-one/desc-myv1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-one/desc-myv1.png -------------------------------------------------------------------------------- /images/view-one/drop-myv4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-one/drop-myv4.png -------------------------------------------------------------------------------- /images/view-one/select-myv1v2v3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-one/select-myv1v2v3.png -------------------------------------------------------------------------------- /images/view-one/show-create-myv1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-one/show-create-myv1.png -------------------------------------------------------------------------------- /images/view-two/create-myv5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-two/create-myv5.png -------------------------------------------------------------------------------- /images/view-two/create-myv6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-two/create-myv6.png -------------------------------------------------------------------------------- /images/view-two/delete-myv3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-two/delete-myv3.png -------------------------------------------------------------------------------- /images/view-two/desc-myv3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-two/desc-myv3.png -------------------------------------------------------------------------------- /images/view-two/desc-student.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-two/desc-student.png -------------------------------------------------------------------------------- /images/view-two/select-myv6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-two/select-myv6.png -------------------------------------------------------------------------------- /images/view-two/show-myv2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-two/show-myv2.png -------------------------------------------------------------------------------- /images/view-two/update-myv5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/view-two/update-myv5.png -------------------------------------------------------------------------------- /images/worm-copy/desc-mygbk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/worm-copy/desc-mygbk.png -------------------------------------------------------------------------------- /images/worm-copy/insert-mycopy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/worm-copy/insert-mycopy.png -------------------------------------------------------------------------------- /images/worm-copy/select-mycollate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guobinhit/mysql-tutorial/427702c4a88e5be0b2f53ec8ed313d46a07fc9fc/images/worm-copy/select-mycollate.png --------------------------------------------------------------------------------