持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用。持久化的大多数时候是将内存中的数据存储在数据库中,当然也可以存储在磁盘文件、XML数据文件中。
方便管理数据(例如:快速的检索等)
DB:数据库(Database)即存储数据的“仓库”。它保存了一系列有组织的数据。
DBMS:数据库管理系统(Database Management System):是一种操纵和管理数据库的大型软件,例如建立、使用和维护数据库。
目前互联网上常见的数据库管理软件有Sybase、DB2、Oracle、MySQL、Access、Visual Foxpro(面向对象型)、MS SQL Server、Informix、PostgreSQL(最符合SQL标准,但是性能差)这几种。以下是2017年StackOverflow 对各数据库受欢迎程度进行调查后的统计结果:
MySQL是一种开放源代码的关系型数据库管理系统,开发者为瑞典MySQL AB公司。在2008年1月16号被Sun公司收购。而2009年,SUN又被Oracle收购.目前 MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,使得很多互联网公司选择了MySQL作为网站数据库(Facebook, Twitter, YouTube,阿里的蚂蚁金服,去哪儿,魅族,百度外卖,腾讯)。
阿里巴巴/蚂蚁金服主要使用两种关系数据库:OceanBase和MySQL。数据规模:MySQL单台机器TB级,OceanBase单个集群从几个TB到几百个TB皆有。
去哪儿:MySQL,Redis,HBase
腾讯社交网络主要使用深度定制MySQL数据库+自研NoSQL,规模万台以上服务器,千万级qps。
百度外卖目前线上主要使用Mysql、redis等数据库。MySQL 数据数百TB级,redis 数据几TB级。
目前魅族OLTP场景主要使用的是MySQL,缓存服务使用的是Redis。数据库实例近1000,数据大小100T+, redis实例1000+。
关系型数据库:关系数据库的表采用二维表格来存储数据,是一种按行与列排列的具有相关信息的逻辑组,它类似于Excle工作表。一个数据库可以包含任意多个数据表。表中的一行即为一条记录。数据表中的每一列称为一个字段,表是由其包含的各种字段定义的,每个字段描述了它所含有的数据的意义,数据表的设计实际上就是对字段的设计。创建数据表时,为每个字段分配一个数据类型,定义它们的数据长度和其他属性。行和列的交叉位置表示某个属性值,如“数据库原理”就是课程名称的属性值。
SQL:结构化查询语言(Structured Query Language)。
方式一:通过控制面板
方式二:通过电脑管家等软件卸载
方式三:通过安装包中提供的卸载功能卸载
如果再次安装不成功,可以卸载后对残余文件进行清理后再安装
(1)清除安装残余文件
(2)清除数据残余文件
请在卸载前做好数据备份
如何打开注册表编辑器:在系统的搜索框中输入regedit
如果前两步做了,再次安装还是失败,那么可以清理注册表
1:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Eventlog\Application\MySQL服务 目录删除
2:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\MySQL服务 目录删除
3:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Services\Eventlog\Application\MySQL服务 目录删除
4:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Services\MySQL服务 目录删除
5:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MySQL服务目录删除
6:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MySQL服务删除
注册表中的ControlSet001,ControlSet002,不一定是001和002,可能是ControlSet005、006之类
Typical:表示一般常用的组件都会被安装,默认情况下安装到”C:\Program Files\MySQL\MySQL Server 5.5\”下。
Complete:表示会安装所有的组件。此套件会占用比较大的磁盘空间。
Custom:表示用户可以选择要安装的组件,可以更改默认按照的路径。这种按照类型最灵活,适用于高级用户。
这里可以选择安装哪些部分,主要是这里可以设置两个路径:
MySQL Server的应用软件的安装路径,默认在“C:\Program Files\MySQL\MySQL Server 5.5\”
Server data files的数据存储的目录路径,默认在“C:\ProgramData\MySQL\MySQL Server 5.5\”
建议把数据存储的目录路径修改一下,以防系统崩溃或重装系统时数据保留。
安装进度
系统会显示MySQL Enterprise版(企业版)的一些功能介绍界面,可以单击“Next”继续。
单击“Finish”按钮完成安装过程。如果想马上配置数据库连接,选择“Launch the MySQL Instance Configuration Wizard”复选框。如果现在没有配置,以后想要配置或重新配置都可以在“MySQL Server”的安装目录的bin目录下(例如:D:\ProgramFiles\MySQL5.5\MySQL Server 5.5\bin)找到“MySQLInstanceConfig.exe”打开“MySQL Instance Configuration Wizard”向导。
选择配置方式,“Detailed Configuration(手动精确配置)”、“Standard Configuration(标准配置)”,我们选择“Detailed Configuration”,方便熟悉配置过程。
Develop Machine(开发机),使用最小数量的内存
Server Machine(服务器),使用中等大小的内存
Dedicated MySQL Server Machine(专用服务器),使用当前可用的最大内存。
选择mysql数据库的大致用途:
“Multifunctional Database(通用多功能型,好)”:此选项对事务性存储引擎(InnoDB)和非事务性(MyISAM)存储引擎的存取速度都很快。
“Transactional Database Only(服务器类型,专注于事务处理,一般)”:此选项主要优化了事务性存储引擎(InnoDB),但是非事务性(MyISAM)存储引擎也能用。
“Non-Transactional Database Only(非事务处理型,较简单)主要做一些监控、记数用,对MyISAM数据类型的支持仅限于non-transactional,注意事务性存储引擎(InnoDB)不能用。
InnoDB的数据文件会在数据库第一次启动的时候创建,默认会创建在MySQL的安装目录下。用户可以根据实际的空间状况进行路径的选择。
选择您的网站的一般mysql 访问量,同时连接的数目,“Decision Support(DSS)/OLAP(决策支持系统,20个左右)”、“Online Transaction Processing(OLTP)(在线事务系统,500个左右)”、“Manual Setting(手动设置,自己输一个数)”
是否启用TCP/IP连接,设定端口,如果不启用,就只能在自己的机器上访问mysql 数据库了,我这里启用,把前面的勾打上,Port Number:3306,还有一个关于防火墙的设置“Add firewall exception ……”需要选中,将MYSQL服务的监听端口加为windows防火墙例外,避免防火墙阻断。
在这个页面上,您还可以选择“启用标准模式”(Enable Strict Mode),这样MySQL就不会允许细小的语法错误。尽量使用标准模式,因为它可以降低有害数据进入数据库的可能性。
注意:如果要用原来数据库的数据,最好能确定原来数据库用的是什么编码,如果这里设置的编码和原来数据库数据的编码不一致,在使用的时候可能会出现乱码。
这个比较重要,就是对mysql默认数据库语言编码进行设置,第一个是西文编码,第二个是多字节的通用utf8编码,第三个,手工选择字符集。
提示:
如果安装时选择了字符集和“utf8”,通过命令行客户端来操作数据库时,有时候会出现乱码,
这是因为“命令行客户端”默认是GBK字符集,因此客户端与服务器端就出现了不一致的情况,会出现乱码。
可以在客户端执行:
mysql> set names gbk;
可以通过以下命令查看:
mysql> show variables like 'character_set_%';
对于客户端和服务器的交互操作,MySQL提供了3个不同的参数:character_set_client、character_set_connection、character_set_results,分别代表客户端、连接和返回结果的字符集。通常情况下,这3个字符集应该是相同的,才能确保用户写入的数据可以正确的读出和写入。“set names xxx;”命令可以同时修改这3个参数的值,但是需要每次连接都重新设置。
选择是否将mysql 安装为windows服务,还可以指定Service Name(服务标识名称,例如我这里取名为“MySQL5.5”),是否将mysql的bin目录加入到Windows PATH环境变量中(加入后,就可以直接使用bin下的命令)”,我这里全部打上了勾。
这一步询问是否要修改默认root 用户(超级管理)的密码(默认为空),“New root password”如果要修改,就在此填入新密码,“Confirm(再输一遍)”内再填一次,防止输错。(如果是重装,并且之前已经设置了密码,在这里更改密码可能会出错,请留空,并将“Modify Security Settings”前面的勾去掉,安装配置完成后另行修改密码)
“Enable root access from remotemachines(是否允许root 用户在其它的机器或使用IP地址登陆,如果要安全,就不要勾上,如果要方便,就勾上它)”。如果没有勾选,默认只支持localhost和127.0.0.1连接。
最后“Create An Anonymous Account(新建一个匿名用户,匿名用户可以连接数据库,不能操作数据,包括查询,如果要有操作数据的权限需要单独分配)”,一般就不用勾了
关系型数据库分为桌面文件共享型数据库,例如Access,和C/S架构的网络共享型数据库,例如:MySQL,Oracle等。MySQL软件的服务器端必须先启动,客户端才可以连接和使用使用数据库。
启动服务的方式:
“我的电脑/计算机”-->右键-->“管理”-->“服务”-->启动和关闭MySQL
“开始菜单”-->“控制面板”-->“管理工具”-->“服务”-->启动和关闭MySQL
“任务管理器”-->“服务”-->启动和关闭MySQL
net start MySQL服务名
net stop MySQL服务名
“开始菜单”-->MySQL-->MySQL Server 5.5 --> MySQL 5.5 Command Line Client
仅限于root用户
mysql -h 主机名 -P 端口号 -u 用户名 -p密码
例如:mysql -h localhost -P 3306 -u root -proot
注意:
(1)-p与密码之间不能有空格,其他参数名与参数值之间可以有空格也可以没有空格
mysql -hlocalhost -P3306 -uroot -proot
(2)密码建议在下一行输入
mysql -h localhost -P 3306 -u root -p
Enter password:****
(3)如果是连本机:-hlocalhost就可以省略,如果端口号没有修改:-P3306也可以省略
简写成:mysql -u root -p
Enter password:****
连接成功后,有关于MySQL Server服务版本的信息,还有第几次连接的id标识。
也可以在命令行通过以下方式获取MySQL Server服务版本的信息
或登录后,通过以下方式查看当前版本信息:
例如:Navicat Preminum,SQLyogEnt等工具
还有其他工具:mysqlfront,phpMyAdmin
(1)Navicat Preminum
(2)SQLyog
MySQL最重要、最与众不同的特性是它的存储引擎架构,这种架构的设计将查询处理(Query Processing)及其他系统任务(Server Task)和数据的存储/提取相分离。这种处理和存储分离的设计可以在使用时根据性能、特性,以及其他需求来选择数据存储的方式。
MySQL中同一个数据库,不同的表格可以选择不同的存储引擎。
查看当前mysql数据库管理软件支持的存储引擎: SHOW ENGINES;
查看默认存储引擎和当前选择的存储引擎:SHOW VARIABLES LIKE '%storage_engine%';
创建新表时如果不指定存储引擎,那么系统就会使用默认存储引擎,MySQL5.5之前的默认存储引擎是MyISAM,5.5之后改为了InnoDB。
查看已经创建的表格的存储引擎: SHOW CREATE TABLE 表名称;
查看当前的MySQL服务器中有哪些数据库 |
mysql> SHOW DATABASES; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.05 sec) |
使用test数据库 |
mysql> USE test; Database changed |
创建表格 |
mysql> CREATE TABLE t_stu( -> sid INT, -> sname VARCHAR(100), -> gender CHAR -> ); Query OK, 0 rows affected (0.14 sec) |
查看表结构 |
mysql> DESC t_stu; +--------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+--------------+------+-----+---------+-------+ | sid | int(11) | YES | | NULL | | | sname | varchar(100) | YES | | NULL | | | gender | char(1) | YES | | NULL | | +--------+--------------+------+-----+---------+-------+ 3 rows in set (0.03 sec) |
插入记录 |
mysql> INSERT INTO t_stu VALUES(1,'张三','男'); Query OK, 1 row affected (0.06 sec)
mysql> INSERT INTO t_stu VALUES(2,'李四','男'); Query OK, 1 row affected (0.09 sec)
mysql> INSERT INTO t_stu VALUES(3,'王五','男'); Query OK, 1 row affected (0.06 sec) |
查看记录 |
mysql> SELECT * FROM t_stu; +------+-------+--------+ | sid | sname | gender | +------+-------+--------+ | 1 | 张三 | 男 | | 2 | 李四 | 男 | | 3 | 王五 | 男 | +------+-------+--------+ 3 rows in set (0.00 sec) |
修改记录 |
mysql> UPDATE t_stu SET sname = '张三丰' WHERE sid = 1; Query OK, 1 row affected (0.08 sec) Rows matched: 1 Changed: 1 Warnings: 0
mysql> SELECT * FROM t_stu; +------+--------+--------+ | sid | sname | gender | +------+--------+--------+ | 1 | 张三丰 | 男 | | 2 | 李四 | 男 | | 3 | 王五 | 男 | +------+--------+--------+ 3 rows in set (0.00 sec) |
删除记录 |
mysql> DELETE FROM t_stu WHERE sid = 1; Query OK, 1 row affected (0.08 sec)
mysql> SELECT * FROM t_stu; +------+-------+--------+ | sid | sname | gender | +------+-------+--------+ | 2 | 李四 | 男 | | 3 | 王五 | 男 | +------+-------+--------+ 2 rows in set (0.00 sec) |
ERROR 1046 (3D000): No database selected |
解决方案一:就是使用“USE 数据库名;”语句,这样接下来的语句就默认针对这个数据库进行操作 |
解决方案二:就是所有的表对象前面都加上“数据库.” |
mysql> INSERT INTO t_stu VALUES(1,'张三','男'); ERROR 1366 (HY000): Incorrect string value: '\xD5\xC5\xC8\xFD' for column 'sname' at row 1 |
原因:服务器端认为你的客户端的字符集是utf-8,而实际上你的客户端的字符集是GBK
查看所有字符集:SHOW VARIABLES LIKE 'character_set_%';
解决方案,设置当前连接的客户端字符集“SET NAMES GBK;”
关于SQL的关键字和函数名等不区分大小写,但是对于数据值是否区分大小写,和字符集与校对规则有关。
_ci(大小写不敏感),_cs(大小写敏感),_bin(二元,即比较是基于字符编码的值而与language无关)
show collation like 'gbk%';
show collation like 'utf8%';
utf8_unicode_ci和utf8_general_ci对中、英文来说没有实质的差别。
utf8_general_ci 校对速度快,但准确度稍差。
utf8_unicode_ci 准确度高,但校对速度稍慢。
如果你的应用有德语、法语或者俄语,请一定使用utf8_unicode_ci。一般用utf8_general_ci就够了。
或
修改数据库的字符集和校对规则:
ALTER DATABASE 数据库名称 DEFAULT CHARACTER SET 字符集名称 【COLLATE 校对规则名称】;
例如:
ALTER DATABASE ceshi_db DEFAULT CHARACTER SET utf8 collate utf8_general_ci;
注意:修改了数据库的默认字符集和校对规则后,原来已经创建的表格的字符集和校对规则并不会改变,如果需要,那么需要单独修改。
查看字符集:show create table users;
如果要查看校对规则:show table status from bookstore like '%users%' ;
修改某个表格的字符集和校对规则:
修改表的默认字符集:
ALTER TABLE 表名称 DEFAULT CHARACTER SET 字符集名称 【COLLATE 校对规则名称】;
把表默认的字符集和所有字符列(CHAR,VARCHAR,TEXT)改为新的字符集:
ALTER TABLE 表名称 CONVERT TO CHARACTER SET 字符集名称 【COLLATE 校对规则名称】;
例如:ALTER TABLE ceshi_table DEFAULT CHARACTER SET gbk collate gbk_chinese_ci;
常用的数据类型有:
整数类型 |
字节 |
最小值(有符号/无符号) |
最大值(有符号/无符号) |
TINYINT |
1 |
-128/0 |
127/255 |
SMALLINT |
2 |
-32768/0 |
32767/65535 |
MEDIUMINT |
3 |
-8388608/0 |
8388607/1677215 |
INT、INTEGER |
4 |
-2147483648/0 |
2147483647/4294967295 |
BIGINT |
8 |
-9223372036854775808/0 |
9223372036854775807/18446744073709551615 |
整数列的可选属性有三个:
原来,在 int(M) 中,M 的值跟 int(M) 所占多少存储空间并无任何关系。 int(3)、int(4)、int(8) 在磁盘上都是占用 4 bytes 的存储空间。
对于浮点列类型,在MySQL中单精度值使用4个字节,双精度值使用8个字节
注意:在编程中,如果用到浮点数,要特别注意误差问题,因为浮点数是不准确的,所以我们要避免使用“=”来判断两个数是否相等。如果希望保证值比较准确,推荐使用定点数数据类型。
char是一种固定长度的类型,varchar则是一种可变长度的类型,它们的区别是:
char如果不指定(M)则表示长度默认是1个字符。varchar必须指定(M)。
char(M)类型的数据列里,每个值都占用M个字符,如果某个长度小于M,MySQL就会在它的右边用空格字符补足(在检索操作中那些填补出来的空格字符将被去掉;如果存入时右边本身就带空格,检索时也会被去掉);在varchar(M)类型的数据列里,每个值只占用刚好够用的字符再加上一个到两个用来记录其长度的字节(即总长度为L字符+1/2字字节)。
(4.0版本以下,varchar(20),指的是20字节,如果存放UTF8汉字时,只能存6个(每个汉字3字节) ;5.0版本以上,varchar(20),指的是20字符)
由于某种原因char 固定长度,所以在处理速度上要比varchar快速很多,但相对费存储空间,所以对存储不大,但在速度上有要求的可以使用char类型,反之可以用varchar类型来实例。
text文本类型,可以存比较大的文本段,搜索速度稍慢,因此如果不是特别大的内容,建议使用char,varchar来代替。还有text类型不用加默认值,加了也没用。而且text和blob类型的数据删除后容易导致“空洞”,使得文件碎片比较多,所以频繁使用的表不建议包含text类型字段,建议单独分出去,单独用一个表。
一,存储很短的信息,比如门牌号码101,201……这样很短的信息应该用char,因为varchar还要占个byte用于存储信息长度,本来打算节约存储的现在得不偿失。
二,固定长度的。比如使用uuid作为主键,那用char应该更合适。因为他固定长度,varchar动态根据长度的特性就消失了,而且还要占个长度信息。
三,十分频繁改变的column。因为varchar每次存储都要有额外的计算,得到长度等工作,如果一个非常频繁改变的,那就要有很多的精力用于计算,而这些对于char来说是不需要的。
MyISAM和MEMORY存储引擎中无论使用char还是varchar其实都是作为char类型处理的。
其他像InnoDB存储引擎,建议使用varchar类型,因为对于InnoDB数据表,内部的行存储格式并没有区分固定长度和可变长度列(所有数据行都使用指向数据列值的头指针),而且主要影响性能的因素是数据行使用的存储总量,由于char平均占用的空间多于varchar,所以除了简短并且固定长度的,其他考虑varchar。
BIT数据类型可用来保存位字段值。BIT(M)类型允许存储M位值。M范围为1~64,默认为1。
BIT其实就是存入二进制的值,类似010110。如果存入一个BIT类型的值,位数少于M值,则左补0。如果存入一个BIT类型的值,位数多于M值,MySQL的操作取决于此时有效的SQL模式:如果模式未设置,MySQL将值裁剪到范围的相应端点,并保存裁减好的值。如果模式设置为traditional(“严格模式”),超出范围的值将被拒绝并提示错误,并且根据SQL标准插入会失败。
对于位字段,直接使用SELECT命令将不会看到结果,可以用bin()或hex()函数进行读取。
包括:xxxBLOB和xxxBINARY
BINARY和VARBINARY类型类似于CHAR和VARCHAR类型,但是不同的是,它们存储的不是字符字符串,而是二进制串。所以它们没有字符集,并且排序和比较基于列值字节的数值值。当保存BINARY(M)值时,在它们右边填充0x00(零字节)值以达到指定长度。取值时不删除尾部的字节。比较时所有字节很重要(因为空格和0x00是不同的,0x00<空格),包括ORDER BY和DISTINCT操作。比如插入'a '会变成'a \0'。
BLOB是一个二进制大对象,可以容纳可变数量的数据。有4种BLOB类型:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。它们只是可容纳值的最大长度不同。分别与四种TEXT类型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT对应有相同的最大长度和存储需求。在TEXT或BLOB列的存储或检索过程中,不存在大小写转换。BLOB和TEXT列不能有默认值。BLOB或TEXT对象的最大大小由其类型确定,但在客户端和服务器之间实际可以传递的最大值由可用内存数量和通信缓存区大小确定。你可以通过更改max_allowed_packet变量的值更改消息缓存区的大小,但必须同时修改服务器和客户端程序。
MySql中的ENUM是一个字符串对象,其值来自表创建时在列规定中显式枚举的一列值:
值的索引规则如下:
SET和ENUM类型非常类似,也是一个字符串对象,里面包含0~64个成员。
SET和ENUM存储上有所不同,SET是根据成员的个数决定存储的字节数。
SET和ENUM最主要的区别在于SET类型一次可以选择多个成员,而ENUM则只能选择一个。
例如:set(‘a’,’b’,’c’,’d’)
Null特征:
(1)所有的类型的值都可以是null,包括int、float等数据类型
(2)空字符串””,不等于null,0也不等于null,false也不等于null
(3)任何运算符,判断符碰到NULL,都得NULL
(4)NULL的判断只能用is null,is not null
(5)NULL 影响查询速度,一般避免使值为NULL
面试:
为什么建表时,加not null default '' 或 default 0
答:不想让表中出现null值.
为什么不想要的null的值
答:(1)不好比较,null是一种特殊值,比较时,只能用专门的is null 和 is not null来比较.
碰到运算符,一律返回null
(2)效率不高,影响提高索引效果.
因此,我们往往,在建表时 not null default '' 或 default 0
SQL:Structure Query Language结构化查询语言,它是使用关系模型的数据库应用语言,由IBM上世纪70年代开发出来。后由美国国家标准局(ANSI)开始着手制定SQL标准,先后有SQL-86,SQL-89,SQL-92,SQL-99等标准。
命名规则:
在命令行中的要求:
说明:一个语句可以分开多行编写,以;或\g结束
SQL的分类:
主要的语句关键字包括create、drop、alter等。
主要的语句关键字包括insert、delete、update、select等。
主要的语句关键字包括grant、revoke等。
注意:database不能改名。一些可视化工具可以改名,它是建新库,把所有表复制到新库,再删旧库完成的。
create database 数据库名 [charset 字符集]; (关键字大写效果:CREATE DATABASE 数据库名;)
如果不指定字符集,则按照安装mysql服务时选择的默认字符集。
show databases;
提示:当前用户有权限查看的
drop database 数据库名;
use 数据库名;
select database();
注意:要操作表格和数据之前必须先说明是对哪个数据库进行操作,否则就要对所有对象加上“数据库名.”。
show tables; #前面必须有use 数据库名语句,否则报错ERROR 1046 (3D000): No database selected
show tables from 数据库名;
(1)基础版
CREATE TABLE 表名称( 字段名1 数据类型1, 字段名2 数据类型2, 字段名3 数据类型3 ); |
CREATE TABLE t_stu( sid INT, sname VARCHAR(100), gender CHAR ); |
(2)详细版
CREATE TABLE 表名称( 字段名1 数据类型1 主键 自增长, 字段名2 数据类型2 非空 默认值, 字段名3 数据类型3 )ENGINE=当前表格的引擎 AUTO_INCREMENT=自增长的起始值 DEFAULT CHARSET=表数据的默认字符集; |
CREATE TABLE t_stu( sid INT PRIMARY KEY AUTO_INCREMENT, sname VARCHAR(100) NOT NULL, gender CHAR NOT NULL DEFAULT '男' )ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; |
desc 表名称;
查看表的定义:SHOW CREATE TABLE 表名;
drop table 表名称;
注意:
数据和结构都被删除
所有正在运行的相关事务被提交
所有相关索引被删除
DROP TABLE 语句不能回滚
(1)重命名表
alter table 表名 rename 新表名;
rename table 表名 to 新表名;
(2)增加一列
alter table 表名 add 【column】 列名 数据类型 【default 默认值】【not null】; #默认在最后
alter table 表名 add 【column】 列名 数据类型 【default 默认值】【not null】 after 某一列;
alter table 表名 add 【column】 列名 数据类型 【default 默认值】【not null】 first;
(3)删除列
alter table 表名 drop 【column】 列名;
(4)修改列类型
alter table 表名 modify 【column】 列名 数据类型【default 默认值】【not null】;
alter table 表名 modify 【column】 列名 数据类型【default 默认值】【not null】 after 某一列;
alter table 表名 modify 【column】 列名 数据类型【default 默认值】【not null】 first;
(5)修改列名等
alter table 表名 change 【column】 列名 新列名 数据类型【default 默认值】【not null】;
数据完整性(Data Integrity)是指数据的精确性(Accuracy)和可靠性(Reliability)。它是应防止数据库中存在不符合语义规定的数据和防止因错误信息的输入输出造成无效操作或错误信息而提出的。数据的完整性要从以下四个方面考虑:
根据约束的特点,分为几种:
(1)查看某个表的约束和索引
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称'; |
SHOW INDEX FROM 表名称; |
SHOW CREATE TABLE 表名; |
(2)主键约束PRIMARY KEY
主键:Primary key,简称PK,数据库主键作用保证实体的完整性,可以是一个列或多列的组合。
主键约束相当于唯一约束+非空约束的组合,主键约束列不允许重复,也不允许出现空值,如果是多列组合的主键约束,那么这些列都不允许为空值,并且组合的值不允许重复。
每个表有且最多只允许一个主键约束。
MySQL的主键名总是PRIMARY,就算自己命名了主键约束名也没用。
当创建主键约束时,MySQL默认在对应的列上建立主键索引。删除主键时,也会直接删除主键索引。
如何建立主键?
在主键列后面直接加主键约束,复合主键不能使用这种方式 |
单独声明主键约束 |
声明复合主键,复合主键只能使用这种方式 |
|
CREATE TABLE t_stu( sid INT PRIMARY KEY, sname VARCHAR(100), gender CHAR ); |
CREATE TABLE t_course( cid INT , cname VARCHAR(100), decription VARCHAR(200), PRIMARY KEY(cid) ); |
CREATE TABLE t_stu_course( sid INT, cid INT, score DOUBLE(4,1), PRIMARY KEY(sid,cid) ); |
|
建表后添加主键约束 |
alter table 表名称 add 【constraint 约束名】 primary key (字段名); |
||
alter table 表名称 add 【constraint 约束名】 primary key (字段名1,字段名2); |
|||
ALTER TABLE t_stu ADD PRIMARY KEY(sid); |
ALTER TABLE t_course ADD PRIMARY KEY(cid); |
ALTER TABLE t_stu_course ADD PRIMARY KEY(sid,cid); |
如何删除主键和对应的索引?
删除主键约束,不需要指定主键名,因为一个表只有一个主键,删除主键约束后,非空还存在 alter table表名称drop primary key; |
(3)唯一键Unique key,简称UK,
如何建立唯一性约束?
在某个列后面直接加唯一性约束 |
单独指定表的唯一性约束 |
组合列唯一性约束 |
CREATE TABLE t_course( cid INT PRIMARY KEY, cname VARCHAR(100) UNIQUE, description VARCHAR(200) ); |
CREATE TABLE t_stu( sid INT PRIMARY KEY, sname VARCHAR(100), card_id CHAR(18), CONSTRAINT uk_card_id UNIQUE KEY(card_id) ); #其中CONSTRAINT uk_cname和KEY可以省略 |
CREATE TABLE t_stu_course( id INT PRIMARY KEY, sid INT, cid INT, score DOUBLE(4,1), CONSTRAINT uk_sid_cid UNIQUE KEY(sid,cid) ); #其中CONSTRAINT uk_sid_cid和KEY可以省略 |
建表后增加唯一性约束 |
alter table表名称 add 【constraint 约束名】 unique 【key】 (字段名); alter table表名称 add 【constraint 约束名】 unique 【key】 (字段名1,字段名2); |
|
ALTER TABLE t_course ADD CONSTRAINT uk_cname UNIQUE KEY(cname); #其中CONSTRAINT uk_cname和KEY可以省略 |
ALTER TABLE t_stu ADD CONSTRAINT uk_card_id UNIQUE KEY(card_id); #其中CONSTRAINT uk_cname和KEY可以省略 |
ALTER TABLE t_stu_course ADD CONSTRAINT uk_sid_cid UNIQUE KEY(sid,cid); #其中CONSTRAINT uk_cname和KEY可以省略 |
如何删除唯一性约束和索引?
ALTER TABLE 表名称 DROP INDEX 唯一性约束名; #注意:如果忘记名称,可以通过“show index from 表名称;”查看 |
主键和唯一键的区别:
(1)主键是非空,唯一键允许空
(2)主键一个表只能一个,唯一键可以有多个
4)外键:Foreign key,简称FK
注意:
如何建立外键约束?
创建外键 |
CREATE TABLE t_department( did INT PRIMARY KEY, dname VARCHAR(100) NOT NULL UNIQUE, description VARCHAR(200) NOT NULL ); CREATE TABLE t_employee( eid INT PRIMARY KEY, ename VARCHAR(100) NOT NULL, dept_id INT, CONSTRAINT fk_emp_dept_did FOREIGN KEY(dept_id) REFERENCES t_department(did) ON UPDATE CASCADE ON DELETE RESTRICT ); #其中CONSTRAINT fk_emp_dept_did可以省略 #ON UPDATE CASCADE ON DELETE RESTRICT如果省略表示都是RESTRICT |
一个表可以有多个外键,而且主表和从表可以是一张表 |
CREATE TABLE t_emp( eid INT PRIMARY KEY, ename VARCHAR(100) NOT NULL, manager_id INT, dept_id INT, CONSTRAINT fk_emp_dept_did FOREIGN KEY(dept_id) REFERENCES t_department(did) ON UPDATE CASCADE ON DELETE RESTRICT, CONSTRAINT fk_emp_mid_eid FOREIGN KEY(manager_id) REFERENCES t_emp(eid) ON UPDATE CASCADE ON DELETE RESTRICT ); #其中CONSTRAINT fk_emp_dept_did可以省略 #ON UPDATE CASCADE ON DELETE RESTRICT如果省略表示都是RESTRICT |
建表后创建外键 |
alter table表名称 add 【constraint 约束名】 foreign key (从表字段名) references 主表名(主表被参照字段名); ALTER TABLE t_emp ADD CONSTRAINT fk_emp_dept_did FOREIGN KEY(dept_id) REFERENCES t_department(did) ON UPDATE CASCADE ON DELETE RESTRICT; #其中CONSTRAINT fk_emp_dept_did可以省略 #ON UPDATE CASCADE ON DELETE RESTRICT如果省略表示都是RESTRICT |
如何删除外键约束?
ALTER TABLE 表名称 DROP FOREIGN KEY 外键约束名; ALTER TABLE t_emp DROP FOREIGN KEY fk_emp_dept_did; |
查看约束名 SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称'; |
如何删除外键列上的索引?需要单独删除
ALTER TABLE 表名称 DROP INDEX 外键列索引名; ALTER TABLE t_emp DROP INDEX dept_id; |
查看索引名 show index from 表名称; |
(5)非空约束
CREATE TABLE t_stu( sid INT PRIMARY KEY, sname VARCHAR(100) NOT NULL ); |
如果某列已经创建好,那么可以修改列语句修改:
例如:原来非空,修改为允许空
ALTER TABLE ceshi_table MODIFY des VARCHAR(20); |
例如:原来允许空,修改为非空
ALTER TABLE ceshi_table MODIFY des VARCHAR(20) NOT NULL; |
(6)检查约束
注意: MySQL不支持check约束,但可以使用check约束,而没有任何效果;
例如:age tinyint check(age >20) 或 sex char(2) check(sex in(‘男’,’女’))
CREATE TABLE t_stu( sid INT PRIMARY KEY, sname VARCHAR(100) NOT NULL, gender CHAR NOT NULL CHECK(gender IN('男','女')) ); |
(7)Default缺省约束
default:默认值,在插入数据时某列如果没指定其他的值,那么会将默认值添加到新记录。
CREATE TABLE t_stu( sid INT PRIMARY KEY, sname VARCHAR(100) NOT NULL, gender CHAR NOT NULL CHECK(gender IN('男','女')) ); |
如果某列已经创建好,那么可以修改列语句修改:
例如:原来有默认值,去除默认值
ALTER TABLE ceshi_table MODIFY des VARCHAR(20); |
例如:原来没有默认值,增加默认值
ALTER TABLE ceshi_table MODIFY des VARCHAR(20) DEFAULT '略'; |
索引:索引是对数据库表中一列或多列的值进行排序的一种结构。索引是一个单独的、物理的数据库结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。由此可知,索引是要消耗数据库空间的。而约束是一种逻辑概念。
例如:一本字典,如何快速找到某个字,可以给字典加目录,对数据库来说,索引的作用即是给"数据"加目录。
设有N条随机记录,不用索引,平均查找N/2次,那么用了索引之后呢。如果是btree(二叉树)索引, ,如果是hash(哈希)索引,时间复杂度是1。
索引好处:加快了查询速度(select )
索引坏处:降低了增,删,改的速度(update/delete/insert),增大了表的文件大小(索引文件甚至可能比数据文件还大)
MySQL提供多种索引类型供选择:
MySQL的索引方法:
MySQL中多数索引都以BTREE的形式保存。
索引的使用原则:
(1)不过度索引
(2)索引条件列(where后面最频繁的条件比较适宜索引)
(3)索引散列值,过于集中的值不要索引,例如:给性别"男","女"加索引,意义不大
CREATE INDEX 索引名 ON 表名称 (column_name,[column_name...]); 最左边的列最关键
alter table 表名称 drop index 索引名;
例如:
CREATE TABLE t_stu( sid INT PRIMARY KEY AUTO_INCREMENT, sname VARCHAR(100) NOT NULL, gender CHAR NOT NULL DEFAULT '男', birthday DATE, address VARCHAR(200) ); |
关于自增长auto_increment:
数据操纵语言(DML)DML用于插入、修改、删除数据记录,包括如下SQL语句:
INSERT:添加数据到数据库中
UPDATE:修改数据库中的数据
DELETE:删除数据库中的数据
INSERT INTO 表名称 VALUES(值1,值2,......); |
INSERT INTO 表名称 VALUES(值1,值2,......),(值1,值2,......),...; |
INSERT INTO 表名称 (字段1,字段2,......) VALUES(值1,值2,......); |
INSERT INTO 表名称 (字段1,字段2,......) VALUES(值1,值2,......),(值1,值2,......),.....; |
1、值列表(值1,值2,......)的顺序、个数与字段列表(字段1,字段2,......) 中字段的顺序、个数一致
(1)如果个数少了就报Column count doesn’t match value count
(2)如果VALUES前面的()中没有列出字段,那么默认就是为表中的所有字段赋值,那么个数与顺序与表结构中字段定义的一致
2、关于自增长列、默认值列、允许为NULL列的赋值
(1)如果字段列表列出了字段名,那么值列表中就要为其赋值,哪怕它是自增长列,有默认值列,可以为NULL值的列。
(2)对于没有列出的字段,像自增列就自动赋值,像默认值列就自动赋默认值,像允许NULL的列就自动赋NULL值,但是非空列又没有提供默认值会自动赋值为对应数据类型的默认值,例如字符串赋值为空字符串,int赋值为0;
3、VALUES也可以写成VALUE,但是VALUES是标准写法
4、可以同时插入多行
5、如果插入从表的数据,要注意查看主表参照字段的值是否存在
6、值的位置可以是常量值、表达式、函数
练习(一)
CREATE TABLE t_stu( sid INT PRIMARY KEY AUTO_INCREMENT, sname VARCHAR(100) NOT NULL, gender CHAR NOT NULL DEFAULT '男', card_id CHAR(18) NOT NULL UNIQUE, birthday DATE, address VARCHAR(200) ); |
|
INSERT INTO t_stu VALUES(1,'张三',DEFAULT,'123456789012345678','1989-09-09',NULL); INSERT INTO t_stu VALUES(2,'李四','女','123456789012345677','1988-09-09','尚硅谷'); INSERT INTO t_stu VALUES(0,'王五','男','123456789012345676','1987-09-09','尚硅谷'); INSERT INTO t_stu VALUES(NULL,'赵六','男','123456789012345675','1987-09-09','尚硅谷'); |
|
INSERT INTO t_stu VALUES (NULL,'冰冰','女','123456789012345674','1988-09-09','尚硅谷'), (NULL,'小丽','女','123456789012345673','1988-09-09','尚硅谷'); |
|
INSERT INTO t_stu (sname,card_id,birthday) VALUES('小薇','123456199012045672',STR_TO_DATE(SUBSTRING(card_id,7,8),'%Y%m%d')); |
|
INSERT INTO t_stu (sname,card_id,birthday)VALUES ('小红','123456789012345671','1990-09-09'), ('小紫','123456789012345670','1990-09-09'); |
练习(二)
CREATE TABLE t_department( did INT PRIMARY KEY AUTO_INCREMENT, dname VARCHAR(100) NOT NULL, description VARCHAR(200), manager_id INT );
INSERT INTO t_department(dname,description) VALUES('教学部','技术培训'), ('咨询部','课程咨询服务'); |
|
CREATE TABLE `t_job` ( `job_id` INT(11) PRIMARY KEY AUTO_INCREMENT, `job_name` VARCHAR(100) DEFAULT NULL, `description` VARCHAR(200) DEFAULT NULL );
INSERT INTO t_job VALUES (NULL,'JavaSE讲师','Java基础'), (NULL,'Web讲师','Web基础'), (NULL,'JavaEE框架','框架讲解'), (NULL,'课程顾问','课程咨询'); |
|
CREATE TABLE t_employee( eid INT PRIMARY KEY AUTO_INCREMENT, ename VARCHAR(100) NOT NULL, gender CHAR NOT NULL DEFAULT '男', card_id CHAR(18) UNIQUE, tel CHAR(11), job_id INT, `mid` INT, birthday DATE, hiredate DATE, address VARCHAR(100), dept_id INT, FOREIGN KEY (dept_id) REFERENCES t_department(did), FOREIGN KEY (job_id) REFERENCES t_job(job_id) ); INSERT INTO `t_employee`(`eid`,`ename`,`gender`,`card_id`,`tel`,`job_id`,`mid`,`birthday`,`hiredate`,`address`,`dept_id`) VALUES (1,'孙红雷','男','123456789012345678','12345678901',1,NULL,'1990-01-01','2015-01-01','白庙',1), (2,'张亮','男','123456789012345677','12345678902',2,NULL,'1990-01-02','2015-01-02','天通苑北',1), (3,'鹿晗','男','123456789012345676','12345678903',3,NULL,'1990-01-03','2015-01-03','北苑',1), (4,'邓超','男','123456789012345675','12345678904',2,NULL,'1990-01-04','2015-01-04','和谐家园',1), (5,'孙俪','女','123456789012345674','12345678905',3,NULL,'1990-01-05','2015-01-05','霍营',1), (6,'Angelababy','女','123456789012345673','12345678906',4,NULL,'1990-01-06','2015-01-06','回龙观',2);
|
|
CREATE TABLE t_salary( eid INT PRIMARY KEY, basic_salary DECIMAL(10,2), performance_salary DECIMAL(10,2), commission_pct DECIMAL(10,2), deduct_wages DECIMAL(10,2), FOREIGN KEY (eid) REFERENCES t_employee(eid) ); INSERT INTO `t_salary`(`eid`,`basic_salary`,`performance_salary`,`commission_pct`,`deduct_wages`) VALUES (1,'12000.00','6000.00','0.40','0.00'), (2,'9000.00','5000.00','0.20',NULL), (3,'11000.00','8000.00',NULL,NULL), (4,'13000.00','5000.00',NULL,NULL), (5,'8000.00','8000.00','0.30',NULL), (6,'15000.00','6000.00',NULL,NULL); |
UPDATE 表名称 SET 字段名1 = 值1, 字段名2=值2,...... 【WHERE 条件】; |
UPDATE 表1,表2,...... SET 表1.字段名1 = 值1, 表1.字段名2=值2,表2.字段1 = 值1, 表2.字段2=值2...... 【WHERE 条件】; |
如果两个表没有建立外键,但逻辑上有外键关系
#修改所有人的基本工资,涨薪5% UPDATE t_salary SET basic_salary = basic_salary * 1.05; |
#修改"孙俪"的手机号码为"13709098765",生日为"1982-09-26" UPDATE t_employee SET tel = '13709098765',birthday = '1982-09-26' WHERE ename = '孙俪'; |
#修改"邓超"的入职日期为今天 UPDATE t_employee SET hiredate = CURDATE() WHERE ename ='邓超'; |
#修改"咨询部"的主管id为6 UPDATE t_department SET manager_id =6 WHERE did = 2; |
#修改"教学部"的主管id为1 UPDATE t_department SET manager_id =1 WHERE did = 1; |
#修改"教学部"的主管id为"孙红雷"的编号 UPDATE t_department,t_employee SET t_department.manager_id =t_employee.eid WHERE t_department.`dname` = '教学部' AND t_department.`did` = t_employee.`dept_id` AND t_employee.ename = '孙红雷'; |
#修改所有员工的领导编号为该员工所在部门的主管编号 UPDATE t_employee,t_department SET t_employee.mid = t_department.manager_id WHERE t_employee.dept_id = t_department.did; |
#修改教学部的主管编号,以及该部门所有员工的领导编号为"邓超"的编号 UPDATE t_department,t_employee SET t_department.manager_id =t_employee.eid WHERE t_department.`dname` = '教学部' AND t_department.`did` = t_employee.`dept_id` AND t_employee.ename = '邓超';
UPDATE t_employee,t_department SET t_employee.mid = t_department.manager_id WHERE t_employee.dept_id = t_department.did AND t_department.`dname` = '教学部'; |
delete from 表名 【where 条件】; |
delete 表1,表2,....... from 表1,表2,...... 【where 条件】; |
1、如果不加where条件,表示删除整张表的数据,表结构保留。
delete from 表名;
删除整张表的数据还可以使用truncate 表名;
区别:
truncate相当于删除表再重建一张同名结构的表,操作后得到一张全新表,而delete是在原有表中删除数据。如果决定清空一张表的数据,truncate速度更快一些。
TRUNCATE语句不能回滚
2、如果删除主表的记录,要注意查看从表的外键是否有依赖该行的值,如果有
(1)如果外键是on delete RESTRICT或on delete NO ACTION,那么要先处理从表的数据,才能删除
(2)如果外键是on delete SET NULL 或 on delete CASCADE,那么删除时从表的对应记录也会被置空或跟着删除
3、可以一次删除多个表的数据
例如:两个表没有建立外键,但逻辑上有外键关系,也可以通过删除多个表的数据来实现级联删除
#删除学号为9的学生信息 DELETE FROM t_stu WHERE sid = 9; |
#注意:前提是没有外键或外键是on delete cascade #删除所有“教学部”的员工信息和薪资信息和“教学部”部门信息 DELETE t_employee,t_department,t_salary FROM t_employee,t_department,t_salary WHERE t_department.`dname` ='教学部' AND t_employee.`dept_id`=t_department.`did` AND t_employee.`eid` = t_salary.eid; |
SELECT 查询列表 FROM 表名或视图列表 【WHERE 条件表达式】 【GROUP BY 字段名 【HAVING 条件表达式】】 【ORDER BY 字段 【ASC|DESC】】 【LIMIT m,n】; |
例如:
#查询表中的所有行所有列 #使用*表示,查询所有字段,即查询所有行 select * from t_stu;
#查询部分字段,查询部分列 select sname,major from t_stu;
#查询所有列,部分行 select * from t_stu where major = 'JavaEE';
#查询部分行,部分列 select sname,major from t_stu where major = 'JavaEE'; |
说明:
语法:AS 别名
说明:
(1)可以给字段取别名、可以给表名取别名
(2)AS 可以省略
(3)如果给字段取别名,如果别名中包含特殊符号,例如“空格”等,建议给别名加上双引号或单引号
(4)如果是给表名取别名,那么不能加双引号或单引号,也不能有特殊符号,例如“空格”等
(5)建议别名简短,见名知意
示例:
UPDATE t_department AS d,t_employee AS e SET d.manager_id =e.eid WHERE d.dname = '教学部' AND d.did = e.`dept_id` AND e.ename = '孙红雷'; |
#查询员工姓名以及手机号码 SELECT ename AS '员工姓名',tel AS '手机号码' FROM t_employee; |
#查询员工表的部门编号 SELECT DISTINCT dept_id FROM t_employee;
#统计员工表中员工有几个部门 SELECT COUNT(DISTINCT dept_id) FROM t_employee; |
例如:select `name` from t_stu;
可以给字段或表名加着重号
如果字段名或表名与关键字一样更要加着重号了
(1)算术运算符:+ - * /(除也可以写成div,div取整) %(取模可以写成mod)
(2)比较运算符:= > >= < <= !=(不等于还可以写成<>) <=>(安全等于)
(3)逻辑运算符:&&(逻辑与也可以写成and) ||(逻辑或也可以写成or) not(逻辑非) xor(逻辑异或)
(4)范围:表达式 between ... and ... (也可以写成 表达式>=... and 表达式 <=...)
表达式 not between ... and ...(也可以写成 表达式<... || 表达式 >...)
(5)集合:in (值,值,值...) not in(值,值,值...)
(6)模糊查询:LIKE NOT LIKE,通配符:%表示0-n个字符,_下划线代表一个字符
(7)位运算符:&(按位与) |(按位或)^(按位异或)~(按位取反)>>(右移)<<(左移)
(8)NULL值判断,is null 或 is not null,如果使用null=null,null<>null,null=0,null<>0,null=false等都不对
不过xxx is null 可以使用xxx <=> null ,xxx is not null 可以写成 not xxx <=> null
结论:所有的运算符遇到NULL结果都是NULL,除了<=>
#一、算术运算符 #+,-,*,/(div),%(mod) #筛选出eid是偶数的员工 SELECT * FROM t_employee WHERE eid % 2 = 0; SELECT * FROM t_employee WHERE eid MOD 2 = 0;
#查看每天的基本工资值,每个月按22天算 SELECT eid,basic_salary/12 AS "日薪" FROM t_salary;
#div也表示除,但是只保留整数部分 SELECT eid,basic_salary DIV 12 AS "日薪" FROM t_salary;
#关于+,在Java中,+的左右两边如果有字符串,那么表示字符串的拼接,但是在MySQL中+只表示数值相加, #如果遇到非数值类型,先尝试转成数值,如果转失败,就按0计算 SELECT eid+ename FROM t_employee; SELECT eid+birthday FROM t_employee;
#MySQL中字符串拼接要使用字符串函数实现 SELECT CONCAT(eid,":",ename) AS result FROM t_employee; |
#二、比较运算符 #=,>, <,>=, <=, !=(不等于<>),<=>(安全等于) #查询basic_salary!=10000 SELECT eid,basic_salary FROM t_salary WHERE basic_salary != 10000; SELECT eid,basic_salary FROM t_salary WHERE basic_salary <> 10000;
#查询basic_salary=10000,注意在Java中比较是== SELECT eid,basic_salary FROM t_salary WHERE basic_salary = 10000;
#查询commission_pct等于0.40 SELECT eid,commission_pct FROM t_salary WHERE commission_pct = 0.40; SELECT eid,commission_pct FROM t_salary WHERE commission_pct <=> 0.40;
#查询commission_pct等于NULL SELECT eid,commission_pct FROM t_salary WHERE commission_pct IS NULL; SELECT eid,commission_pct FROM t_salary WHERE commission_pct <=> NULL;
#查询commission_pct不等于NULL SELECT eid,commission_pct FROM t_salary WHERE commission_pct IS NOT NULL; SELECT eid,commission_pct FROM t_salary WHERE NOT commission_pct <=> NULL; |
#三、逻辑运算符 #与&&,或||,非! #与 AND,或 OR ,非 NOT,异或 XOR
#查询性别男,并且在90以前出生的员工 SELECT * FROM t_employee WHERE gender='男' AND birthday<'1990-01-01';
#查询职位编号job_id是1或2的员工 SELECT * FROM t_employee WHERE job_id =1 OR job_id = 2;
#查询基本薪资是在9000-12000之间的员工编号和基本薪资 SELECT eid,basic_salary FROM t_salary WHERE basic_salary >=9000 AND basic_salary<=12000;
#查询基本薪资不在9000-12000之间的员工编号和基本薪资 SELECT eid,basic_salary FROM t_salary WHERE NOT (basic_salary >=9000 AND basic_salary<=12000); SELECT eid,basic_salary FROM t_salary WHERE basic_salary <9000 OR basic_salary>12000;
|
#四、表示区间范围和集合范围 #between ... and ... 和 not between ... and ... #in(集合) 和 not in(...)
#查询基本薪资是在9000-12000之间的员工编号和基本薪资 SELECT eid,basic_salary FROM t_salary WHERE basic_salary BETWEEN 9000 AND 12000;
#查询eid是1,3,5的基本工资 SELECT eid,basic_salary FROM t_salary WHERE eid IN (1,3,5); |
#五、模糊查询 #like 和 通配符 一起使用 #like _ 匹配单个字符 #like % 匹配任意个字符
#查询名字中有'冰'字的员工信息 SELECT * FROM t_employee WHERE ename LIKE '%冰%';
#查询姓李的员工信息 SELECT * FROM t_employee WHERE ename LIKE '李%';
#查询姓李,名字就一个字的员工信息 SELECT * FROM t_employee WHERE ename LIKE '李_';
#查询李冰冰的信息 SELECT * FROM t_employee WHERE ename LIKE '李冰冰'; |
通常情况,可以使用FIND_IN_SET()函数或LIKE操作符搜索SET值:
mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET('value',set_col)>0;
mysql> SELECT * FROM tbl_name WHERE set_col LIKE '%value%';
第1个语句找出SET_col包含value set成员的行。第2个类似,但有所不同:它在其它地方找出set_col包含value的行,甚至是在另一个SET成员的子字符串中。
下面的语句也是合法的:
mysql> SELECT * FROM tbl_name WHERE set_col & 1;
mysql> SELECT * FROM tbl_name WHERE set_col = 'val1,val2';
第1个语句寻找包含第1个set成员的值。第2个语句寻找一个确切匹配的值。应注意第2类的比较。将set值与'val1,val2'比较返回的结果与同'val2,val1'比较返回的结果不同。指定值时的顺序应与在列定义中所列的顺序相同。
如果想要为SET列确定所有可能的值,使用SHOW COLUMNS FROM tbl_name LIKE set_col并解析输出中第2列的SET定义。 有什么实际应用呢?
比如我们设定用户的权限控制,一个用户可能会有多种权限,我们使用所有权限创建一个SET类型的字段,我们不需要用一系列int来定义各种权限了,直接使用一个SET字段即可:
/* 用户权限permission表 */ create table user_permission( id int UNSIGNED not null auto_increment, user_id int not null , permission set('阅读','评论','发帖') not null, primary key(id), unique (user_id) ); desc user_permission; insert into user_permission values (0,1,'阅读'),(0,2,'阅读'),(0,3,'阅读,评论'); insert into user_permission values (0,4,'阅读,评论,发帖'); select *,permission+0 from user_permission; select permission from user_permission where user_id=1; select * from user_permission where permission & 10; SELECT * FROM user_permission WHERE FIND_IN_SET('评论',permission)>0; |
#NULL值判断与处理 #查询奖金百分比不为空的员工编号 SELECT eid,commission_pct FROM t_salary WHERE commission_pct IS NOT NULL;
#查询奖金百分比为空的员工编号 SELECT eid,commission_pct FROM t_salary WHERE commission_pct IS NULL;
#关于null值计算 #所有运算符遇到null都是null
#计算实际的薪资: basic_salary + salary * 奖金百分比 #函数:IFNULL(表达式,用什么值代替) SELECT eid,basic_salary + performance_salary *(1+ commission_pct) FROM t_salary;#错误的 SELECT eid,basic_salary + performance_salary *(1+ IFNULL(commission_pct,0)) FROM t_salary;
#<=>安全等于 #查询奖金百分比为空的员工编号 SELECT eid,commission_pct FROM t_salary WHERE commission_pct <=> NULL;
|
#七、位运算符 #>> << & | ~ ^(异或) SELECT 2^3,2&3,2|3,2>>3,2<<3,~3; |
作用:从2张或多张表中,取出有关联的数据.
关联查询一共有几种情况:
说明:
关联条件 |
|
表名前缀 |
否则报Column 'eid' in field list is ambiguous |
表别名 |
定义:将两(或多)个表的所有行进行组合,连接后的行数为两(或多)个表的乘积数.
在MySQL中如下情况会出现笛卡尔积,主要是因为缺少关联条件或者关联条件不准确
注:外连接必须写关联条件,否则报语法错误
#笛卡尔积 #查询员工姓名和所在部门名称 SELECT ename,dname FROM t_employee,t_department; SELECT ename,dname FROM t_employee INNER JOIN t_department; SELECT ename,dname FROM t_employee CROSS JOIN t_department; SELECT ename,dname FROM t_employee JOIN t_department; |
表连接的约束条件可以有三种方式:WHERE, ON, USING
#关联条件 #把关联条件写在where后面 SELECT ename,dname FROM t_employee,t_department WHERE t_employee.dept_id=t_department.did;
#把关联条件写在on后面,只能和JOIN一起使用 SELECT ename,dname FROM t_employee INNER JOIN t_department ON t_employee.dept_id=t_department.did; SELECT ename,dname FROM t_employee CROSS JOIN t_department ON t_employee.dept_id=t_department.did; SELECT ename,dname FROM t_employee JOIN t_department ON t_employee.dept_id=t_department.did;
#把关联字段写在using()中,只能和JOIN一起使用 #而且两个表中的关联字段必须名称相同,而且只能表示= #查询员工姓名与基本工资 SELECT ename,basic_salary FROM t_employee INNER JOIN t_salary USING(eid);
#n张表关联,需要n-1个关联条件 #查询员工姓名,基本工资,部门名称 SELECT ename,basic_salary,dname FROM t_employee,t_department,t_salary WHERE t_employee.dept_id=t_department.did AND t_employee.eid=t_salary.eid;
SELECT ename,basic_salary,dname FROM t_employee INNER JOIN t_department INNER JOIN t_salary ON t_employee.dept_id=t_department.did AND t_employee.eid=t_salary.eid; |
有两种,显式的和隐式的,返回连接表中符合连接条件和查询条件的数据行
格式:
隐式:SELECT [cols_list] from 表1,表2 where [condition]
显式:SELECT [cols_list] from 表1 INNER JOIN 表2 ON [关联条件] where [其他筛选条件]
SELECT [cols_list] from 表1 CROSS JOIN 表2 ON [关联条件] where [其他筛选条件]
SELECT [cols_list] from 表1 JOIN 表2 ON [关联条件] where [其他筛选条件]
#内连接 #查询员工姓名和所在部门名称 SELECT ename,dname FROM t_employee,t_department WHERE t_employee.dept_id=t_department.did; SELECT ename,dname FROM t_employee INNER JOIN t_department ON t_employee.dept_id=t_department.did; SELECT ename,dname FROM t_employee CROSS JOIN t_department ON t_employee.dept_id=t_department.did; SELECT ename,dname FROM t_employee JOIN t_department ON t_employee.dept_id=t_department.did;
#查询员工姓名,基本工资,部门名称 SELECT ename,basic_salary,dname FROM t_employee,t_department,t_salary WHERE t_employee.dept_id=t_department.did AND t_employee.eid=t_salary.eid;
SELECT ename,basic_salary,dname FROM t_employee INNER JOIN t_department INNER JOIN t_salary ON t_employee.dept_id=t_department.did AND t_employee.eid=t_salary.eid; |
外连接分为:
左外连接(LEFT OUTER JOIN),简称左连接(LEFT JOIN)
右外连接(RIGHT OUTER JOIN),简称右连接(RIGHT JOIN)
全外连接(FULL OUTER JOIN),简称全连接(FULL JOIN)。
返回左表中的所有行,如果左表中行在右表中没有匹配行,则结果中右表中的列返回空值。 |
返回左边中行在右表中没有匹配行的记录 |
#左连接 #查询所有部门信息以及该部门员工信息 SELECT did,dname,eid,ename FROM t_department LEFT OUTER JOIN t_employee ON t_department.did = t_employee.dept_id; |
#查询部门信息,仅保留没有员工的部门信息 SELECT did,dname,eid,ename FROM t_department LEFT OUTER JOIN t_employee ON t_department.did = t_employee.dept_id WHERE t_employee.dept_id IS NULL; #“从表外键列”是NULL |
#查询所有员工信息,以及员工的部门信息 SELECT eid,ename,did,dname FROM t_employee LEFT OUTER JOIN t_department ON t_employee.dept_id = t_department.did ; |
#查询员工信息,仅保留没有分配部门的员工 SELECT eid,ename,did,dname FROM t_employee LEFT OUTER JOIN t_department ON t_employee.dept_id = t_department.did WHERE t_employee.dept_id IS NULL; #“从表外键列”是NULL |
B |
|
恰与左连接相反,返回右表中的所有行,如果右表中行在左表中没有匹配行,则结果中左表中的列返回空值。 |
返回右表中在左表没有匹配行的记录 |
#查询所有部门信息以及该部门员工信息 SELECT did,dname,eid,ename FROM t_employee RIGHT OUTER JOIN t_department ON t_department.did = t_employee.dept_id; |
#查询部门信息,仅保留没有员工的部门信息 SELECT did,dname,eid,ename FROM t_employee RIGHT OUTER JOIN t_department ON t_department.did = t_employee.dept_id WHERE t_employee.dept_id IS NULL; #“从表外键列”是NULL |
#查询所有员工信息,以及员工的部门信息 SELECT eid,ename,did,dname FROM t_department RIGHT OUTER JOIN t_employee ON t_employee.dept_id = t_department.did ; |
#查询员工信息,仅保留没有分配部门的员工 SELECT eid,ename,did,dname FROM t_department RIGHT OUTER JOIN t_employee ON t_employee.dept_id = t_department.did WHERE t_employee.dept_id IS NULL; #“从表外键列”是NULL |
mysql不支持FULL JOIN,但是可以用 left join union right join代替
#查询所有部门信息和员工信息 SELECT did,dname,eid,ename FROM t_department LEFT OUTER JOIN t_employee ON t_department.did = t_employee.dept_id UNION SELECT did,dname,eid,ename FROM t_department RIGHT OUTER JOIN t_employee ON t_department.did = t_employee.dept_id; |
#查询所有没有员工的部门和没有分配部门的员工 SELECT did,dname,eid,ename FROM t_department LEFT OUTER JOIN t_employee ON t_department.did = t_employee.dept_id WHERE t_employee.dept_id IS NULL UNION SELECT did,dname,eid,ename FROM t_employee LEFT OUTER JOIN t_department ON t_department.did = t_employee.dept_id WHERE t_employee.dept_id IS NULL; |
当table1和table2本质上是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义。然后两个表再进行内连接,外连接等查询
#自连接 #查询员工姓名以及领导姓名,仅显示有领导的员工 SELECT emp.ename,mgr.ename FROM t_employee AS emp, t_employee AS mgr WHERE emp.mid = mgr.eid;
#查询员工姓名以及领导姓名,仅显示有领导的员工 SELECT emp.ename,mgr.ename FROM t_employee AS emp INNER JOIN t_employee AS mgr ON emp.mid = mgr.eid;
#查询所有员工姓名及其领导姓名 SELECT emp.ename,mgr.ename FROM t_employee AS emp LEFT JOIN t_employee AS mgr ON emp.mid = mgr.eid; |
从原表中的记录中进行筛选
很多情况下,用户都需要进行一些汇总操作,比如统计整个公司的人数或者统计每一个部门的人数等。
#聚合函数
#AVG(【DISTINCT】 expr) 返回expr的平均值
SELECT AVG(basic_salary) FROM t_salary;
#COUNT(【DISTINCT】 expr)返回expr的非NULL值的数目
#统计员工总人数
SELECT COUNT(*) FROM t_employee;#count(*)统计的是记录数
#统计员工表的员工所在部门数
SELECT COUNT(dept_id) FROM t_employee;#统计的是非NULL值
SELECT COUNT(DISTINCT dept_id) FROM t_employee;#统计的是非NULL值,并且去重
#MIN(【DISTINCT】 expr)返回expr的最小值
#查询最低基本工资值
SELECT MIN(basic_salary) FROM t_salary;
#MAX(【DISTINCT】 expr)返回expr的最大值
#查询最高基本工资值
SELECT MAX(basic_salary) FROM t_salary;
#查询最高基本工资与最低基本工资的差值
SELECT MAX(basic_salary)-MIN(basic_salary) FROM t_salary;
#SUM(【DISTINCT】 expr)返回expr的总和
#查询基本工资总和
SELECT SUM(basic_salary) FROM t_salary;
#group by + 聚合函数 #统计每个部门的人数 SELECT dept_id,COUNT(*) FROM t_employee GROUP BY dept_id;
#统计每个部门的平均基本工资 SELECT emp.dept_id,AVG(s.basic_salary ) FROM t_employee AS emp,t_salary AS s WHERE emp.eid = s.eid GROUP BY emp.dept_id;
#统计每个部门的年龄最大者 SELECT dept_id,MIN(birthday) FROM t_employee GROUP BY dept_id;
#统计每个部门基本工资最高者 SELECT emp.dept_id,MAX(s.basic_salary ) FROM t_employee AS emp,t_salary AS s WHERE emp.eid = s.eid GROUP BY emp.dept_id;
#统计每个部门基本工资之和 SELECT emp.dept_id,SUM(s.basic_salary ) FROM t_employee AS emp,t_salary AS s WHERE emp.eid = s.eid GROUP BY emp.dept_id; |
注意:
用count(*),count(1),谁好呢?
其实,对于myisam引擎的表,没有区别的.
这种引擎内部有一计数器在维护着行数.
Innodb的表,用count(*)直接读行数,效率很低,因为innodb真的要去数一遍.
关于mysql的group by的特殊:
注意:在SELECT 列表中所有未包含在组函数中的列都应该是包含在 GROUP BY 子句中的,换句话说,SELECT列表中最好不要出现GROUP BY子句中没有的列。
对于标准语句来说,这个语句是错误的,但是mysql可以这么干,出于可移植性和规范性,不推荐这么写。
having与where类似,可筛选数据
having与where不同点
#按照部门统计员工人数,仅显示部门人数少于3人的 SELECT dept_id,COUNT(*) AS c FROM t_employee WHERE dept_id IS NOT NULL GROUP BY dept_id HAVING c <3; |
#查询每个部门的平均工资,并且仅显示平均工资高于10000 SELECT emp.dept_id,AVG(s.basic_salary ) AS avg_salary FROM t_employee AS emp,t_salary AS s WHERE emp.eid = s.eid AND dept_id IS NOT NULL GROUP BY emp.dept_id HAVING avg_salary >10000; |
用法:order by col1,col2,col3...
说明:先按col1排序如果col1相同就按照col2排序,依次类推
col1,col2,col3可以是select后面的字段也可以不是
例如:order by click_count desc;
如果两个字段排序不一样,例如:
order by 字段1 asc ,字段2 desc;
#排序 #查询员工基本工资,按照基本工资升序排列,如果工资相同,按照eid升序排列 SELECT t_employee.eid,basic_salary FROM t_employee INNER JOIN t_salary ON t_employee.eid = t_salary.eid ORDER BY basic_salary,eid;
#查询员工基本工资,按照基本工资降序排列,如果工资相同,按照eid排列 SELECT t_employee.eid,basic_salary FROM t_employee INNER JOIN t_salary ON t_employee.eid = t_salary.eid ORDER BY basic_salary DESC,eid;
#统计每个部门的平均基本工资,并按照平均工资降序排列 SELECT emp.dept_id,AVG(s.basic_salary) FROM t_employee AS emp,t_salary AS s WHERE emp.eid = s.eid GROUP BY emp.dept_id ORDER BY AVG(s.basic_salary) DESC; |
limit m,n
m表示从下标为m的记录开始查询,第一条记录下标为0,n表示取出n条出来,如果从m开始不够n条了,就有几条取几条。m=(page-1)*n,(page页码,n表示每页显示的条数)
如果第一页limit 0,n
如果第二页limit n,n
依次类推,得出公式limit (page-1)*n , n
#分页 #查询员工信息,每页显示5条,第二页 SELECT * FROM t_employee LIMIT 5,5;
#统计每个部门的平均基本工资,并显示前三名 SELECT emp.dept_id,AVG(s.basic_salary) FROM t_employee AS emp,t_salary AS s WHERE emp.eid = s.eid GROUP BY emp.dept_id ORDER BY AVG(s.basic_salary) DESC LIMIT 0,3; |
某些情况下,当进行一个查询时,需要的条件或数据要用另外一个 select 语句的结果,这个时候,就要用到子查询。
例如:
为了给主查询(外部查询)提供数据而首先执行的查询(内部查询)被叫做子查询。
一般根据子查询的嵌入位置分为,where型子查询,from型子查询,exists型子查询。
where型子查询即把内层sql语句查询的结果作为外层sql查询的条件.
IN:等于任何一个
ALL:和子查询返回的所有值比较。例如:sal>ALL(1,2,3)等价于sal>1 && sal>2 && sal>3,即大于所有。
ANY:和子查询返回的任意一个值比较。例如:sal>ANY(1,2,3)等价于sal>1 or sal>2 or sal>3,即大于任意一个就可以。
EXISTS:判断子查询是否有返回结果(不关心具体行数和内容),如果返回则为TRUE,否则为FALSE。 |
#子查询 #where型子查询 #查询比“孙红雷”的工资高的员工编号 SELECT * FROM t_salary WHERE basic_salary > (SELECT basic_salary FROM t_employee INNER JOIN t_salary ON t_employee.eid=t_salary.eid WHERE t_employee.ename='孙红雷');
#查询和孙红雷,李晨在同一个部门的员工 SELECT * FROM t_employee WHERE dept_id IN(SELECT dept_id FROM t_employee WHERE ename='孙红雷' OR ename = '李晨');
SELECT * FROM t_employee WHERE dept_id = ANY(SELECT dept_id FROM t_employee WHERE ename='孙红雷' OR ename = '李晨');
#查询全公司工资最高的员工编号,基本工资 SELECT eid,basic_salary FROM t_salary WHERE basic_salary = (SELECT MAX(basic_salary) FROM t_salary);
SELECT eid,basic_salary FROM t_salary WHERE basic_salary >= ALL(SELECT basic_salary FROM t_salary); |
from型子查询即把内层sql语句查询的结果作为临时表供外层sql语句再次查询.
#from型 #找出比部门平均工资高的员工编号,基本工资 SELECT t_employee.eid,basic_salary FROM t_salary INNER JOIN t_employee INNER JOIN ( SELECT emp.dept_id AS did,AVG(s.basic_salary) AS avg_salary FROM t_employee AS emp,t_salary AS s WHERE emp.eid = s.eid GROUP BY emp.dept_id) AS temp ON t_salary.eid = t_employee.eid AND t_employee.dept_id = temp.did WHERE t_salary.basic_salary > temp.avg_salary; |
3、exists型子查询
#exists型 #查询部门信息,该部门必须有员工 SELECT * FROM t_department WHERE EXISTS (SELECT * FROM t_employee WHERE t_employee.dept_id = t_department.did); |
(1)拷贝表结构
CREATE TABLE newadmin LIKE admin;
(2)拷贝表结构和数据(但约束与索引除外)
CREATE TABLE newadmin AS ( SELECT * FROM admin ) ;
(3)拷贝表结构+数据
CREATE TABLE newadmin LIKE admin;
INSERT INTO newadmin SELECT * FROM admin;
(4)跨数据库拷贝表
CREATE TABLE newadmin LIKE shop.admin;
CREATE TABLE newshop.newadmin LIKE shop.admin;
(5)拷贝一个表中其中的一些字段(指定新名),其中一些数据
CREATE TABLE newadmin AS
(
SELECT id, username AS uname, password AS pass FROM admin WHERE id<10
) ;
(6)在创建表的同时定义表中的字段信息。
create table tt
(
eid int primary key auto_increment
)
as
(
select employee_id as eid,first_name,last_name,email from employees
);
在 INSERT 语句中加入子查询。
不必书写 VALUES 子句。
子查询中的值列表应与 INSERT 子句中的列名对应。
INSERT INTO emp2
SELECT * FROM employees WHERE department_id = 90;
或
INSERT INTO sales_reps(id, name, salary, commission_pct)
SELECT employee_id, last_name, salary, commission_pct
FROM employees
WHERE job_id LIKE '%REP%';
MySQL数据库提供了很多函数包括:
ABS(x) |
返回x的绝对值 |
CEIL(x) |
返回大于x的最小整数值 |
FLOOR(x) |
返回大于x的最大整数值 |
MOD(x,y) |
返回x/y的模 |
RAND(x) |
返回0~1的随机值 |
ROUND(x,y) |
返回参数x的四舍五入的有y位的小数的值 |
TRUNCATE(x,y) |
返回数字x截断为y位小数的结果 |
SQRT(x) |
返回x的平方根 |
POW(x,y) |
返回x的y次方 |
CONCAT(S1,S2,......,Sn) |
连接S1,S2,......,Sn为一个字符串 |
CONCAT_WS(s, S1,S2,......,Sn) |
同CONCAT(s1,s2,...)函数,但是每个字符串之间要加上s |
CHAR_LENGTH(s) |
返回字符串s的字符数 |
LENGTH(s) |
返回字符串s的字节数,和字符集有关 |
INSERT(str, index , len, instr) |
将字符串str从第index位置开始,len个字符长的子串替换为字符串instr |
UPPER(s) 或 UCASE(s) |
将字符串s的所有字母转成大写字母 |
LOWER(s) 或LCASE(s) |
将字符串s的所有字母转成小写字母 |
LEFT(s,n) |
返回字符串s最左边的n个字符 |
RIGHT(s,n) |
返回字符串s最右边的n个字符 |
LPAD(str, len, pad) |
用字符串pad对str最左边进行填充,直到str的长度为len个字符 |
RPAD(str ,len, pad) |
用字符串pad对str最右边进行填充,直到str的长度为len个字符 |
LTRIM(s) |
去掉字符串s左侧的空格 |
RTRIM(s) |
去掉字符串s右侧的空格 |
TRIM(s) |
去掉字符串s开始与结尾的空格 |
TRIM(【BOTH 】s1 FROM s) |
去掉字符串s开始与结尾的s1 |
TRIM(【LEADING】s1 FROM s) |
去掉字符串s开始处的s1 |
TRIM(【TRAILING】s1 FROM s) |
去掉字符串s结尾处的s1 |
REPEAT(str, n) |
返回str重复n次的结果 |
REPLACE(str, a, b) |
用字符串b替换字符串str中所有出现的字符串a |
STRCMP(s1,s2) |
比较字符串s1,s2 |
SUBSTRING(s,index,len) |
返回从字符串s的index位置其len个字符 |
CURDATE() 或 CURRENT_DATE() |
返回当前日期 |
CURTIME() 或 CURRENT_TIME() |
返回当前时间 |
NOW()
SYSDATE() CURRENT_TIMESTAMP() LOCALTIME() LOCALTIMESTAMP() |
返回当前系统日期时间 |
YEAR(date) MONTH(date) DAY(date) HOUR(time) MINUTE(time) SECOND(time) |
返回具体的时间值 |
WEEK(date) WEEKOFYEAR(date) |
返回一年中的第几周 |
DAYOFWEEK() |
返回周几,注意:周日是1,周一是2,。。。周六是7 |
WEEKDAY(date) |
返回周几,注意,周1是0,周2是1,。。。周日是6 |
DAYNAME(date) |
返回星期:MONDAY,TUESDAY.....SUNDAY |
MONTHNAME(date) |
返回月份:January,。。。。。 |
DATEDIFF(date1,date2) TIMEDIFF(time1, time2) |
返回date1 - date2的日期间隔 返回time1 - time2的时间间隔 |
DATE_ADD(datetime, INTERVAL expr type) |
返回与给定日期时间相差INTERVAL时间段的日期时间 |
DATE_FORMAT(datetime ,fmt) |
按照字符串fmt格式化日期datetime值 |
STR_TO_DATE(str, fmt) |
按照字符串fmt对str进行解析,解析为一个日期 |
(1)DATE_ADD(datetime,INTERVAL expr type)
SELECT DATE_ADD(NOW(), INTERVAL 1 YEAR); SELECT DATE_ADD(NOW(), INTERVAL -1 YEAR); #可以是负数 SELECT DATE_ADD(NOW(), INTERVAL '1_1' YEAR_MONTH); #需要单引号 |
|
表达式类型 |
YEAR_MONTH |
YEAR |
DAY_HOUR |
MONTH |
DAY_MINUTE |
DAY |
DAY_SECOND |
HOUR |
HOUR_MINUTE |
MINUTE |
HOUR_SECOND |
SECOND |
MINUTE_SECOND |
(2)DATE_FORMAT(datetime ,fmt)和STR_TO_DATE(str, fmt)
格式符 |
说明 |
格式符 |
说明 |
%Y |
4位数字表示年份 |
%y |
表示两位数字表示年份 |
%M |
月名表示月份(January,....) |
%m |
两位数字表示月份(01,02,03。。。) |
%b |
缩写的月名(Jan.,Feb.,....) |
%c |
数字表示月份(1,2,3,...) |
%D |
英文后缀表示月中的天数(1st,2nd,3rd,...) |
%d |
两位数字表示月中的天数(01,02...) |
%e |
数字形式表示月中的天数(1,2,3,4,5.....) |
|
|
%H |
两位数字表示小数,24小时制(01,02..) |
%h和%I |
两位数字表示小时,12小时制(01,02..) |
%k |
数字形式的小时,24小时制(1,2,3) |
%l |
数字形式表示小时,12小时制(1,2,3,4....) |
%i |
两位数字表示分钟(00,01,02) |
%S和%s |
两位数字表示秒(00,01,02...) |
%W |
一周中的星期名称(Sunday...) |
%a |
一周中的星期缩写(Sun.,Mon.,Tues.,..) |
%w |
以数字表示周中的天数(0=Sunday,1=Monday....) |
|
|
%j |
以3位数字表示年中的天数(001,002...) |
%U |
以数字表示年中的第几周,(1,2,3。。)其中Sunday为周中第一天 |
%u |
以数字表示年中的第几周,(1,2,3。。)其中Monday为周中第一天 |
|
|
%T |
24小时制 |
%r |
12小时制 |
%p |
AM或PM |
%% |
表示% |
IF(value,t ,f) |
如果value是真,返回t,否则返回f |
IFNULL(value1, value2) |
如果value1不为空,返回value1,否则返回value2 |
CASE WHEN 条件1 THEN result1 WHEN 条件2 THEN result2 .... [ELSE resultn] END |
相当于Java的if...else if... |
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1 .... [ELSE 值n] END |
相当于Java的switch |
|
SELECT ename ,CASE WHEN salary>=15000 THEN '高薪' WHEN salary>=10000 THEN '潜力股' WHEN salary>=8000 THEN '屌丝' ELSE '草根' END FROM t_employee; |
|
SELECT oid,`status`, CASE `status` WHEN 1 THEN '未付款' WHEN 2 THEN '已付款' WHEN 3 THEN '已发货' WHEN 4 THEN '确认收货' ELSE '无效订单' END FROM t_order; |
函数 |
描述 |
database() |
返回当前数据库名 |
version() |
返回当前数据库版本 |
user() |
返回当前登录用户名 |
password(str) |
返回字符串str的加密版本,41位长的字符串 |
md5(str) |
返回字符串str的md5值,也是一种加密方式 |
DCL用来控制数据库的访问,包括如下SQL语句:
思考:我去银行给朋友汇款,我卡上有1000元,朋友卡上500元,我给朋友转账50元(无手续费),如果,我的钱刚扣,而朋友的钱又没加时,网线断了,怎么办?
组成事务的所有SQL必须:要么全部执行,要么全部取消(就像上面的银行例子)。
注意:
#开启手动处理事务模式 #set autocommit = false; #开始事务(推荐) start transaction;
#查看当前表的数据 select * from t_stu_detail; #删除整张表的数据 delete from t_stu_detail; #查询该表数据,发现显示删除后的结果 select * from t_stu_detail; #回滚 rollback #查看当前表的数据,发现又回来了 select * from t_stu_detail;
#删除整张表的数据 delete from t_stu_detail; #提交事务 commit; #查看当前表的数据,发现真删除了 select * from t_stu_detail; |
#插入一条记录 INSERT INTO t_stu_detail VALUES (1, '123456789012345678', '1990-01-21', '12345678901', '[email protected]', '北七家'); #保存还原点1 savepoint point1; #插入一条记录
INSERT INTO t_stu_detail VALUES (2, '123456789012345677', '1990-02-21', '12345678902', '[email protected]', '北七家'); #保存还原点2 savepoint point2;
#查看当前效果 select * from t_stu_detail;
#回滚到某个还原点 rollback to point1;
#提交事务 commit; |
#清空表 truncate t_stu_detail; #回滚,对于truncate无法回滚 rollback; |
#修改表结构 alter table t_stu_detail add description varchar(50); #回滚,对于修改表结构的语句无法回滚 rollback; |
对于同时运行的多个事务(多线程并发), 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题: (问题的本质就是线程安全问题,共享数据的问题)
数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。
Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE. Oracle 默认的事务隔离级别为: READ COMMITED
Mysql 支持 4 中事务隔离级别. Mysql 默认的事务隔离级别为: REPEATABLE-READ
每启动一个 mysql 程序, 就会获得一个单独的数据库连接. 每个数据库连接都有一个变量 @@tx_isolation, 表示当前的事务隔离级别.
隔离级别 |
描述 |
READ-UNCOMMITTED |
允许事务读取其他事务未提交的数据,脏读、不可重复读、幻读的问题都会出现 |
READ-COMMITTED |
只允许事务读取其他事务已经提交的数据,可以避免脏读,但是不可重复读、幻读的问题仍然会出现 |
REPEATABLE-READ |
确保事务可以多次从一个字段中读取相同的值,好比在事务开启时对现有的数据进行了拍照,其他事务对数据的修改,不管事务是否提交,我这里读取的是拍照下来的数据,可以避免脏读和不可重复读,但幻读的问题仍然存在。 注意:INNODB使用了MVCC (Multiversion Concurrency Control),即多版本并发控制技术防止幻读。真正的像拍照一样,其他事务新插入或删除的记录也看不出来。 |
SERIALIZABLE |
确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行插入、更新、删除操作,所有并发问题都可以避免,但是性能十分低下。 |
(1)脏读
脏读:进入餐厅发现“梦中情人”旁边座位已经有“帅哥”坐那儿了,正郁闷,打完饭,发现那个位置是空着的,又欣喜若狂,其实刚刚那个“帅哥”只是临时过去打个招呼。
客户端A却读取到B未提交的脏数据 |
客户端B还未提交 |
客户端A读取不到B未提交的脏数据 |
客户端B还未提交 |
(2)不可重复读
不可重复读:在图书馆门口,发现自己占的位置旁边有位“美女”,等刷完卡,兴冲冲的走到那儿,发现已经变成一“如花”了。
A客户端在同一个事务中,前后两次读取同一条记录,值不同 |
B客户端提交了新修改的数据 |
A客户端在同一个事务中,前后两次读取同一条记录,值相同 |
B客户端提交了新修改的数据 |
(3)幻读
大学考前画重点,老师说“第一章 xxxxxx概念”,你赶紧找,“天啊,在哪儿啊”,等你画完,就听老师说:“第四章xxxxx”,中间那些你都没听到。
A客户端在同一个事务中,对同一个表的查询记录数不相同 |
B客户端事务删除了数据,并提交 |
A客户端在同一个事务中,对同一个表的查询记录数不相同 |
B客户端事务添加了数据,并提交 |
(4)序列化
A客户端的事务级别是序列化,A客户端正在查看temp表 |
B客户端想要多temp进行增、删、改操作不被允许 如果A客户端迟迟不结束事务,B客户端将会报 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
|
|
|
|
|
但是B客户端对A客户端未涉及的表不受影响 |
数据库的权限和数据库的安全是息息相关的,不当的权限设置可能会导致各种各样的安全隐患,操作系统的某些设置也会对MySQL的安全造成影响。
MySQL的权限系统通过下面两个阶段进行认证:
对于身份认证,MySQL是通过IP地址和用户名联合进行确认的,也就是说,同样的一个用户名如果来自不同的IP地址,则MySQL将其视为不同的用户。
例如MySQL安装后默认创建的用户root@localhost表示用户root只能从本地(localhost)进行连接才可以通过认证,此用户从其他任何主机对数据库进行的连接都将被拒绝,除非安装时选择了(Enable root access from remote machines),那创建的就是root@%用户,就表示可以从任意主机通过root用户进行连接。
在权限存取的两个过程中,系统会用到”mysql”数据库中user和db、host这三个最重要的权限表。
user表中的权限是针对所有数据库的,db表存储了某个用户对一个数据库的权限,host表中存储了某个主机对数据库的操作权限,配合db表对给定主机上数据库级操作权限做更细致的控制;但是很少用,新版本已经取消了host表。
当用户进行连接时,权限表的存取过程有一些两个阶段:
用户表user
user表有39个字段。这些字段可以分为4类:
列 |
说明 |
Select_priv |
确定用户是否可以通过SELECT命令选择数据 |
Insert_priv |
确定用户是否可以通过INSERT命令插入数据 |
Update_priv |
确定用户是否可以通过UPDATE命令修改现有数据 |
Delete_priv |
确定用户是否可以通过DELETE命令删除现有数据 |
Create_priv |
确定用户是否可以创建新的数据库和表 |
Drop_priv |
确定用户是否可以删除现有数据库和表 |
Reload_priv |
确定用户是否可以执行刷新和重新加载MySQL所用各种内部缓存的特定命令,包括日志、权限、主机、查询和表 执行 flush-hosts,flush-logs,flush-privileges,flush-status,flush-tables,flush-threads,refresh,reload等命令的而全新 |
Shutdown_priv |
确定用户是否可以关闭MySQL服务器。在将此权限提供给root账户之外的任何用户时,都应当非常谨慎 |
Process_priv |
确定用户是否可以通过SHOW PROCESSLIST命令查看其他用户的进程 |
File_priv |
确定用户是否可以执行SELECT INTO OUTFILE和LOAD DATA INFILE命令,查看服务器主机上的文件 |
Grant_priv |
确定用户是否可以将已经授予给该用户自己的权限再授予其他用户 |
References_priv |
目前只是某些未来功能的占位符;现在没有作用 |
Index_priv |
确定用户是否可以创建和删除表索引 |
Alter_priv |
确定用户是否可以重命名和修改表结构 |
Show_db_priv |
确定用户是否可以查看服务器上所有数据库的名字,包括用户拥有足够访问权限的数据库 |
Super_priv |
确定用户是否可以执行某些强大的管理功能,例如通过KILL命令删除用户进程,使用SET GLOBAL修改全局MySQL变量,执行关于复制和日志的各种命令 |
Create_tmp_table_priv |
确定用户是否可以创建临时表 |
Lock_tables_priv |
确定用户是否可以使用LOCK TABLES命令阻止对表的访问/修改 |
Execute_priv |
确定用户是否可以执行存储过程 |
Repl_slave_priv |
确定用户是否可以读取用于维护复制数据库环境的二进制日志文件。此用户位于主系统中,有利于主机和客户机之间的通信 |
Repl_client_priv |
确定用户是否可以确定复制从服务器和主服务器的位置 |
Create_view_priv |
确定用户是否可以创建视图 |
Show_view_priv |
确定用户是否可以查看视图或了解视图如何执行 |
Create_routine_priv |
确定用户是否可以更改或放弃存储过程和函数 |
Alter_routine_priv |
确定用户是否可以修改或删除存储函数及函数 |
Create_user_priv |
确定用户是否可以执行CREATE USER命令,这个命令用于创建新的MySQL账户 |
Event_priv |
确定用户能否创建、修改和删除事件 |
Trigger_priv |
确定用户能否创建和删除触发器 |
其他几个db、host、tables_priv、columns_priv权限表类似,可以通过desc查看字段
语句命令方式
有两种方法:
GRANT 权限类型列表 on object_type {表名称|*|*.*|db_name.*} to user [identified by password ‘密码’][,user [identified by password ‘密码’] .... with grant option; 其中:object_type = TABLE | FUNCTION | PROCEDURE |
示例:
例1:创建用户admin,权限为可以在所有数据库上执行所有权限,但只能从本地进行连接
GRANT ALL PRIVILEGES ON *.* TO admin@localhost; |
可以发现除了Grant_priv权限外,所有权限在user表里面都是Y.
例2:在例1基础上,增加对admin的grant权限
GRANT ALL PRIVILEGES ON *.* TO admin@localhost WITH GRANT OPTION; |
例3:在例2基础上,设置密码为“123”
GRANT ALL PRIVILEGES ON *.* TO admin@localhost IDENTIFIED BY '123' WITH GRANT OPTION; |
例4:创建新用户chai,可以从任何IP进行连接,权限为对test数据库的所有表进行SELECT、UPDATE、INSERT、DELETE操作,初始密码为“123”
GRANT SELECT,INSERT,UPDATE,DELETE ON test.* TO 'chai'@'%' IDENTIFIED BY '123'; |
发现此例,user表中权限都是N,db表中增加的记录权限则都是Y。
注意:
Host值 |
User值 |
被条目匹配的连接 |
‘thomas.loc.gov’ |
‘fred’ |
fred,从thomas.loc.gov连接 |
‘thomas.loc.gov’ |
‘’ |
任何用户,从thomas.loc.gov连接 |
‘%’ |
‘fred’ |
fred,从任何主机连接 |
‘%’ |
‘’ |
任何用户,从任何主机连接 |
‘%.loc.gov’ |
‘fred’ |
fred,从在loc.gov域的任何主机连接 |
‘x.y.%’ |
‘fred’ |
fred,从在x.y.net,x.y.com等主机连 |
‘144.155.166.177’ |
‘fred’ |
fred,从144.155.166.177的IP地址连接 |
‘144.155.166.%’ |
‘fred’ |
fred,从‘144.155.166.*的C类子网的任何主机连接 |
如果有多个匹配,服务器必须选择使用哪个条目,按照下述原则来解决:
navicat图形化界面
1、新建用户
2、填写用户名、主机和密码
3、配use表的安全列和资源权限列的信息
0表示不限制
4、选择user表的权限,这是针对所有数据库的全局权限
5、也可以设置单独某个数据库或某个表,或某个列的权限
SQLyog图形化界面
1、新建用户
2、填写用户名密码和资源权限等
3、全局权限
4、某个库或某个表等局部权限
show grants for user@host;
drop user 用户名;
1、在命令行出现乱码问题
按照数据库时选择utf8, 而我们在windows下窗口是GBK的,因此,需要在命令行客户端声明字符集.
set names gbk;是为了告诉服务器,客户端用的GBK编码,防止乱码.
mysql> set names gbk;
Query OK, 0 rows affected (0.00 sec)
可以查看字符集
mysql> show variables like 'character_set_%';
2、退出当前错误语句
语句打错以后应该退出本语句,再继续打新语句.
也可以打\c,快速退出本语句.
3、如何破解数据库的密码?安全模式登录
1:通过任务管理器或者服务管理,关掉mysqld(服务进程)
2:通过命令行+特殊参数开启mysqld
mysqld --skip-grant-tables
3:此时,mysqld服务进程已经打开,并且,不需要权限检查.
4:mysql -uroot 无密码登陆服务器.
5: 修改权限表
A: use mysql;
B: update user set Password = password('123456') where User = 'root';
C: flush privileges;
6:通过任务管理器,关掉mysqld服务进程.
7:再次通过服务管理,打mysql服务。
8:即可用修改后的新密码登陆